Hi all!
Below is the code from my Algo, minus the signals which are generated in Pipeline.
The majority of the non-signal code has been "borrowed" from other Algos and questions answered by @dan whitnable on these message boards. (Thanks Dan!).
I've been through the code many times but cannot identify the problem.
Longs are entered and then exited correctly (longs should be held for "days_held" days).
Shorts are entered correctly, but then on the 2nd day they are flicked from Shorts to longs. They are then held for the correct amount of time ("days_held" days).
This is of course playing havoc with the Algo's turnover in addition to obscuring the genuine signals.
Can any eagle eyed coders spot what I've done wrong?
Or any suggestions how i could track down the bug?
Thanks :-)
return Pipeline(
columns={
'latest_close' : latest_close,
'shorts': shorts,
'longs': longs
},
screen=(securities_to_trade),
)
def before_trading_start(context, data):
# Gets our pipeline output every day.
context.output = pipeline_output('my_pipeline')
context.portpos_count = len(context.portfolio.positions)
print "port pos count:"+str(context.portpos_count)
context.shorts = context.output[
context.output['shorts']].index.tolist()
context.longs = context.output[
context.output['longs']].index.tolist()
context.YestPrice = context.output['latest_close']
context.shorts_sig_count = len(context.shorts)
print "shorts sig count:"+str(context.shorts_sig_count)
context.longs_sig_count = len(context.longs)
print "longs sig count:"+str(context.longs_sig_count)
context.MyShortsCandidate = cycle(context.shorts)
context.MyLongsCandidate = cycle(context.longs)
for stock in context.portfolio.positions:
CurrPrice = float(data.current([stock], 'price'))
if stock in context.age:
context.age[stock] += 1
else:
context.age[stock] = 1
for stock in context.age:
if stock not in context.portfolio.positions:
context.age[stock] = 0
message = 'Stock.symbol: {symbol} : age: {age}'
log.info(message.format(symbol=stock.symbol, age=context.age[stock]))
pass
def rebalance(context, data):
cancel_open_orders(context, data)
# Create position size constraint
constrain_pos_size = opt.PositionConcentration.with_equal_bounds(
-context.max_pos_size,
context.max_pos_size
)
# Ensure long and short books
# are roughly the same size
dollar_neutral = opt.DollarNeutral()
# Constrain target portfolio's leverage
max_leverage = opt.MaxGrossExposure(context.max_leverage)
# Constrain portfolio turnover
max_turnover = opt.MaxTurnover(context.max_turnover)
#checking each stock in the protfolio to see if is ready to exit
for stock in context.portfolio.positions:
if not get_open_orders(stock):
if (stock in context.age and context.age[stock] <days_held ):
pass
elif (
stock in context.age and context.age[stock] >=days_held
):
if context.portfolio.positions[stock].amount >0:
###EXIT LONGS###
weight = 0
weights = pd.Series(index = context.longs, data = weight)
# Next create a TargetWeights object using our weights series
target_weights_longs = opt.TargetWeights(weights)
orders = order_optimal_portfolio(objective = target_weights_longs, constraints = [max_leverage,dollar_neutral,constrain_pos_size,max_turnover,])
###EXIT SHORTS###
if context.portfolio.positions[stock].amount <0:
# set the weight for the stock to zero
weight = 0
weights = pd.Series(index = context.shorts, data= weight)
target_weights_shorts = opt.TargetWeights(weights)
orders = order_optimal_portfolio(objective = target_weights_shorts, constraints = [max_leverage,dollar_neutral,constrain_pos_size,max_turnover,])
else:
context.age[stock] = 1
####Now process new longs#####
if context.longs_sig_count == 0:
WeightThisBuyOrder = 0
else:
weight = min(0.04,float((1.00 /days_held)/ context.longs_sig_count))
weights = pd.Series(index = context.longs, data = weight)
# Next create a TargetWeights object using our weights series
target_weights = opt.TargetWeights(weights)
orders = order_optimal_portfolio(objective = target_weights, constraints = [max_leverage,dollar_neutral,constrain_pos_size,max_turnover,])
####Now process new shorts#####
if context.shorts_sig_count == 0:
WeightThisSellOrder = 0
else:
weight = min(0.04,float((1.00 /days_held)/ context.shorts_sig_count))
weights = pd.Series(index = context.shorts, data = weight)
target_weights = opt.TargetWeights(-weights)
orders = order_optimal_portfolio(objective = target_weights, constraints = [max_leverage,dollar_neutral,constrain_pos_size,max_turnover,])
def my_record_vars(context, data):
"""
Record variables at the end of each day.
"""
# Record our variables.
record(leverage=context.account.leverage)
record(positions=len(context.portfolio.positions))
if 0 < len(context.age):
MaxAge = context.age[max(
context.age.keys(), key=(lambda k: context.age[k]))]
print ("MaxAge: ",MaxAge)
record(MaxAge=MaxAge)
def log_open_order(StockToLog):
oo = get_open_orders()
if len(oo) == 0:
return
for stock, orders in oo.iteritems():
if stock == StockToLog:
for o in orders:
message = 'Found open order for {amount} shares in {stock}'
log.info(message.format(amount=o.amount, stock=stock))
def log_open_orders():
oo = get_open_orders()
if len(oo) == 0:
return
for stock, orders in oo.iteritems():
for o in orders:
message = 'Found open order for {amount} shares in {stock}'
log.info(message.format(amount=o.amount, stock=stock))
def cancel_open_orders(context, data):
oo = get_open_orders()
if len(oo) == 0:
return
for stock, orders in oo.iteritems():
for o in orders:
cancel_order(o)
# This is the every minute stuff
def handle_data(context, data):
pass