Implementing Bracket Orders for binance API
-
From my research online, I understand that binance doesn't provide an option to place bracket orders directly, so, inspite of being able to use backet orders while backtesting using backtrader, it's difficult to deploy the same backtrader code into the live markets. Luckily, binance supports OCO(One cancels the other) orders which I could use to place a target and stoploss once I enter into a position. So, I am looking for some thoughts on how I could manually create bracket orders in the strategy class.
class Strategy(bt.Strategy): def __init__(self): self.close = self.datas[0].close .. ..... .... def next(self): if not self.order and not self.position: Print("Case 1 - Place order if strategy conditions are met") if not self.order and self.position: Print("Case 2 - Send the stoploss and target orders") if self.order and not self.position: Print("Case 3 - Check if the order is still valid based on the strategy being applied on fresh data, if not, cancel the existing entry order") if self.order and self.position: - Print("Case 4 - Sit back and relax!")
So, all the print statements are for reference and I want to implement the idea of the respective comments. When I have a position and no orders, that means I need to quickly send a target and stoploss order using the OCO order type(case 2) but the issue is my stoploss/target values are already decided when I place an entry order(case 1) and I just can't figure out where to store these stoploss/target values before the backtrader enters the case 2(to create an OCO order) in the next iteration after the order is filled into a position. Is there a way I could store these value somewhere?
Also, I would appreciate if there are any alternative strategies that I could to create the bracket order behaviour?
And, lastly, a fundamental question wrt live markets, let's say, I am working on 15 min candles, I believe the backtrader will only work once in 15 mins and remains quiet the rest of the time, basically whenever new data is available it triggers the next function right? If yes, I believe my approach to create the bracket order is doomed because if I wait for 15 mins to place the OCO order(stoploss and target orders) after my entry order turns into a position, I might have a naked position in the market for 15 mins in a worst case scenario and that's not an outcome I could take a risk on!
I hope someone could throw some thoughts on my issues, I want to deploy the backtrader algo on binance real-time if that info matters. Thank you!
-
@godseye You should use the
notify_order
method. When your order gets filled, you will get a call tonotify_order
. From here you check if the order is complete and then issue your new orders.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 if order.status == order.Margin: return # Check if an order has been completed if order.status in [order.Completed]: ####### ISSUE BRACKET ORDERS HERE ####### 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"Value: {order.executed.value:6.2f} " f"Comm: {order.executed.comm:4.2f} " f"Size: {order.created.size:9.4f} " )
-
@run-out really appreciate the response, that makes a lot of sense to me now, one last question is how to handle partial fills? I believe even if my entry trade is partially filled it appears in the order.Submitted I understand. so let's say I placed an order for entry with quantity 10, and only 5 got filled initial(which is a partial fill) and then my backtrader enters the notify_trade() block, so I place an order for tp/sl (OCO) with 5 lots. but then when the rest of it is filled, now backtrader enters the notify_order() block again this time will it show the quantity filled in the order as 10 or 5? if it's 10 I will be in a situation that it places 10 lots of oco order rather than 5. How should I overcome this situation?
Also, when the OCO order is filled, even then it enters the order.completed in the notify_order right? is there a way I could find the difference between simple buy/sell order(that I place to enter the trader - so, want to use the details in order.completed) and my oco orders(placed for stoploss/target, - so don't want to use it in order.completed)?
-
@godseye said in Implementing Bracket Orders for binance API:
Submitted I understand. so let's say I placed an order for entry with quantity 10, and only 5 got filled initial(which is a partial fill) and then my backtrader enters the notify_trade() block, so I place an order for tp/sl (OCO) with 5 lots. but then when the rest of it is filled, now backtrader enters the notify_order() block again this time will it show the quantity filled in the order as 10 or 5? if it's 10 I will be in a situation that it places 10 lots of oco order rather than 5. How should I overcome this situation?
I"m not 100% on this but I can get you the right direction. Orders have events as follows:
['Created', 'Submitted', 'Accepted', 'Partial', 'Completed', 'Canceled', 'Expired', 'Margin', 'Rejected']
You can specify the event you are looking for in the notify_order method:
if order.status == order.Submitted: return
If you wish to do stuff for partial orders, then
if order.status == order.Partial: return
For details on partial orders, check the docs :
Notifications may happen even several times for the same status in the case of Order.Partial. This status will not be seen in the backtesting broker (which doesn’t consider volume when matching) but it will for sure be set by real brokers. Real brokers may issue one or more executions before updating a position, and this group of executions will make up for an Order.Partial notification. Actual execution data is in the attribute: order.executed which is an object of type OrderData (see below for the reference), with usual fields as size and price
@godseye said in Implementing Bracket Orders for binance API:
Also, when the OCO order is filled, even then it enters the order.completed in the notify_order right? is there a way I could find the difference between simple buy/sell order(that I place to enter the trader - so, want to use the details in order.completed) and my oco orders(placed for stoploss/target, - so don't want to use it in order.completed)?
The non-completed leg of an OCO is 'cancelled` status, not complete.
-
@run-out said in Implementing Bracket Orders for binance API:
if order.status == order.Partial:
returnShould read:
if order.status == order.Partial: do stuff here
-
@godseye said in Implementing Bracket Orders for binance API:
I might have a naked position in the market for 15 mins in a worst case scenario and that's not an outcome I could take a risk on!
Have you solved the naked position problem?