This post is to illustrate that momentum strategies that minimize loss during large drawdowns are not profitable when the inverse of the strategy is employed.
Take for instance the SP500 sector momentum algo, the top 2 outperform the benchmark, and the bottom 2 tend to underperform. In my long algo, I buy the highest x sectors every month and exit if the SP500 month-end price is lower than the 200 day moving average. This produces a good return.
Lets try the exact inverse! If the long strategy works, surely the short version should at least hedge.
Basically the code does nothing until the SP500 dips below its 200 day moving average. Then it shorts the worst performing sector until the sp500 rises above the moving average again.
The result is just awful. The short porfolio does rise during the 2008 recession, and finishes slightly above, but nowhere close to being worth the whipsaw events that bleed portfolio value. The only value it provides is for adrenaline junkies who prefer to see rises and falls in their portfolio and would hate to dump all their portfolio into cash.
To those familiar with moving averages or technical signals in general, this might be intuitive. But I really needed to see it for myself to believe it. I also thought that negative momentum would tip the scales towards a profitable short strategy.
I think I will test it again, but with a combined long/short combination. Today is my only day off in 3 weeks, I hope I don't spend all my time programming.....
|Returns||1 Month||3 Month||6 Month||12 Month|
|Alpha||1 Month||3 Month||6 Month||12 Month|
|Beta||1 Month||3 Month||6 Month||12 Month|
|Sharpe||1 Month||3 Month||6 Month||12 Month|
|Sortino||1 Month||3 Month||6 Month||12 Month|
|Volatility||1 Month||3 Month||6 Month||12 Month|
|Max Drawdown||1 Month||3 Month||6 Month||12 Month|
# For this example, we're going to write a simple momentum script. # When the stock goes up quickly, we're going to buy; # when it goes down we're going to sell. # Hopefully we'll ride the waves. # To run an algorithm in Quantopian, you need two functions: # initialize and handle_data from operator import itemgetter def initialize(context): context.topMom = 3 context.rebal_int = 3 context.lookback = 250 set_symbol_lookup_date('2015-01-01') context.stocks = symbols('XLF', 'XLE', 'XLU', 'XLK', 'XLB', 'XLP', 'XLY', 'XLI', 'XLV') #context.stocks = symbols('SPY', 'VEA', 'BIL') #context.stocks = symbols('SPY', 'EFA', 'BND', 'VNQ', 'GSG', 'BIL') #context.stocks = symbols('DDM', 'MVV', 'QLD', 'SSO', 'UWM', 'SAA', 'UYM', 'UGE', 'UCC', 'UYG', 'RXL', 'UXI', 'DIG', 'URE', 'ROM', 'UPW', 'BIL') schedule_function(rebalance, date_rule=date_rules.month_start(), time_rule=time_rules.market_open()) def rebalance(context, data): #Create stock dictionary of momentum MomList = GenerateMomentumList(context, data) #sell all positions for stock in context.portfolio.positions: order_target(stock, 0) #create % weight spy = symbol('SPY') if data[spy].price > data[spy].mavg(200): return weight = 0.95/context.topMom #buy for l in MomList: stock = l #if stock in data and data[stock].close_price < data[stock].mavg(50): if stock in data: order_percent(stock, -weight) pass def GenerateMomentumList(context, data): MomList =  price_history = history(bar_count=context.lookback, frequency="1d", field='price') for stock in context.stocks: now = price_history[stock].ix[-1] old = price_history[stock].ix pct_change = (now - old) / old #if now > data[stock].mavg(200): MomList.append([stock, pct_change, price_history[stock].ix]) #sort in descending order, the price change (%) MomList = sorted(MomList, key=itemgetter(1), reverse=False) #return only the top "topMom" number of securities MomList = MomList[0:context.topMom] return MomList def change(one, two): return(( two - one)/one) def handle_data(context, data): pass