Dear Klaus -
thanks a lot for your immediate response.
This was very helpful and I already had success in modifying this strategy.
- I took out the volatility component as Gary Antonacci describes his strategy purely based on momentum
- I changed the time window to 120 days
- I modified the list of instruments
The following might sound a little ridiculous to an experienced programmer like you, but:
- how can I modify this strategy so that the 2 ETFs with the highest momentum are bought? At the moment it's just the one ETF with the very highest momentum
- where can I specify that the portfolio will be rebalanced every month?
Thanks a lot in advance. I really appreciate your help!
Stephan
# Region Rotation Strategy based on Gary Antonacci - see http://papers.ssrn.com/sol3/papers.cfm?abstract_id=1833722
import math
import pandas
def initialize(context):
context.stocks = {21516: sid(21516), 21769: sid(21769),
14520: sid(14520), 23118: sid(23118),
23870: sid(23870), 23911: sid(23911), 26807: sid(26807)}
context.month = None
context.period = 120 # 6 months period
def _order(stock, amount, price):
if amount != 0:
order(stock, amount)
log.info("%s %d shares of %s = %.2f" % \
# If less than 0, it'll print out selling
(["buying", "selling"][amount<0], abs(amount),
stock.symbol, abs(price*amount)))
@batch_transform(window_length=120)
def get_metrics(dp, security, period):
'''Calculate performance and volatility for given period.'''
# Get's all the close prices of the security in the last 120 days (6 months)
prices = dp['close_price'][security.sid][-period-1:]
begin, end = prices[-period], prices[-1]
# volatility = (pandas.rolling_std(prices,20)*math.sqrt(period/20)).mean()
return (end - begin)/begin #, volatility/begin
def normalise(data, stocks, period):
# Need to return normalised return and volume
stocks_ret = {}
#stocks_vol = {}
for stock in stocks.values():
ret = get_metrics(data, stock, period)
stocks_ret[stock] = ret
# stocks_vol[stock] = vol
# Return max = highest performance, while volatility max is lowest volatility
ret_max, ret_min = max(stocks_ret.values()), min(stocks_ret.values()),
return ret_max, ret_min
def get_best(data, stocks, period):
best = None
ret_max, ret_min = normalise(data, stocks, period)
for stock in stocks.values():
ret = get_metrics(data, stock, period)
#log.debug('%s: return: %.2f, vol: %.2f' % (stock.symbol, ret, vol))
ret = (ret-ret_min)/(ret_max-ret_min)
#vol = (vol-vol_min)/(vol_max-vol_min)
rank = ret * 1.0 #+ vol * 0.3
log.debug('%s: return: %.2f, rank: %.2f' % \
(stock.symbol, ret, rank))
if best is None or best[1] < rank:
best = stock, rank
log.debug("The BEST rank is: " + best[0].symbol)
return best[0]
def handle_data(context, data):
stocks = context.stocks
month = data[stocks.values()[0]].datetime.month
if not context.month:
context.month = month
ret = get_metrics(data, stocks.values()[0], context.period)
# check if next month began
if context.month == month:
return
context.month = month
if ret:
stock = get_best(data, stocks, context.period)
positions = context.portfolio.positions
if positions[stock.sid]['amount']:
return
sold = 0.0
for position in positions.values():
if position.amount:
pstock = context.stocks[position.sid]
price = data[pstock].price
_order(pstock, -position.amount, price)
sold += position.amount * price
amount = int((context.portfolio.cash+sold)/data[stock].price)
_order(stock, amount, data[stock].price)