Open t3chap opened 1 year ago
Bracket orders entered into the IB API don't automatically cancel the unfilled part when the other side of the bracket is filled when using the buy_bracket or sell_bracket. This could be because of a change on IB's side of things, I'm not certain. The orders when viewed from the IBAPI have One Cancel Another group names but just aren't cancelling, leaving unexpected orders working.
the line in the code seems to work if it is changed to oid = ex.orderId
It appears the api update changed the case of the beginning of the variable. However, I'm still not able to get bracket orders to be placed in the IBAPI with the same OCA grouping, which still leads to orphaned orders.
Any update on this? The two main strategies I'm working on are using those handy bracket orders... I guess at least I can rewrite and handle myself the cancellation of the unfilled part of the main order.
I just made my own versions as methods. Ideally the correct ones would be fixed but to make this possible to trade I did the following, which seems to work just fine:
def buy_bracket_market(self,size=1, stopprice=None, limitprice=None, ** kwargs):
'''replace the organic buy_bracket order since no longer integrates
with IB well. This buys at the market and sets a bracket at the
stop price and limit price.
'''
try:
nextid = self.broker.get_high_order_id()
print('next id is {}' . format(nextid))
if stopprice:
if limitprice:
print('buying bracket testing target: {} stop: {} ' . format(limitprice,stopprice))
oca_group = (uuid.uuid4())
main_order = self.buy(exectype=bt.Order.Market, size = size, transmit = False, ** kwargs)
self.broker.get_high_order_id()
time.sleep(.1)
take_profit_order = self.sell(exectype=bt.Order.Limit, price = limitprice, size = main_order.size,\
transmit=False,ocaType = 1, ocaGroup = oca_group, ** kwargs)
self.broker.get_high_order_id()
time.sleep(.1)
stop_loss_order = self.sell(exectype=bt.Order.Stop, price = stopprice, size = main_order.size,\
transmit=True,ocaType = 1, ocaGroup = oca_group, ** kwargs)
else:
print('missing limitprice')
else:
print('missing stopprice')
except: #this might be problemmatic if only part of the previous bracket failed, we'd end up with unintentional duplicates
nextid = self.broker.get_high_order_id()
print('next id is {}' . format(nextid))
if stopprice:
if limitprice:
print('selling bracket testing target: {} stop: {} ' . format(limitprice,stopprice))
oca_group = (uuid.uuid4())
main_order = self.sell(exectype=bt.Order.Market, size = size, transmit = False, ** kwargs)
self.broker.get_high_order_id()
time.sleep(.1)
take_profit_order = self.buy(exectype=bt.Order.Limit, price = limitprice, size = main_order.size, \
transmit=False,ocaType = 1, ocaGroup = oca_group, ** kwargs)
self.broker.get_high_order_id()
time.sleep(.1)
stop_loss_order = self.buy(exectype=bt.Order.Stop, price = stopprice, size = main_order.size, \
transmit=True,ocaType = 1, ocaGroup = oca_group, ** kwargs)
#bracket_order = [main_order,take_profit_order,stop_loss_order]
#return bracket_order
else:
print('missing limitprice')
else:
print('missing stopprice')
def sell_bracket_market(self,size=1, stopprice=None, limitprice=None, ** kwargs):
'''replace the organic sell_bracket order since no longer integrates
with IB well. This sellss at the market and sets a bracket at the
stop price and limit price.
'''
try:
nextid = self.broker.get_high_order_id()
print('next id is {}' . format(nextid))
if stopprice:
if limitprice:
print('selling bracket testing target: {} stop: {} ' . format(limitprice,stopprice))
oca_group = (uuid.uuid4())
main_order = self.sell(exectype=bt.Order.Market, size = size, transmit = False, ** kwargs)
self.broker.get_high_order_id()
time.sleep(.1)
take_profit_order = self.buy(exectype=bt.Order.Limit, price = limitprice, size = main_order.size, \
transmit=False,ocaType = 1, ocaGroup = oca_group, ** kwargs)
self.broker.get_high_order_id()
time.sleep(.1)
stop_loss_order = self.buy(exectype=bt.Order.Stop, price = stopprice, size = main_order.size, \
transmit=True,ocaType = 1, ocaGroup = oca_group, ** kwargs)
#bracket_order = [main_order,take_profit_order,stop_loss_order]
#return bracket_order
else:
print('missing limitprice')
else:
print('missing stopprice')
except:
nextid = self.broker.get_high_order_id()
print('next id is {}' . format(nextid))
if stopprice:
if limitprice:
print('selling bracket testing target: {} stop: {} ' . format(limitprice,stopprice))
oca_group = (uuid.uuid4())
main_order = self.sell(exectype=bt.Order.Market, size = size, transmit = False, ** kwargs)
self.broker.get_high_order_id()
time.sleep(.1)
take_profit_order = self.buy(exectype=bt.Order.Limit, price = limitprice, size = main_order.size, \
transmit=False,ocaType = 1, ocaGroup = oca_group, ** kwargs)
self.broker.get_high_order_id()
time.sleep(.1)
stop_loss_order = self.buy(exectype=bt.Order.Stop, price = stopprice, size = main_order.size, \
transmit=True,ocaType = 1, ocaGroup = oca_group, ** kwargs)
#bracket_order = [main_order,take_profit_order,stop_loss_order]
#return bracket_order
else:
print('missing limitprice')
else:
print('missing stopprice')
File ~/anaconda3/lib/python3.9/site-packages/atreyu_backtrader_api-0.1.0-py3.9.egg/atreyu_backtrader_api/ibbroker.py:358 in submit order.ocaGroup = self.orderbyid[order.oco.orderId].ocaGroup
AttributeError: 'int' object has no attribute 'orderId'
Exception: 'Execution' object has no attribute 'OrderId' Traceback (most recent call last): File "/home/tim/anaconda3/lib/python3.9/site-packages/atreyu_backtrader_api-0.1.0-py3.9.egg/atreyu_backtrader_api/ibbroker.py", line 520, in push_commissionreport oid = ex.OrderId AttributeError: 'Execution' object has no attribute 'OrderId' ExecId: 0000e1a7.641848b4.01.01, Commission: 0.770000, Currency: USD, RealizedPnL: , Yield: , YieldRedemptionDate: 0