This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
date, open, high, low, close, volume, npy | |
2001-12-31, 1.0, 1.0, 1.0, 1.0, 0.5, 3.0 | |
2002-01-31, 2.0, 2.5, 1.1, 1.2, 3.0, 5.0 | |
... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class NetPayOutData(bt.feeds.GenericCSVData): | |
lines = ('npy',) # add a line containing the net payout yield | |
params = dict( | |
npy=6, # npy field is in the 6th column (0 based index) | |
dtformat='%Y-%m-%d', # fix date format a yyyy-mm-dd | |
timeframe=bt.TimeFrame.Months, # fixed the timeframe | |
openinterest=-1, # -1 indicates there is no openinterest field | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class St(bt.Strategy): | |
params = dict( | |
selcperc=0.10, # percentage of stocks to select from the universe | |
rperiod=1, # period for the returns calculation, default 1 period | |
vperiod=36, # lookback period for volatility - default 36 periods | |
mperiod=12, # lookback period for momentum - default 12 periods | |
reserve=0.05 # 5% reserve capital | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def log(self, arg): | |
print('{} {}'.format(self.datetime.date(), arg)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def __init__(self): | |
# calculate 1st the amount of stocks that will be selected | |
self.selnum = int(len(self.datas) * self.p.selcperc) | |
# allocation perc per stock | |
# reserve kept to make sure orders are not rejected due to | |
# margin. Prices are calculated when known (close), but orders can only | |
# be executed next day (opening price). Price can gap upwards | |
self.perctarget = (1.0 - self.p.reserve) % self.selnum |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# returns, volatilities and momentums | |
rs = [bt.ind.PctChange(d, period=self.p.rperiod) for d in self.datas] | |
vs = [bt.ind.StdDev(ret, period=self.p.vperiod) for ret in rs] | |
ms = [bt.ind.ROC(d, period=self.p.mperiod) for d in self.datas] | |
# simple rank formula: (momentum * net payout) / volatility | |
# the highest ranked: low vol, large momentum, large payout | |
self.ranks = {d: d.npy * m / v for d, v, m in zip(self.datas, vs, ms)} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def next(self): | |
# sort data and current rank | |
ranks = sorted( | |
self.ranks.items(), # get the (d, rank), pair | |
key=lambda x: x[1][0], # use rank (elem 1) and current time "0" | |
reverse=True, # highest ranked 1st ... please | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# put top ranked in dict with data as key to test for presence | |
rtop = dict(ranks[:self.selnum]) | |
# For logging purposes of stocks leaving the portfolio | |
rbot = dict(ranks[self.selnum:]) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# prepare quick lookup list of stocks currently holding a position | |
posdata = [d for d, pos in self.getpositions().items() if pos] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# remove those no longer top ranked | |
# do this first to issue sell orders and free cash | |
for d in (d for d in posdata if d not in rtop): | |
self.log('Exit {} - Rank {:.2f}'.format(d._name, rbot[d][0])) | |
self.order_target_percent(d, target=0.0) |