
The strategy trades Oil by opening a long position at 7 p.m. (GMT+3) on days with positive abnormal returns, holding until midnight to capture short-term gains.
ASSET CLASS: CFDs, ETFs, futures | REGION: Global | FREQUENCY:
Intraday | MARKET: commodities | KEYWORD: Oil, Momentum
I. STRATEGY IN A NUTSHELL
The strategy trades Oil commodities by entering short-term long positions after detecting abnormal positive returns, exploiting intraday momentum from significant price surges.
II. ECONOMIC RATIONALE
Abnormal returns trigger short-lived momentum driven by investor herding, where prices continue rising temporarily—creating opportunities for quick, profit-oriented intraday trades.
III. SOURCE PAPER
Gold and Oil Prices: Abnormal Returns, Momentum and Contrarian Effects [Click to Open PDF]
Guglielmo Maria Caporale, Alex Plastun
<Abstract>
This paper explores price (momentum and contrarian) effects on the days characterised by abnormal returns and the following ones in two commodity markets. Specifically, using daily Gold and Oil price data over the period 01.01.2009-31.03.2020 the following hypotheses are tested: H1) there are price effects on days with abnormal returns, H2) there are price effects on the day after abnormal returns occur; H3) the price effects caused by abnormal returns are exploitable. For these purposes average analysis, t-tests, CAR and trading simulation approaches are used. The main results can be summarised as follows. Hourly returns during the day of abnormal returns are significantly bigger than those during average “normal” days. Prices tend to move in the direction of abnormal returns till the end of the day when these occur. The presence of abnormal returns can usually be detected before the end of the day by estimating specific timing parameters, and a momentum effect can be detected. On the following day two different price patterns are detected: a momentum effect for Oil prices and a contrarian effect for Gold prices respectively. Trading simulations show that these effects can be exploited to generate abnormal profits.


IV. BACKTEST PERFORMANCE
| Annualised Return | 21.36% |
| Volatility | N/A |
| Beta | 0.001 |
| Sharpe Ratio | N/A |
| Sortino Ratio | -1.329 |
| Maximum Drawdown | N/A |
| Win Rate | 48% |
V. FULL PYTHON CODE
from AlgorithmImports import *
import numpy as np
from math import floor
#endregion
class OilIntradayMomentum(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2010, 1, 1)
self.SetCash(1000000)
self.period = 3 * 21
self.treshhold_value = 2
self.future:Future = self.AddFuture(Futures.Energies.CrudeOilWTI, \
Resolution.Minute, \
dataNormalizationMode=DataNormalizationMode.BackwardsRatio, \
contractDepthOffset=0)
self.symbol:Symbol = self.future.Symbol
self.daily_ret = [] # daily returns
self.open = 0 # latest open
self.day_close_flag:bool = False
self.day_open_flag:bool = False
self.market:Symbol = self.AddEquity('SPY', Resolution.Daily).Symbol
self.Schedule.On(self.DateRules.EveryDay(self.market), self.TimeRules.BeforeMarketClose(self.market, 1), self.DayClose)
self.Schedule.On(self.DateRules.EveryDay(self.market), self.TimeRules.AfterMarketOpen(self.market, 1), self.DayOpen)
def OnData(self, data: Slice) -> None:
# close
if self.day_close_flag:
self.day_close_flag = False
self.Liquidate()
if self.symbol in data and data[self.symbol]:
close:float = data[self.symbol].Close
if close != 0 and self.open != 0 and close != self.open:
todays_ret:float = close / self.open - 1
self.daily_ret.append(todays_ret)
if len(self.daily_ret) < self.period:
return
mean:float = np.mean(self.daily_ret)
std:float = np.std(self.daily_ret)
high_threshhold = mean + self.treshhold_value * std
if todays_ret > high_threshhold:
if not self.Portfolio.Invested:
self.MarketOrder(self.future.Mapped, 1)
self.open = 0
# open
if self.day_open_flag:
self.day_open_flag = False
if self.symbol in data and data[self.symbol]:
self.open = data[self.symbol].Open
def DayClose(self) -> None:
self.day_close_flag = True
def DayOpen(self) -> None:
self.day_open_flag = True
VI. Backtest Performance