Original paper
Abstract
Investors face a number of challenges when seeking to estimate the prospective performance of a long-only investment in commodity futures. For instance, historically, the average annualized excess return of individual commodity futures has been approximately zero and commodity futures returns have been largely uncorrelated with one another. However, the prospective annualized excess return of a rebalanced portfolio of commodity futures can be equity-like. Certain security characteristics, such as the term structure of futures prices, and some portfolio strategies have historically been rewarded with above average returns. Avoiding naïve extrapolation of historical returns and striking a balance between dependable sources of return and possible sources of return is important. This is the unabridged version of our 2006 publication in the Financial Analysts Journal.
Keywords:Â Strategic asset allocation, Tactical asset allocation, Diversification return, Roll return, Momentum, Market timing, Convenience yield, Contango, Backwardation, Normal backwardation, Commodity correlation, Commodity risk factors, Commodity term structure, Trading strategies, Overlay strategies
Trading rules
- The investment universe is all commodity futures contracts.
- The approach involves buying the top quintile (20%) of commodities exhibiting the highest roll-returns.
- Simultaneously, sell short the bottom quintile (20%) of commodities showing the lowest roll-returns.
- Maintain the long-short positions for a duration of one month.
- Contracts in each quintile are equally-weighted.
Python code
Backtrader
import backtrader as bt
class RollRankStrategy(bt.Strategy):
def __init__(self):
# divide investment universe into quintiles
self.quintiles = 5
# get the number of contracts in each quintile
self.contracts_per_quintile = len(self.datas) // self.quintiles
# get the length of roll period
self.roll_period = 30 # assuming the trading period is 1 month
# calculate the number of contracts to trade long/short
self.num_longs_shorts = self.contracts_per_quintile // 5
def next(self):
# calculate roll-returns for all contracts
roll_returns = [d.close[-1] / d(-self.roll_period).close[0] for d in self.datas]
# sort contracts by roll-returns
ranks = sorted(range(len(roll_returns)), key=lambda x: roll_returns[x])
# go long on top 20% of contracts
for i in ranks[-self.num_longs_shorts:]:
self.buy(datalist[i], size=1/self.num_longs_shorts)
# go short on bottom 20% of contracts
for i in ranks[:self.num_longs_shorts]:
self.sell(datalist[i], size=1/self.num_longs_shorts)
Note: This is just an example, and the code may need to be adjusted based on the specifics of the commodity futures contracts being traded.