One of the main problems I have experienced with momentum strategies is that I regularly get sucked into buying right at the high. In the short term prices often mean revert which can lead to quick losses. My first way of attempting to deal with this problem involved using multiple momentum periods in a quest to find stocks that were moving up in both the short and long term. Another popular solution is to ignore the most recent months price change by incorporating a lag month. Using slope or volatility measures is another method that I have found to work well in backtests.

Today's algorithm ranks each of SPDR sectors ETF's according to one year momentum and their one month linear regression slope. Momentum is ranked in descending order however slope is ranked in ascending order. Ranks are totaled and whichever ETF has the lowest score is purchased each month.

The rationale behind this strategy is that a positive slope is associated with long term gains whilst a negative slope is associated with recent declines. I wanted to target ETF's with long term momentum that have recently pulled back in price (Buy the dip and let her rip!).

Today's algorithm ranks each of SPDR sectors ETF's according to one year momentum and their one month linear regression slope. Momentum is ranked in descending order however slope is ranked in ascending order. Ranks are totaled and whichever ETF has the lowest score is purchased each month.

The rationale behind this strategy is that a positive slope is associated with long term gains whilst a negative slope is associated with recent declines. I wanted to target ETF's with long term momentum that have recently pulled back in price (Buy the dip and let her rip!).

Here's the Quantopian code:

```
import pandas as pd
import numpy as np
from scipy import stats
import statsmodels.api as sm
def initialize(context):
set_symbol_lookup_date('2015-01-01')
schedule_function(buy,date_rule=date_rules.month_start(),time_rule=time_rules.market_open())
schedule_function(sell,date_rule=date_rules.month_end(),time_rule=time_rules.market_close())
set_commission(commission.PerShare(cost=0.005, min_trade_cost=1.00))
context.stocks = symbols('XLK', 'XLF', 'XLV', 'XLE', 'XLY', 'XLP', 'XLI', 'XLU', 'XLB')
context.topn = 1
context.mom_lookback = 252
context.slope_lookback = 21
context.top_total = 1.0
context.bottom_total = 0
context.extra_lag = 20
def buy(context, data):
returns = []
for s in context.stocks:
mom_closes = history(bar_count=context.mom_lookback, frequency="1d", field='close_price')
mom = mom_closes[s][-1-context.extra_lag]/mom_closes[s][0]
slope_closes = history(bar_count=context.slope_lookback, frequency="1d", field='close_price')
y = slope_closes[s].values
x = np.arange(1, (len(y)+1))
x = sm.add_constant(x, prepend=True)
model = sm.OLS(y, x).fit().params
inter, slope = model
returns.append([s, mom, slope])
df = pd.DataFrame(returns, columns=['stock', 'mom', 'slope']).dropna()
df = df.set_index('stock')
df['mom_rank']=df['mom'].rank(ascending=False)
df['slope_rank']=df['slope'].rank(ascending=True)
df['score']=df.mom_rank+df.slope_rank
df['rank']=df['score'].rank(ascending=True)
df = df.sort_index(by='rank', ascending=True)
print df
top = df.head(context.topn)
bottom = df.tail(context.topn)
longs = top.index.values.tolist()
shorts = bottom.index.values.tolist()
long_weight = context.top_total/float(len(longs))
short_weight = context.bottom_total/float(len(shorts))
if get_open_orders():
log.info("waiting for order fills")
return
for l in longs:
order_target_percent(l, long_weight)
for s in shorts:
order_target_percent(s, short_weight)
def sell(context, data):
for x in context.portfolio.positions:
order_target(x, 0)
def handle_data(context, data):
pass
```

I left the option to go market neutral (top and bottom totals refers to leverage which can be positive or negative; typically you would want to buy the top while shorting the bottom).