Bracket Order Parameters
Dave-Vallance opened this issue · 1 comments
When creating a buy and sell order, some exchanges (Binance) can return an error if Backtrader's Bracket order kwargs parent
and transmit
are present in the request.
The current workaround is to delete the kwargs before submitting the order. However, this might limit integration of bracket orders in the future.
As such, a more elegant solution would be good.
Example of deletion in current code base:
def buy(self, owner, data, size, price=None, plimit=None,
exectype=None, valid=None, tradeid=0, oco=None,
trailamount=None, trailpercent=None,
**kwargs):
del kwargs['parent']
del kwargs['transmit']
return self._submit(owner, data, exectype, 'buy', size, price, kwargs)
Reference to pull request: #2
I tried to trail the code with references from onandabroker.py, _transmit(), similar to _submit()
I don't have good grasp of your work yet, but it seems to me that enabling bracket orders could be a matter of restructing the broker code to function similar to the other samples in Backtrader's official repo? The biggest differences in style seem to be that ccxtbroker.py creates and submits the ccxt order first, before creating the Backtrader Order object in the submit() method;
def _submit(self, owner, data, exectype, side, amount, price, params):
...
ret_ord = self.store.create_order(symbol=data.symbol, order_type=order_type, side=side,
amount=amount, price=price, params=params)
_order = self.store.fetch_order(ret_ord['id'], data.symbol)
order = CCXTOrder(owner, data, _order) # Subclass of OrderBase
...
Whereas the official broker samples create the Order object in the buy() method and sends the object to transmit()/_submit(). Here is the buy() from onandabroker.py, where BuyOrder() is the subclass of OrderBase, just like CCXTOrder():
def buy(self, owner, data,
size, price=None, plimit=None,
exectype=None, valid=None, tradeid=0, oco=None,
trailamount=None, trailpercent=None,
parent=None, transmit=True,
**kwargs):
order = BuyOrder(owner=owner, data=data,
size=size, price=price, pricelimit=plimit,
exectype=exectype, valid=valid, tradeid=tradeid,
trailamount=trailamount, trailpercent=trailpercent,
parent=parent, transmit=transmit)
order.addinfo(**kwargs)
order.addcomminfo(self.getcommissioninfo(data))
return self._transmit(order) # Equivalent to _submit() in ccxtbroker.py
Following which, getting bracket function could be a matter of adding the following code snippet (just an example):
def _submit(self, owner, data, exectype, side, amount, price, params):
...
...
order = CCXTOrder(owner, data, _order) # Subclass of OrderBase
oref = order.ref
pref = getattr(order.parent, 'ref', oref) # parent ref or self
if params.transmit:
if params.parent != order.ref: # children order
# Put parent in orders dict, but add stopside and takeside
# to order creation. Return the takeside order, to have 3s
takeside = order # alias for clarity
parent, stopside = self.opending.pop(pref)
for o in parent, stopside, takeside:
self.orders[o.ref] = o # write them down
self.brackets[pref] = [parent, stopside, takeside]
self.o.order_create(parent, stopside, takeside)
return takeside # parent was already returned
else: # Parent order, which is not being transmitted
self.orders[order.ref] = order
return self.o.order_create(order)