Sizer trouble
-
Some (not all!) of my orders get MARGIN rejected and I cannot figure out why. Please help, thanks in advance.
Below I buffer the orders by 50 USD in the Sizer but I still get the MARGIN :(
_getsizing:
result = int(cash_per_order / data.open[1]) * self.coef result = round(result, 0) while True: c = comminfo.getcommission(result, data.open[1]) if result * data.open[1] + c < self.broker.get_cash()-50: break result -= 1 # price, size, commission, all costs, available cash print("Sizer:", data.open[1], result, c, result * data.open[1] + c, self.broker.get_cash())
notify_order:
elif (o_status == "Margin"): self.cancel(self.order[symbol]) self.order[symbol] = None print("\n", "MARGIN!", order.p.data.open[0], order.size, self.broker.get_cash(), "\n")
Result:
Sizer: 10.814 9347 46.735 101125.193 101180.15400000001MARGIN! 10.814 9347 101180.15400000001
The whole (very straightforward) Sizer:
class LongSizer(bt.Sizer): #coef = 0.95 coef = 1 def _getsizing(self, comminfo, cash, data, isbuy): result = 0 if isbuy is True: if self.strategy.getposition(data) is not None: if self.strategy.getposition(data).size > 0: return 0 max_pos_value = int(self.broker.get_value() / self.strategy.max_stake) cash_per_order = int(self.broker.get_cash() / len(self.strategy.buy_orders.keys())) if cash_per_order > max_pos_value: cash_per_order = max_pos_value try: if cash_per_order > data.open[1]: result = int(cash_per_order / data.open[1]) * self.coef result = round(result, 0) while True: c = comminfo.getcommission(result, data.open[1]) if result * data.open[1] + c < self.broker.get_cash()-50: break result -= 1 print("Sizer:", data.open[1], result, c, result * data.open[1] + c, self.broker.get_cash()) else: return 0 except IndexError: return 0 else: if self.strategy.getposition(data) is not None: if self.strategy.getposition(data).size > 0: result = self.strategy.getposition(data).size return result
-
I ended up by disabling the check as suggested here: https://community.backtrader.com/topic/782/help-with-simple-bband-strategy
cerebro.broker.set_checksubmit(checksubmit=False)
However, I would still appreciate to learn what's wrong with the Sizer or how to debug the issue further. Looks like a BT bug for me :S
-
@kriku Could you clarify a few things?
- What is this variable that's showing up?
data.open[1]
- Could you print out logs with labels so we can follow along without hunting?
Sizer: 10.814 9347 46.735 101125.193 101180.15400000001
- Could you print out a log where margin is happening with OHLCV, both sides of the trade please, along with the margin error message?
Thank you.
- What is this variable that's showing up?
-
@run-out By both sides I mean before and after.
-
Sorry for the delay.
@run-out said in Sizer trouble:
- What is this variable that's showing up?
data.open[1]
data.open[1] is the next bar of the data feed (the nearest bar in the future) as data.open[0] is the current bar. As you see, the open price value by which the sizing is done (10.685), is the same as the open price value printed out by the order status change handler in the MARGIN message. For the sizer, it is open[1] and for the order status change handler it is open[0] because the handler is triggered at the next bar.
- Could you print out logs with labels so we can follow along without hunting?
Sizer: 10.814 9347 46.735 101125.193 101180.15400000001
print("Sizer:", data.open[1], result, c, result * data.open[1] + c, self.broker.get_cash())
Prints out the following:
- the next open bar value used for sizing;
- result of the _get_sizing (the size determined in the current function);
- commission as c;
- size * open price of the next bar + commission (by my current understanding, the total cost of the transaction);
- amount of cash obtained from the broker.
- Could you print out a log where margin is happening with OHLCV, both sides of the trade please, along with the margin error message?
Here you are:
dt = self.datas[0].datetime.datetime() print(dt, order.p.data.open[0], order.p.data.high[0], order.p.data.low[0], order.p.data.close[0], order.p.data.volume[0])
2005-03-23 11:00:00 10.668 10.728 10.625 10.687 9830985.0
Sizer: 10.685 10009 50.045 106996.21 106998.12
2005-03-23 12:00:00 MARGIN! 10.685 10009 106998.12
2005-03-23 12:00:00 10.685 10.771 10.685 10.719 7653056.0Looks like the broker is trying to add some additional costs besides open price & commission but I have no idea what these could possibly be.
- What is this variable that's showing up?
-
BTW, I have removed the $50 buffer from the Sizer so that the line
if result * data.open[1] + c < self.broker.get_cash()-50:
is now as following:
if result * data.open[1] + c < self.broker.get_cash():
-
@kriku data.open[1] is not really a thing in backtrader. I'm not sure what value you are getting for that, but you can't look forward in backtrader.
If you want to use the next open pricing for sizing, you use the following instructions for cheat on open.
Try also putting in a lot of money and then use only only a small amount of cash to trade (eg. $100 million and trade 100 shares of whatever). See if your margin dissappears. If it does, then your normal code is too close to the line when markets shoot up the next day.
-
@run-out That's not true. There are a number of posts on the issue, for example this: https://community.backtrader.com/topic/260/how-to-buy-maximum-stakes
My code clearly demonstrates that data.open[1] retrieves the next open price.
-
@run-out Btw, the exact method to determine the size of the order is quite irrelevant, be it with data.open[1] or not. The log shows that a MARGIN status is raised although the order + commission is less than available cash.
-
Relevant part from the documentation:
And although people can try to look into the future with a positive [1] index approach, this requires preloading data which is not always available.
https://www.backtrader.com/docu/cerebro/cheat-on-open/cheat-on-open/