For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See:
Datafeed with only Close data
Hi All,
I have a dataset with only closing prices and a few fundamental variables.
Data looks something like this:
Date Close quality momentum value growth 0 2010-02-01 19.19 19 2 17 50 1 2010-03-01 21.14 24 4 20 55 2 2010-04-01 22.76 25 1 19 59 3 2010-05-03 24.22 24 6 17 63 4 2010-06-01 20.73 21 7 19 60
I've created my own CSV class as such:
class customCSV(bt.feeds.GenericCSVData): linesoverride = True # discard usual OHLC structure # datetime must be present and last lines = ('close','quality', 'momentum', 'value', 'growth', 'datetime',) # datetime (always 1st) and then the desired order for params = dict( datetime=0, close = 1, # default field pos 1 quality = 2, # default field pos 2 momentum = 3, # default field pos 3 value= 4, # default field pos 4 growth = 5, # default field pos 5 dtformat = '%Y-%m-%d', timeframe=bt.TimeFrame.Months, # fixed the timeframe openinterest=-1,)
I create the strategy below, which I basically copied from this article but changed self.ranks to work with my data.
def log(self, arg): print('{} {}'.format(self.datetime.date(), arg)) 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 # simple rank formula: Quality * a + Momentum * b + Value * c + Growth * d with a + b + c + d = 100 (no short) # the highest ranked: high value, high momentum, high quality and high growth self.ranks = {d: d.quality*0.25 + d.momentum*0.25 + d.value*0.25 + d.growth*0.25 for d in self.datas} 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 ) # 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:]) # prepare quick lookup list of stocks currently holding a position posdata = [d for d, pos in self.getpositions().items() if pos] # 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('Leave {} - Rank {:.2f}'.format(d._name, rbot[d][0])) self.order_target_percent(d, target=0.0) # rebalance those already top ranked and still there for d in (d for d in posdata if d in rtop): self.log('Rebal {} - Rank {:.2f}'.format(d._name, rtop[d][0])) self.order_target_percent(d, target=self.perctarget) del rtop[d] # remove it, to simplify next iteration # issue a target order for the newly top ranked stocks # do this last, as this will generate buy orders consuming cash for d in rtop: self.log('Enter {} - Rank {:.2f}'.format(d._name, rtop[d][0])) self.order_target_percent(d, target=self.perctarget)
When I run this however, I get the following error:
AttributeError: 'Lines_LineSeries_DataSeries_OHLC_OHLCDateTime_Abst' object has no attribute 'open'
I've tried cheat_on_close=True but this didn't work. Anyone have any advice on how to work with only Close data?
Thank you!