Multidata strategy returning none type object
-
Hi, I am trying to test a simple cross over on multiple data feeds. Here I use a custom pandas subclass to add data and a custom sizer subclass to size my positions according to some conditions mentioned in the code below.
My problem is that when I use bt.sizers.FixedSize with whatever stake I wish, I do not get a nonetype error when I iterate over the self.orders[d] object (that holds all my orders) to get the order ref numbers. However when I use my custom sizer subclass MySizer, it throws an error that says nonetype object has no attribute ref. While I understand that the error is because self.orders[d] may not have any orders in reality, I don't know why the orders are not there?
My code:
class pandas_data_ext(bt.feeds.PandasData): lines = ('Peaks', 'Trough', ) params = ( ('nocase', True), ('datetime', None), ('open', -1), ('high', -1), ('low', -1), ('close', -1), ('volume', -1), ('openinterest', -1), ('Peaks', -1), ('Trough', -1), ) class MySizer(bt.Sizer): def _getsizing(self, comminfo, cash, data, isbuy): size = (cash * 0.01)/(data.open[1] * 0.05) return math.floor(size) class Breakout(bt.Strategy): params = (('fsma', 10), ('ssma', 20), ('roc', 10), ('stop', 0.95), ('atr', 20), ) def __init__(self): self.inds = {} for d in (self.datas): self.inds[d] = {} self.inds[d]['fsma'] = bt.talib.SMA(d.close, timeperiod = self.p.fsma) self.inds[d]['ssma'] = bt.talib.SMA(d.close, timeperiod = self.p.ssma) self.inds[d]['cross'] = bt.indicators.CrossUp(self.inds[d]['fsma'], self.inds[d]['ssma']) self.orders = {} self.execprice = None self.totalcost = None def log(self, txt, dt=None): dt = self.datas[0].datetime.date() print(f'Date: {dt}, {txt}') def notify_order(self, order): dt, dn = self.datetime.date(), order.data._name print('Date: {}, Name: {}, Order: {}, Type: {}, Status: {}'.format( dt, dn, order.ref, "Buy" * order.isbuy() or "Sell", order.getstatusname()) ) if order.status == order.Completed: self.execprice = order.executed.price self.totalcost = order.executed.value self.log(f'Executed price: {self.execprice}') order_name = ['main', 'stop', 'limit', 'close'] if not order.alive(): # not alive - nullify dorders = self.orders[order.data] idx = dorders.index(order) dorders[idx] = None self.log('-- No longer alive {} Ref'.format(order_name[idx])) self.log(f'Account Balance: {cerebro.broker.getcash()}') if all(x is None for x in dorders): dorders[:] = [] def notify_trade(self, trade): if trade.isopen: return else: self.log(f'OPERATION PROFIT: GROSS {round(trade.pnl, 2)}, NET {round(trade.pnlcomm, 2)}, Trade PnL: {round(trade.pnlcomm/self.totalcost, 2)}') self.log(f'Updated Account Balance: {cerebro.broker.getcash()}') def next(self): for d in (self.datas): name = d._name pos = self.getposition(d).size # if pos: self.log('Name: {}, Close: {}, Position: {}'.format(name, d.close[0], pos)) if d.Peaks == 1.0: self.inds[d]['prev_high'] = d.high[0] if not pos and not self.orders.get(d): if self.inds[d]['cross'] > 0: p1 = d.open[1] p2 = p1 * self.p.stop # p3 = round(d.close[0] - (self.inds[d]['atr'] * 3), 2) o1 = self.buy(data = d, exectype = bt.Order.Market, transmit = False) o2 = self.sell(data = d, price = p2, exectype = bt.Order.Stop, transmit = False, parent = o1) o3 = self.sell(data = d, exectype = bt.Order.StopTrail, trailpercent = 0.07, transmit = True, parent = o1) self.orders[d] = [o1, o2, o3] self.orefs = [o.ref for o in self.orders[d]] self.log('Name: {}, Buy at: {}, Stop at {}'.format(name, p1, p2)) self.log(f'Order Numbers are : {self.orefs}') cerebro = bt.Cerebro() cerebro.broker.set_cash(200000) print(f'Starting Portfolio Value: {cerebro.broker.getvalue()}') for n in range(len(all_dfs_one)): dataset = list(zip(all_dfs_one, stocks)) data = pandas_data_ext(dataname=dataset[n][0], datetime=None, open=-1, high=-1, low=-1, close=-1, volume=-1, Peaks=-1, Trough=-1) cerebro.adddata(data, name = dataset[n][1]) cerebro.addstrategy(Breakout) cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name = 'mytrades') cerebro.addsizer(MySizer) cerebro.broker.setcommission(commission = 0.0015) # cerebro.addwriter(bt.WriterFile, csv=True, out = f'/Users/varadjoshi/Documents/Markets Data/multidata.csv', csv_counter = False) cerebro.run() print(f'Final Portfolio Value: {cerebro.broker.getvalue()}') # print(f'Trades: {strats.analyzers.mytrades.get_analysis()}')
-
@vypy1 I"m not sure what the problem is but I would check the values here:
def _getsizing(self, comminfo, cash, data, isbuy): size = (cash * 0.01) / (data.open[1] * 0.05) new_size = math.floor(size) print(size, comminfo, cash, data, isbuy, new_size) return new_size
If you have a large value stock, you could be getting zero shares traded since the fraction would be less than one, and the floor of that would be zero.
-
@run-out Let me check that
-
@run-out Yup you are right, it is trading in decimals which is not possible. Let me do something to fix this.