Original paper
Abstract
Commodities as an asset class have been in growing demand over the last 40 years, as investors that have traditionally held portfolios of stocks and bonds seek the ‘equity-like’ returns along with diversification potential and inflation hedging characteristics available through commodities investment. However, perhaps due to their relative complexity and the large remaining disagreements in the current literature about the fundamental drivers of commodities returns, investors do not universally agree on the merits of commodity investments. This paper begins by reviewing the existing theories and fundamental drivers of returns from commodity investments to better understand the risks that commodity investors are compensated for bearing. From this perspective we will evaluate existing methods of commodity investing with a focus on why the risk premia these strategies capture are likely to persist in the future.
Keywords:Â commodity, commodities, investing, roll, momentum
Trading rules
- Choose a variety of commodity futures for investment purposes.
- Analyze the historical performance of each future spanning the previous year.
- Categorize these futures into five groups according to their performance metrics.
- Initiate a long position on the quintile exhibiting the strongest performance (highest momentum).
- Enter a short position on the quintile with the weakest performance (lowest momentum).
- Adjust the positions on a monthly basis.
Python code
Backtrader
import backtrader as bt
import numpy as np
class CommodityMomentum(bt.Strategy):
params = (
('lookback', 12),
('rebalance_period', 30),
)
def __init__(self):
self.future_data = {}
self.inds = {}
def prenext(self):
self.next()
def nextstart(self):
self.next()
def next(self):
if len(self.data) % self.params.rebalance_period == 0:
self.rebalance_portfolio()
def add_future_data(self, future_name, future_data):
self.future_data[future_name] = future_data
self.inds[future_name] = {}
self.inds[future_name]['momentum'] = bt.indicators.Momentum(future_data.close, period=self.params.lookback)
def rebalance_portfolio(self):
momentums = []
for future_name, future_data in self.future_data.items():
if len(future_data) < self.params.lookback:
continue
momentum_value = self.inds[future_name]['momentum'][0]
momentums.append((future_name, momentum_value))
sorted_momentums = sorted(momentums, key=lambda x: x[1])
quintile_size = len(sorted_momentums) // 5
long_futures = [future_name for future_name, _ in sorted_momentums[-quintile_size:]]
short_futures = [future_name for future_name, _ in sorted_momentums[:quintile_size]]
for future_name, future_data in self.future_data.items():
if future_name in long_futures:
self.order_target_percent(future_data, target=1.0/len(long_futures))
elif future_name in short_futures:
self.order_target_percent(future_data, target=-1.0/len(short_futures))
else:
self.order_target_percent(future_data, target=0)
cerebro = bt.Cerebro()
# Add your data feeds and set the respective names
# Example: data_feed = bt.feeds.YourDataFeed(dataname="your_data_feed")
# cerebro.adddata(data_feed, name="future_name")
strategy = cerebro.addstrategy(CommodityMomentum)
for future_name, future_data in strategy.future_data.items():
strategy.add_future_data(future_name, future_data)
cerebro.run()
Please note that you need to add your data feeds and set the respective names before running the code.