Skip to content
This repository has been archived by the owner on Mar 14, 2024. It is now read-only.

Bracket order with several take profit #694

Open
ingelrii opened this issue Feb 15, 2024 · 3 comments
Open

Bracket order with several take profit #694

ingelrii opened this issue Feb 15, 2024 · 3 comments

Comments

@ingelrii
Copy link

ingelrii commented Feb 15, 2024

Hello,
I’m trying to set a bracket order, and I want to place a parent order with several take profits, each one with different targets. To do it, I place 3 bracket orders, but when the first one is filled, I get the error 201-cancelled order ‘you cannot have both sides of the contract…’.

this is the code I run:

def our_BracketOrder(ib, n_buy_contracts, opt_contract):
parent = Order()
parent.orderId = ib.client.getReqId()
parent.action = "BUY"
parent.orderType = "MKT"
parent.totalQuantity = n_buy_contracts
parent.transmit = False

takeProfit = Order()
takeProfit.orderId = parent.orderId + 1
takeProfit.action = "SELL"
takeProfit.orderType = "LMT"
takeProfit.totalQuantity = n_buy_contracts
takeProfit.lmtPrice = 3
takeProfit.parentId = parent.orderId
takeProfit.transmit = False

stopLoss = Order()
stopLoss.orderId = parent.orderId + 2
stopLoss.action = "SELL"
stopLoss.orderType = "STP"
stopLoss.auxPrice = 0.5
stopLoss.totalQuantity = n_buy_contracts
stopLoss.parentId = parent.orderId
stopLoss.transmit = True

BO = {'parent': parent, 'takeProfit': takeProfit, 'stopLoss':stopLoss}
return BO

def our_BracketOrder2(ib, n_buy_contracts, opt_contract):
parent2 = Order()
parent2.orderId = ib.client.getReqId()
parent2.action = "BUY"
parent2.orderType = "MKT"
parent2.totalQuantity = n_buy_contracts
parent2.transmit = False

takeProfit2 = Order()
takeProfit2.orderId = parent2.orderId + 1
takeProfit2.action = "SELL"
takeProfit2.orderType = "LMT"
takeProfit2.totalQuantity = n_buy_contracts
takeProfit2.lmtPrice = 3
takeProfit2.parentId = parent2.orderId
takeProfit.transmit = False

stopLoss2 = Order()
stopLoss2.orderId = parent2.orderId + 2
stopLoss2.action = "SELL"
stopLoss2.orderType = "STP"
stopLoss2.auxPrice = 0.5
stopLoss2.totalQuantity = n_buy_contracts
stopLoss2.parentId = parent2.orderId
stopLoss2.transmit = True

BO2 = {'parent': parent2, 'takeProfit': takeProfit2, 'stopLoss':stopLoss2}
return BO2

The lmtPrice and auxPrice should be changed once the first parent order has been filled.

I think maybe I could change the order as it follows:

def our_BracketOrder(ib, n_buy_contracts, opt_contract):
parent = Order()
parent.orderId = ib.client.getReqId()
parent.action = "BUY"
parent.orderType = "MKT"
parent.totalQuantity = n_buy_contracts
parent.transmit = False

takeProfit = Order()
takeProfit.orderId = parent.orderId + 1
takeProfit.action = "SELL"
takeProfit.orderType = "LMT"
takeProfit.totalQuantity = n_buy_contracts
takeProfit.lmtPrice = 3
takeProfit.parentId = parent.orderId
takeProfit.transmit = False

stopLoss = Order()
stopLoss.orderId = parent.orderId + 2
stopLoss.action = "SELL"
stopLoss.orderType = "STP"
stopLoss.auxPrice = 0.5
stopLoss.totalQuantity = n_buy_contracts
stopLoss.parentId = parent.orderId
stopLoss.transmit = True

parent2 = Order()
parent2.orderId = ib.client.getReqId()
parent2.action = "BUY"
parent2.orderType = "MKT"
parent2.totalQuantity = n_buy_contracts
parent2.transmit = False

