
Each trading day computes the first half-hour return by comparing the previous trading day’s close price from the price at 10:00 am. Take a long (short) position at the beginning of the last half-hour if the predictor is positive (negative), and then close the position at the end of the last half-hour.
ASSET CLASS: ETFs | REGION: Global | FREQUENCY:
Intraday | MARKET: commodities | KEYWORD: Momentum
I. STRATEGY IN A NUTSHELL
Each trading day, the strategy computes the first half-hour return by comparing the previous trading day’s closing price to the price at 10:00 a.m. If this return is positive (negative), a long (short) position is initiated at the beginning of the last half-hour of the trading session. All positions are closed at the end of the day, ensuring purely intraday exposure and daily rebalancing.
II. ECONOMIC RATIONALE
Momentum effects are well established across asset classes—equities, currencies, commodities, and bonds—where past performance predicts near-term future returns. At the intraday level, the first half-hour return significantly predicts the last half-hour return. The morning return captures market reactions to overnight and pre-market information, such as earnings announcements and macroeconomic data. Trading volume peaks early as traders digest new information, then subsides until the final half-hour, when institutional rebalancing and order execution intensify. This coordinated trading behavior leads to return continuation within the same day. The strategy capitalizes on this predictable pattern, profiting from the persistence of intraday momentum driven by information flow and institutional trading dynamics.
III. SOURCE PAPER
Intraday Momentum: Evidence from the Crude Oil Market [Click to Open PDF]
Wen, Zhuzhu; Cho, Ro; Ma, Diandian; Xu, Yahua
<Abstract>
Our analysis of high-frequency United States Oil Fund (USO) data from 2006 to 2018 shows that intraday momentum exists in the crude oil market. The first half-hour return from the previous day’s market close positively predicts the last half-hour return both in-sample and out-of-sample. Predictability is stronger during crisis periods and on days with higher realized volatility, higher trading volume, higher overnight returns, and jumps. A market timing strategy, constructed by using the first half-hour return as a timing signal, outperforms two other benchmark strategies.
IV. BACKTEST PERFORMANCE
| Annualised Return | 1.85% |
| Volatility | N/A |
| Beta | 0.003 |
| Sharpe Ratio | N/A |
| Sortino Ratio | N/A |
| Maximum Drawdown | N/A |
| Win Rate | 53% |
V. FULL PYTHON CODE
from AlgorithmImports import *
#endregion
class IntradayMomentumCrudeOil(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2010, 1, 1)
self.SetCash(100000)
self.last_day_close:float = 0
self.symbol:Symbol = self.AddEquity('USO', Resolution.Minute).Symbol
self.ret:float|None = None
def OnData(self, data:Slice) -> None:
if self.symbol in data and data[self.symbol]:
# day close
if self.Time.hour == 16 and self.Time.minute == 0:
self.last_day_close = data[self.symbol].Value
# rebalance
elif self.Time.hour == 15 and self.Time.minute == 30:
q:float = self.CalculateOrderQuantity(self.symbol, 1)
if self.ret:
if self.ret > 0:
self.MarketOrder(self.symbol, q)
self.MarketOnCloseOrder(self.symbol, -q)
else:
self.MarketOrder(self.symbol, -q)
self.MarketOnCloseOrder(self.symbol, q)
self.ret = None
# day open - calculation
elif self.Time.hour == 10 and self.Time.minute == 0:
if self.last_day_close == 0: return
price:float = data[self.symbol].Value
self.ret = price / self.last_day_close - 1
self.last_day_close = 0
VI. Backtest Performance