Introduction
Commodity Futures are excellent portfolio diversifiers and some of them are an effective hedge against inflation. This algorithm will explore the momentum effect in commodity Futures with the momentum return.
Method
As the strategy needs the continuous Futures contract, we import the custom data from Quandl. We create a universe of tradable commodity Futures from all available commodity Futures traded on CME. They are all liquid and active continuous contracts #1. The Futures are mapped by largest open interest contract, while adjusted by backward ratio. The data resolution is daily.
The first step is importing the data.
self.symbols = [
Futures.Dairy.CashSettledButter,
Futures.Dairy.CashSettledCheese,
Futures.Dairy.ClassIIIMilk,
Futures.Dairy.DryWhey,
Futures.Dairy.ClassIVMilk,
Futures.Dairy.NonfatDryMilk,
Futures.Meats.LiveCattle,
Futures.Meats.FeederCattle,
Futures.Meats.LeanHogs,
Futures.Forestry.RandomLengthLumber
]
for symbol in self.symbols:
future = self.AddFuture(symbol,
resolution = Resolution.Daily,
extendedMarketHours = True,
dataNormalizationMode = DataNormalizationMode.BackwardsRatio,
dataMappingMode = DataMappingMode.OpenInterest,
contractDepthOffset = 0
)
future.SetLeverage(1)
We use the indicator RateOfChange(period)
to simulate the momentum return with a period of 12 months. Then it is warmed up by the method WarmUpIndicator(Symbol, Indicator, Resolution)
. All Futures' indicators, and their respective informations (e.g. mapped contract, contract multiplier, updating method of ROC indicator) are stored in a SymbolData
class object, and save within a dictionary self.data
.
self.data = {}
for symbol in self.symbols:
self.data[future.Symbol] = SymbolData(self, future, period)
class SymbolData:
def __init__(self, algorithm, future, period):
self._future = future
self.Symbol = future.Symbol
self.ROC = RateOfChange(period)
# warm up indicator
algorithm.WarmUpIndicator(self.Symbol, self.ROC, Resolution.Daily)
@property
def IsReady(self):
return self.ROC.IsReady and self._future.Mapped is not None
@property
def Value(self):
return self.ROC.Current.Value
@property
def Mapped(self):
return self._future.Mapped
@property
def Multiplier(self):
return self._future.SymbolProperties.ContractMultiplier
def Update(self, bar):
self.ROC.Update(bar.EndTime, bar.Close)
In OnData(self, data)
, indicators for all Futures contracts are updated every day with the close price.
def OnData(self, slice):
# Update the indicator value every day
for symbol, symbol_data in self.data.items():
if slice.Bars.ContainsKey(symbol):
symbol_data.Update(slice.Bars[symbol])
We rank the contracts by the last 12-month return and divide them into quintiles. In the trading part, the algorithm goes long on the quintile with the highest momentum return and goes short on the quintile with the lowest momentum return.
def Initialize(self):
# Rebalance the portfolio every month
self.rebalance = self.Time
def OnData(self, slice):
if self.rebalance <= self.Time:
# sorted futures by 12-month return reversely
self.sorted_roc = sorted([x for x in self.data.values() if x.IsReady], key = lambda x: x.Value, reverse=True)
number_futures = int(0.25*len(self.sorted_roc))
if number_futures == 0: return
self.long = [x for x in self.sorted_roc[:number_futures]]
self.short = [x for x in self.sorted_roc[-number_futures:]]
for symbol in self.Portfolio.Keys:
# liquidate the futures which is no longer in the trading list
if self.Portfolio[symbol].Invested and symbol not in [x.Mapped for x in self.long + self.short]:
self.Liquidate(symbol)
for long in self.long:
qty = self.CalculateOrderQuantity(long.Mapped, 0.5/number_futures)
self.MarketOrder(long.Mapped, qty // long.Multiplier)
for short in self.short:
qty = self.CalculateOrderQuantity(short.Mapped, -0.5/number_futures)
self.MarketOrder(short.Mapped, qty // short.Multiplier)
self.rebalance = Expiry.EndOfMonth(self.Time)