Original paper
Abstract
Alternative beta strategies can serve a variety of different investment objectives, which may include reducing volatility or achieving tilts to systematic risk exposures. It is therefore essential for investors to examine whether these strategies meet their own investment objectives and risk-taking preferences.
Two main approaches to alternative beta are reviewed in this paper: the ‘risk-based approach,’ which entails reducing portfolio risk; and the ‘factor-based approach,’ which involves enhancing return through earning systematic risk premia, with a focus on the latter. Whilst alternative beta is fairly well established in equity strategy investing, it is still a nascent concept in commodities. However, as a result of investors’ pursuit of better diversified portfolios and a recognition that systematic risk factors explain the majority of returns, the development of commodity alternative beta products is gathering pace. This is not entirely unforseen, as investors now view their investment opportunity in the context of risk premia, rather than individual asset classes. From our investigation in this study, there appears to be potential benefit in allocating into alternative beta strategies as part of a portfolio’s commodity allocation, and we find that combining risk-based and factor-based commodity strategies has historically delivered higher return and lower risk than passive long-only strategies on their own.
Finally, it should be borne in mind that alternative beta strategies often take substantial active risks, which are largely driven by factor exposures. Factor returns can be volatile, and all alternative beta strategies can experience considerable drawdown at times. However, as these risk factors have a low correlation with each other, it may be sensible to combine them in order to improve return and reduce risk.
Keywords:Â Commodities; Smart Beta; Alternative Beta; Strategy; Return; Factors; Asset Management; Investment
Trading rules
- Select a set of commodity futures for trading.
- Assess the historical track record of each future over the past 12 months.
- Categorize futures into five groups according to their performance.
- Take a long position on the quintile with the strongest performance (maximum momentum).
- Adopt a short position on the quintile with the weakest performance (minimal momentum).
- Adjust 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.