Sizer and Margin acting strange
Hey all - I have had this strange issue ever since I started using backtrader, and I have no idea what I am doing wrong even after reviewing all the documentation just now. The issue is that I get a Order Canceled/Margin/Rejected message even when I should definitely have more than enough cash in the account. Here are the specifics:
- I have set up a simple strategy to place a plain vanilla buy order on the 200th bar of the price data (for testing).
def next(self): if len(self.dataclose) == 200: self.log('BUY CREATE, %.2f' % self.dataclose) self.buy()
- The price at this time is $1.59 ie "BUY CREATE, 1.59"
2001-04-19, BUY CREATE, 1.59
I set start cash to 10000
sizer._getsizing returns 1000
Therefore, the size of the trade should be about $1590. Why can't I place this order? I should be able to buy up to 6,288 shares at this price. Also, there is no gap the next morning, this doesn't work with cheat on open either. I have not added any margin or commission information, everything is exactly like it is in the tutorials. This has been confusing me since the beginning, because sometimes I can get backtests to run by specifying random margin amounts and commission=0, but with them both being default and this notional size clearly lower than the value of the account, I don't understand what I am doing wrong. This works with stake = 1 and 100, but not 1000 and I can't identify what area of the code is causing this constraint. I have made also made sure that
self.broker.get_value()inside the sizer also returns 1.59, which it does. Any help would be appreciated.
class TestStrategy(bt.Strategy): def __init__(self): self.order = None self.dataclose = self.datas.close def log(self, txt, dt=None): ''' Logging function for this strategy''' dt = dt or self.datas.datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: # Buy/Sell order submitted/accepted to/by broker - Nothing to do return # Check if an order has been completed # Attention: broker could reject order if not enough cash if order.status in [order.Completed]: if order.isbuy(): self.log('BUY EXECUTED, %.2f' % order.executed.price) elif order.issell(): self.log('SELL EXECUTED, %.2f' % order.executed.price) self.bar_executed = len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') # Write down: no pending order self.order = None def next(self): if len(self.dataclose) == 200: self.log('BUY CREATE, %.2f' % self.dataclose) self.buy() class FixedSize(bt.Sizer): params = (('stake', 1000),) def _getsizing(self, comminfo, cash, data, isbuy): return self.params.stake cerebro = bt.Cerebro() cerebro.adddata(data) cerebro.addsizer(FixedSize) cerebro.addstrategy(TestStrategy) cerebro.broker.set_cash(10000) cerebro.run()
I think I figured out the issue. I am using an adjusted close column to calculate the signals, but the open, high, low columns are not adjusted.