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.cash_settled_butter,
    Futures.dairy.cash_settled_cheese,
    Futures.dairy.class_i_i_i_milk,
    Futures.dairy.dry_whey,
    Futures.dairy.class_i_v_milk,
    Futures.dairy.nonfat_dry_milk,
    Futures.meats.live_cattle,
    Futures.meats.feeder_cattle,
    Futures.meats.lean_hogs,
    Futures.forestry.random_length_lumber
]
for symbol in self.symbols:
    future = self.add_future(symbol,
        resolution = Resolution.DAILY,
        extended_market_hours = True,
        data_normalization_mode = DataNormalizationMode.BACKWARDS_RATIO,
        data_mapping_mode = DataMappingMode.OPEN_INTEREST,
        contract_depth_offset = 0
    )
    future.set_leverage(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.warm_up_indicator(self.symbol, self.ROC, Resolution.DAILY)

    @property
    def is_ready(self):
        return self.ROC.is_ready 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.symbol_properties.contract_multiplier

    def update(self, bar):
        self.ROC.update(bar.end_time, bar.close)

In OnData(self, data), indicators for all Futures contracts are updated every day with the close price.

def on_data(self, slice):
    # Update the indicator value every day
    for symbol, symbol_data in self.data.items():
        if slice.bars.contains_key(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 on_data(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.is_ready], 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.calculate_order_quantity(long.mapped, 0.5/number_futures)
            self.market_order(long.mapped, qty // long.multiplier)
        for short in self.short:
            qty = self.calculate_order_quantity(short.mapped, -0.5/number_futures)
            self.market_order(short.mapped, qty // short.multiplier)

        self.rebalance = Expiry.end_of_month(self.time)


Reference

  1. Quantpedia - Momentum Effect in Commodities