@Rudiger, thanks for sharing your code and idea. Here's a variation.
Uses the intraday move as an indicator to hold overnight.
Also, per Mr Aken's comment, if you plot cost basis for a security, you may see the number of trades that have to be made to fully enter any on position. Lowering your capital, or increasing your number of positions, may allow you to enter exactly at the time of your submission signal. Volume slippage can be a shock when you watch how many actual fills you get on a big order.
minRankToQualify = 1.05
def initialize(context):
set_universe(universe.DollarVolumeUniverse(floor_percentile=98.0, ceiling_percentile=99.0))
context.maxPositionCount = 5
schedule_function(func = ExecuteEODEntry,
date_rule = date_rules.every_day(),
time_rule = time_rules.market_close(minutes=1),
half_days = True
)
schedule_function(func = ExitPositions,
date_rule = date_rules.every_day(),
time_rule = time_rules.market_open(minutes=1),
half_days = True
)
def handle_data(context, data):
pass
def ExecuteEODEntry(context, data):
dailyOpens = history(1, '1d', 'open_price')
minutelyCloses = history(1, '1m', 'close_price')
pairs = []
for stock in data:
todaysOpen = dailyOpens[stock][-1]
todaysClose = minutelyCloses[stock][-1]
intradayReturn = todaysOpen / todaysClose
pair = (stock, intradayReturn)
pairs.append(pair)
rankedByIntradayReturn = sorted(pairs, key=lambda (stock, ret): ret, reverse=True)
rankedByIntradayReturn = filter(lambda (stock, ret): ret >= minRankToQualify , rankedByIntradayReturn)
eligibleCount = float(len(rankedByIntradayReturn))
for stock, rank in rankedByIntradayReturn:
order_target_percent(stock, 1.0 / eligibleCount)
print(" Entry {0:<5} @ {1:>7.2f} rank: {2:>7.2f} >>".format(stock.symbol, data[stock].close_price, rank))
def ExitPositions(context, data):
for stock in context.portfolio.positions:
order_target_percent(stock, 0.0)
print("<< Exit {0:<5} @ {1:>7.2f}".format(stock.symbol, data[stock].close_price))