takeProfit2 = Order()
takeProfit2.orderId = parent2.orderId + 1
takeProfit2.action = "SELL"
takeProfit2.orderType = "LMT"
takeProfit2.totalQuantity = n_buy_contracts
takeProfit2.lmtPrice = 3
takeProfit2.parentId = parent2.orderId
takeProfit.transmit = False

stopLoss2 = Order()
stopLoss2.orderId = parent2.orderId + 2
stopLoss2.action = "SELL"
stopLoss2.orderType = "STP"
stopLoss2.auxPrice = 0.5
stopLoss2.totalQuantity = n_buy_contracts
stopLoss2.parentId = parent2.orderId
stopLoss2.transmit = True

BO = {'parent': parent, 'takeProfit': takeProfit, 'stopLoss':stopLoss, 'parent2': parent2, 'takeProfit2': takeProfit2, 'stopLoss2':stopLoss2}
return BO

or maybe like this:

def our_BracketOrder(ib, n_buy_contracts, opt_contract):
parent = Order()
parent.orderId = ib.client.getReqId()
parent.action = "BUY"
parent.orderType = "MKT"
parent.totalQuantity = n_buy_contracts
parent.transmit = False

takeProfit = Order()
takeProfit.orderId = parent.orderId + 1
takeProfit.action = "SELL"
takeProfit.orderType = "LMT"
takeProfit.totalQuantity = n_buy_contracts/2
takeProfit.lmtPrice = 3
takeProfit.parentId = parent.orderId
takeProfit.transmit = False


takeProfit2 = Order()
takeProfit2.orderId = parent.orderId + 1
takeProfit2.action = "SELL"
takeProfit2.orderType = "LMT"
takeProfit2.totalQuantity = n_buy_contracts/2
takeProfit2.lmtPrice = 3
takeProfit2.parentId = parent.orderId
takeProfit.transmit = False

stopLoss = Order()
stopLoss.orderId = parent.orderId + 2
stopLoss.action = "SELL"
stopLoss.orderType = "STP"
stopLoss.auxPrice = 0.5
stopLoss.totalQuantity = n_buy_contracts
stopLoss.parentId = parent.orderId
stopLoss.transmit = True

BO = {'parent': parent, 'takeProfit': takeProfit, 'takeProfit2': takeProfit2, 'stopLoss':stopLoss}
return BO

Has somebody got any idea how to set this order properly?

thank you very much

@mattsta
Copy link
Contributor

mattsta commented Mar 4, 2024

Your orderId logic looks a bit off because if you manually increment parent.orderId + N then the ib.client.getReqId() will generate duplicate IDs in the future. You can just use getReqId() each time.

Your last example looks like it should work, but you'll have a problem if only one take profit triggers at (shares/2) then the price collapses and your stop executes at (shares) because you'll end up short (shares/2) instead of flat like you probably expect.

@ingelrii
Copy link
Author

ingelrii commented Mar 4, 2024

Hello @mattsta!
Thank you very much for your help.
How should I inform the quantity for the take profits and the stop loss to avoid end up short??
For instance, If I buy 2 contracts, instead of buy_contracts/2, should I code the stop loss as the remaining contracts??
Thanks!!

@mattsta
Copy link
Contributor

mattsta commented Mar 5, 2024

There's not a "simple" way for IBKR to fix the problem of multiple take-profit at different levels also with a full remaining quantity stop out condition.

Basically, you'd need to write a custom system to watch your trade executions (add a commisionReportEvent handler to catch every symbol+price+side+profit update) then if your take profit order executes first, you submit an order modification to reduce the quantity for the stop loss each time. Also, there's no guarantee a take profit limit order will execute the full quantity anyway so you need to track your live positions against the executed positions on every update too (so you could have: BUY 100, SELL 50, SELL 50, STOP 100, but maybe it executes BUY 100, SELL 25, STOP 100 (you end up short -25), so you would need to manually update STOP 100 to be STOP 75 after the first SELL 25 happens, etc).

It's not easy to automate multiple partial take profit orders like that, but it can be done if you track all the edge cases.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants