Sell order not executing from notify order
-
I am testing a strategy and I am issuing a sell order from notify order after execution of the buy leg. I use a custom sizer to size my position. My problem is that my strategy enters only 1 trade in the entire backtest when I use my custom sizer but when I use a fixed size sizer for the same conditions multiple trades are issued from the strategy.
Not sure why that is happening. Can anyone help with this.
# Custom sizer class class MySizer(bt.Sizer): def _getsizing(self, comminfo, cash, data, isbuy): size = (cash * 0.01)/(data.open[1] * 0.05) return math.floor(size) # Dummy strategy class test_strat(bt.Strategy): params = (('fma', 20), ('sma', 50), ('trail', 0.08),) def __init__(self): self.open = self.data.open self.high = self.data.high self.low = self.data.low self.close = self.data.close self.fma = bt.indicators.EMA(self.close, period = self.p.fma) self.sma = bt.indicators.EMA(self.close, period = self.p.sma) self.cross = bt.indicators.CrossUp(self.fma, self.sma) self.orders = None self.orefs = [] def log(self, txt, dt=None): dt = self.datas[0].datetime.date() print(f'Date: {dt}, {txt}') def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: return if order.status in [order.Completed]: if order.isbuy(): self.log(f'BUY EXECUTED: {order.executed.price}, Cost: {order.executed.value}, Size: {self.getposition().size}') self.execprice = order.executed.price self.totalcost = order.executed.value # o2 = self.sell(exectype=bt.Order.Stop, price=self.execprice * 0.95) o2 = self.sell(exectype=bt.Order.StopTrail, trailpercent = 0.05) self.orders = [o2] self.orefs = [o2.ref] self.log(f'SELL ORDERS CREATED: {self.orefs}') self.log(f'ORDERS IN THE SYSTEM: {self.orders}') self.log(f'Stop Created At: {self.execprice * 0.95}, Cash: {cerebro.broker.getcash()}') elif order.issell(): self.sellprice = order.executed.price self.sellcost = order.executed.value self.log(f'SELL EXECUTED: {self.sellprice}, Cost: {self.sellcost}') elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') if not order.alive() and order.ref in self.orefs: self.orefs.remove(order.ref) self.log(f'ORDERS ALIVE: {self.orefs}') self.log(f'LIVE ORDERS: {self.orders}') def notify_trade(self, trade): if trade.isopen: return else: self.log(f'OPERATION PROFIT: GROSS {trade.pnl}, NET {trade.pnlcomm}, Trade PnL: {trade.pnlcomm/self.totalcost}') self.log(f'Updated Account Balance: {cerebro.broker.getcash()}') def next(self): self.log(f'Close: {self.close[0]}') if self.orefs: return if not self.position: if self.cross > 0: o1 = self.buy() self.log(f'BUY CREATED: {o1.created.price}') self.orders = [o1] self.orefs = [o1.ref] self.log(f'INITIAL ORDERS: {self.orefs}') cerebro = bt.Cerebro() cerebro.broker.set_cash(200000) print(f'Starting Portfolio Value: {cerebro.broker.getvalue()}') data = bt.feeds.PandasData(dataname=hdfcbank, datetime=None, open=-1, high=-1, low=-1, close=-1, volume=-1) cerebro.adddata(data, name = 'hdfcbank') cerebro.addstrategy(test_strat) cerebro.addsizer(MySizer) cerebro.addanalyzer(trades_list, _name='tradelist') strat = cerebro.run(tradehistory = True) tradeslist = strat[0].analyzers.tradelist.get_analysis() trades = pd.DataFrame(tradeslist) print(f'Final Portfolio Value: {cerebro.broker.getvalue()}')
-
@vypy1 Hi can you include your logs showing the trades? Thanks.
-
@run-out Hi, for some reason when I add the attribute
size = order.executed.size
to my sell order in notify order while MySizer class is in use things work out as expected.
Without this when I look at the logs as provided below, I cant seem to understand why the trade does not close. After closing, it should notify me of this closed trade along with my profits.
Date: 2008-04-23, Close: 144.54 Date: 2008-04-24, Close: 144.26 Date: 2008-04-25, Close: 150.04 Date: 2008-04-28, Close: 152.34 Date: 2008-04-29, Close: 154.78 Date: 2008-04-30, Close: 152.42 Date: 2008-04-30, BUY CREATED: 152.42 Date: 2008-04-30, INITIAL ORDERS: [1868] Date: 2008-05-02, BUY EXECUTED: 154.5, Cost: 39861.0, Size: 258 Date: 2008-05-02, Stop Created At: 146.775, Cash: 160139.0 Date: 2008-05-02, Close: 154.04 Date: 2008-05-05, Close: 152.86 Date: 2008-05-06, Close: 154.29 Date: 2008-05-07, Close: 154.19 Date: 2008-05-08, SELL EXECUTED: 146.5755, Cost: 31981.5 Date: 2008-05-08, ORDERS ALIVE: [] Date: 2008-05-08, Close: 150.84 Date: 2008-05-09, Close: 145.25 Date: 2008-05-12, Close: 146.81 Date: 2008-05-13, Close: 148.03 Date: 2008-05-14, Close: 146.48 Date: 2008-05-15, Close: 147.85 Date: 2008-05-16, Close: 150.04 Date: 2008-05-20, Close: 146.12 Date: 2008-05-21, Close: 141.01 Date: 2008-05-22, Close: 138.38 Date: 2008-05-23, Close: 138.15 Date: 2008-05-26, Close: 134.76 Date: 2008-05-27, Close: 133.27
-
@vypy1 Your logs are not informative enough. Try using some or all of the following and then you'll get better data as to what's happening with your trades.
def notify_order(self, order): """ Triggered upon changes to orders. """ # Suppress notification if it is just a submitted order. if order.status == order.Submitted: return # Print out the date, security name, order number and status. dt, dn = self.datetime.date(), order.data._name type = "Buy" if order.isbuy() else "Sell" self.log( f"{order.data._name:<6} Order: {order.ref:3d}\tType: {type:<5}\tStatus" f" {order.getstatusname():<8} \t" f"Size: {order.created.size:9.4f} Price: {order.created.price:9.4f} " f"Position: {self.getposition(order.data).size}" ) if order.status == order.Margin: return # Check if an order has been completed if order.status in [order.Completed]: self.log( f"{order.data._name:<6} {('BUY' if order.isbuy() else 'SELL'):<5} " # f"EXECUTED for: {dn} " f"Price: {order.executed.price:6.2f} " f"Cost: {order.executed.value:6.2f} " f"Comm: {order.executed.comm:4.2f} " f"Size: {order.created.size:9.4f} " )
-
@run-out Thanks will try this out.