Intraday Momentum in Equities
Log in to collectAcademic paper
Intraday Momentum: The First Half-Hour Return Predicts the Last Half-Hour Return
Lei Gao; Yufeng Han; Guofu Zhou
- George Mason University
- University of North Carolina at Charlotte
- ?University of North Carolina (UNC) at Charlotte - Finance
- Rutgers, The State University of New Jersey
- Washington University in St. Louis
- ?Washington University in St. Louis - John M. Olin Business School
- ?Rutgers, The State University of New Jersey - Rutgers Business School at Newark & New Brunswick
Strategy in a nutshell
This intraday strategy uses the first and last half-hour returns as timing signals. A long position is taken if both returns are positive, a short if both are negative, and neutral if they differ. All positions are closed at market close to avoid overnight risk.
Economic rationale
Predictable intraday price patterns emerge from day traders’ reversion expectations and informed traders’ timing during high-volume periods. Strategic trading at market open and close creates short-term trends that this systematic approach exploits.
Backtest performance
Annualised return4.39%
Volatility4.49%
Beta0.001
Sharpe ratio0.98
Sortino ratio-0.592
Win rate48%
Full Python code
from AlgorithmImports import *
class IntradayMomentumEquities(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2000, 1, 1)
self.SetCash(100000)
self.symbol = self.AddEquity("SPY", Resolution.Minute).Symbol
self.Schedule.On(self.DateRules.EveryDay(self.symbol), self.TimeRules.BeforeMarketClose(self.symbol, 30), self.Rebalance)
self.Schedule.On(self.DateRules.EveryDay(self.symbol), self.TimeRules.BeforeMarketClose(self.symbol, 1), self.MarketClose)
def Rebalance(self):
day_history = self.History([self.symbol], 12*30, Resolution.Minute)
if len(day_history) == 12*30 and 'close' in day_history:
first_half_hour = day_history['close'][:30]
first_half_hour_ret = self.Return(first_half_hour)
twelfth_half_hour = day_history['close'][-30:]
twelfth_half_hour_ret = self.Return(twelfth_half_hour)
if first_half_hour_ret > 0 and twelfth_half_hour_ret > 0:
self.SetHoldings(self.symbol, 1)
elif first_half_hour_ret < 0 and twelfth_half_hour_ret < 0:
self.SetHoldings(self.symbol, -1)
def MarketClose(self):
self.Liquidate()
def Return(self, history):
return (history[-1] - history[0]) / history[0]