Introduction
The main reason for the momentum anomaly is the behavioral biases of the investor like underreaction and confirmation bias. Momentum strategy usually uses portfolios filled by thousands of stocks to compute the momentum factor return. This is not possible for small retail investors with small portfolios. They are constrained compared to big hedge funds and cannot diversify so well. In this tutorial, we'll construct a small portfolio consisting of up to 50 stocks to check the effect of momentum.
Method
The investment universe consists of all US listed companies. Stocks which have no fundamental data are ruled out from the universe.
def coarse_selection_function(self, coarse):
if self.yearly_rebalance:
# drop stocks which have no fundamental data
self.filtered_coarse = [x.symbol for x in coarse if (x.has_fundamental_data)]
return self.filtered_coarse
else:
return Universe.UNCHANGED
In the FineSelectionFunction
, stocks with the lowest market capitalization (25% of the universe) are excluded due to low liquidity.
The momentum is defined as the stock market return over the previous 12 months. Momentum profits are calculated by ranking companies on the basis of yearly return.
The ranking period is one year.
def fine_selection_function(self, fine):
if self.yearly_rebalance:
# Calculate the yearly return and market cap
top_market_cap = sorted(fine, key = lambda x: x.market_cap, reverse=True)[:int(len(self.filtered_coarse)*0.75)]
has_return = []
for i in top_market_cap:
history = self.history([i.symbol], timedelta(days=365), Resolution.DAILY)
if not history.empty:
close = history.loc[str(i.symbol)]['close']
i.returns = (close[0]-close[-1])/close[-1]
has_return.append(i)
sorted_by_return = sorted(has_return, key = lambda x: x.returns)
self.long = [i.symbol for i in sorted_by_return[-10:]]
self.short = [i.symbol for i in sorted_by_return[:10]]
return self.long+self.short
else:
return Universe.UNCHANGED
The investor goes long in the ten stocks with the highest performance and goes short in the ten stocks with the lowest performance. The portfolio is equally weighted and rebalanced yearly.
def on_data(self, data):
if not self.yearly_rebalance: return
if self.long and self.short:
stocks_invested = [x.key for x in self.portfolio if x.value.INVESTED]
# liquidate stocks not in the trading list
for i in stocks_invested:
if i not in self.long+self.short:
self.liquidate(i)
for i in self.short:
self.set_holdings(i, -0.5/len(self.short))
for i in self.long:
self.set_holdings(i, 0.5/len(self.long))
self.long = None
self.short = None
self.yearly_rebalance = False
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!