Introduction
This algorithm will combine the term structure effect and the momentum effect to exploit the trading signals in commodity Futures. The momentum strategy goes long commodity Futures with the highest one-month momentum and shorts on Futures with the lowest one-month momentum. Signals are based on the historical return. While the portfolio in term structure strategy is created with Futures contracts in deep contango and backwardation. It goes long commodities with the highest roll-returns and short commodities with the lowest roll-returns and holds the long-short positions for one month.
Method
Roll Return
The universe is created with 22 commodity Futures. For multiple commodities, we save the FuturesChain of each commodity in dictionary self.chains
.
First, we compute the roll-returns at the start of each month and sort the roll-return list. 1/3 breakpoints are used to split the cross-section of Futures contracts into 3 portfolios, labeled Low
, Med
and High
. For the formula of the roll-return, please see Term Structure Effect in Commodities.
Contracts fall into Med
level are eliminated from the universe. Next we'll calculate the mean return of contracts in High
and Low
.
roll_return = {}
for symbol, chain in self.chains.items():
contracts = sorted(chain, key = lambda x: x.expiry)
expiry_nearest = contracts[0].expiry
price_nearest = float(contracts[0].last_price) if contracts[0].last_price>0 else 0.5*float(contracts[0].ask_price+contracts[0].bid_price)
for x in contracts[1:]:
roll_return[x] = (price_nearest-float(x.last_price))*365 / (x.expiry-expiry_nearest).days
sorted_by_roll_return = sorted(roll_return, key = lambda x: roll_return[x], reverse =True)
tertile = floor(1/3*len(sorted_by_roll_return))
high = sorted_by_roll_return[:tertile]
low = sorted_by_roll_return[-tertile:]
Mean Return
The second filter is the historical mean return. We sort the contracts in the High portfolio into two sub-portfolios (High-Winner and High-Loser) based on the mean return of the commodities over the past one month. High-Winner is thus made of the commodities that have both the highest roll-returns at the time of portfolio construction and the best past performance. Similarly, we sort the commodities in the Low portfolio into two sub-portfolios (Low-Winner and Low-Loser) based on their mean return over the past one months. Low-Loser contains, therefore, commodities that have both the lowest roll-returns at the time of portfolio construction and the worst past performance.
mean_return_high = {}
for i in high:
hist = self.history(i.symbol, timedelta(days = 21), Resolution.MINUTE)
if hist.empty:
continue
hist_close = hist['close'][i.expiry][i.symbol.id.to_string()]
mean_return_high[i] = np.mean(hist_close.pct_change())
high_winners = sorted(mean_return_high, key = lambda x: mean_return_high[x], reverse=True)[:int(len(high)*0.5)]
mean_return_low = {}
for i in low:
hist = self.history(i.symbol, timedelta(days = 21), Resolution.MINUTE)
if hist.empty:
continue
hist_close = hist['close'][i.expiry][i.symbol.id.to_string()]
mean_return_low[i] = np.mean(hist_close.pct_change())
low_losers = sorted(mean_return_low, key = lambda x: mean_return_low[x], reverse=True)[-int(len(low)*0.5):]
The combined strategy buys the High-Winner portfolio, shorts the Low-Loser portfolio and holds this position for one month. At the start of the next month, the strategy liquidates the contracts invested and rebalances the portfolio.
short_weight = 0.5/len(low_losers)
for short in low_losers:
self.set_holdings(short.symbol, -short_weight)
long_weight = 0.5/len(high_winners)
for long in high_winners:
self.set_holdings(long.symbol, long_weight)
Derek Melchin
See the attached backtest for an updated version of the algorithm with the following changes:
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
Jing Wu
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!