How to Create Bracket Orders with IBPy ?

1,601 views
Skip to first unread message

Remi Roche

unread,
Jun 29, 2016, 1:02:53 PM6/29/16
to IbPy Discuss
Hello, 

I am struggling with bracket orders and IBPy.

For info, I have tried unsuccessfully to use this code :

    def createBracketOrder(origOrder, oID, tif, orderType,price):
       
#cc = copy.copy(origContract)
        bracketoptOrder
= Utils.makeOptOrder( Side.flipside(origOrder.m_action), oID, tif, orderType,price,origOrder.m_totalQuantity)
        bracketoptOrder
.m_parentId = origOrder.m_orderId
       
return bracketoptOrder



Do you have any working example of how to execute a bracket order ?

Many thanks,

Rgds,

Remi

Derek Tishler

unread,
Jul 2, 2016, 10:29:59 AM7/2/16
to IbPy Discuss
When creating bracket orders or in general when adding profit takes or stops you need to ensure that m_transmit is set to false on all but the last child order. Otherwise any child will be canceled instantly by TWS. Check for errors such as improper prices, for example you must adhere to price tick increments in stocks or forex, aka no fractional prices that the books cant recognize.

One tip I suggest is creating the order in TWS with the expanded order window, this helps show what fields/setup might be needed to achieve the desired behavior. For example the difference between aux and limit price when dealing with relative orders vs relative limit orders.

You might want to req messages for errors(useful ones) like this and keep and eye on TWS to ensure the order it set up correctly. Since the api is simulating allot of features, you REALLY want to ensure that your order is being set up and acting as it should.:
def error(self, msg):
        if msg.errorCode != 2104 and msg.errorCode != 2106:
            print '\nOrderSystem.py:\t',self.clientId,msg

con.register(error, message.error)

Remi Roche

unread,
Jul 3, 2016, 5:27:30 PM7/3/16
to IbPy Discuss
Hello Derek,

Thank you for your help. I will give it a try this week :)

After intense reading of IB API and your tips, I have confidence to make it run by end of week. I will let you know :)

Thanks again :)

Remi 
Message has been deleted
Message has been deleted

Derek Tishler

unread,
Jul 9, 2016, 9:47:24 AM7/9/16
to IbPy Discuss
Here is some sample code that I took from my order system to show an example of how to go about assembling an entry order with multiple children(profit take, stop loss).


# Example of a IBpy TWS bracker order submission
# Derek M Tishler, 2016
# DMTishler at gmail dot com

# sample function to create basic contract
def make_contract(self, symbol, sec_type, exch, prim_exch, curr):
        Contract.m_symbol      = symbol
        Contract.m_secType     = sec_type
        Contract.m_exchange    = exch
        Contract.m_primaryExch = prim_exch
        Contract.m_currency    = curr
        return Contract

def make_order(self, action, qty, limit = None, profit_take_percent=None, training_stop_percent=None, transmit=True, parentId=None):
        order = Order()

        # is child order?
        if parentId is not None:
            order.m_parentId = parentId
        
        order.m_action        = action
        order.m_totalQuantity = qty

        if profit_take_percent is not None:
        # This will set up out profit take
            order.m_orderType = 'LMT'
            if action == 'BUY':
            # Rounding is due to FX, we cannot create an order with bad price, and FX book increments at 0.00005 only!
                order.m_lmtPrice  = limit - int(np.around((limit*profit_take_percent)/100.0, 5)/0.00005)*0.00005
            elif action == 'SELL':
                order.m_lmtPrice  = limit + int(np.around((limit*profit_take_percent)/100.0, 5)/0.00005)*0.00005
        elif training_stop_percent is not None:
        # This will set up out trailing stop
            order.m_orderType = 'TRAIL'
            order.m_training_stop_percent = training_stop_percent
        elif limit is not None:
        # A simple limit order
            order.m_orderType = 'LMT'
            order.m_lmtPrice = limit
        else:
        # A simple market order
            order.m_orderType = 'MKT'
            
        # Important that we only send the order when all children are formed.
        order.m_transmit      = transmit

        return order

############### Actual order creation #####################
# Same inputs, usualy set up programatically and tracked in order to update orders on the fly
symbol   = 'EUR.USD'
secType  = 'CASH'
exchange = 'IDEALPRO'
oid      = 1 #You need to request a valid order id(reqIDs), and also manage them better than order+1 for child orders?
ammount  = 1000 #1k shares
limit    = 1.00000 #limit price
action   = 'BUY'
counter_action = 'SELL'

# create parent order(entry)
CONTRACT = self.make_contract(symbol, secType, exchange, exchange, 'USD')
ORDER = self.make_order(action, abs(int(ammount)), limit, transmit=False)
self.con.placeOrder(oid, CONTRACT, ORDER)

# create a profit take order of some kind
ORDER = self.make_order(counter_action, abs(int(ammount)), limit, profit_take_percent=0.0125, parentId=oid, transmit=False)
        self.con.placeOrder(oid+1, CONTRACT, ORDER)

# create astop loss order, and THEN transmit(set transmit to true) the entire order by placing this last child order(note inTWS it looks like a tree with parent order and two sub orders inside)
ORDER = self.make_order(counter_action, abs(int(ammount)), limit, training_stop_percent=0.5, parentId=oid, transmit=True)
self.con.placeOrder(oid+2, CONTRACT, ORDER)




On Wednesday, June 29, 2016 at 1:02:53 PM UTC-4, Remi Roche wrote:

Remi Roche

unread,
Jul 11, 2016, 5:11:52 PM7/11/16
to IbPy Discuss
Hello Derek,

Thank you very much for your help.

I was able to create and execute a bracket order from your assembling orders example. That's awesome !! :D

Many thanks again.

Cheers,

Reim

Remi Roche

unread,
Jul 18, 2016, 9:43:26 AM7/18/16
to IbPy Discuss
Hello Derek,

Here are the results ;). Posting here as can help others:

"""
README
======
This file contains Python codes.
Desc : Implementation of Bracket Order, Long with IBPy and a simple order id management
Author: remroc inspired by DerekT and many more ;)
======
"""

from ib.ext.Contract import Contract
from ib.ext.Order import Order
from ib.opt import Connection, message
import time
import datetime as dt


class System:
   
def __init__(self, symbol, secType, exchange, primary_exchange, currency,
                        nbshares
, action, counter_action,
                        port
=7496):
       
self.client_id = 1
        self.order_ids = [-1]
       
self.qty = nbshares
       
self.nbshares = nbshares
       
self.symbol_id, self.symbol = 0, symbol
       
self.port = port
       
self.tws_conn = None
        self.bid_price, self.ask_price = 0, 0
        self.is_position_opened = False
        self.position = 0
        self.account_code = None
        self.unrealized_pnl, self.realized_pnl = 0, 0
        self.secType, self.exchange, self.primary_exchange, self.currency = secType, exchange, primary_exchange, currency
       
self.limit, self.action, self.counter_action = 0, action, counter_action

   
def error_handler(self, msg):
       
if msg.typeName == "error" and msg.id != -1:
           
print "Server Error:", msg

   
def server_handler(self, msg):
       
if msg.typeName == "nextValidId":
           
self.order_id = msg.orderId
       
elif msg.typeName == "managedAccounts":
           
self.account_code = msg.accountsList
       
elif msg.typeName == "updatePortfolio" \
               
and msg.contract.m_symbol == self.symbol:
           
self.unrealized_pnl = msg.unrealizedPNL
           
self.realized_pnl = msg.realizedPNL
           
self.position = msg.position
       
elif msg.typeName == "error" and msg.id != -1:
           
return

    def next_order_id(self):
       
return self.order_ids[-1]

   
def save_order_id(self,msg):
       
if self.order_ids[-1] < msg.orderId:
           
self.order_ids.append(msg.orderId)
           
print "self.order_ids = '[%s]'" % ', '.join(map(str, self.order_ids))
       
elif not self.order_ids[-1] < msg.orderId:
           
self.tws_conn.reqIds(1)


   
def tick_event(self, msg):
       
if msg.field == 1:
           
self.bid_price = msg.price
       
elif msg.field == 2:
           
self.ask_price = msg.price

       
print ("%s - self.ask_price '%s', self.bid_price '%s', " % (dt.datetime.now(), self.ask_price, self.bid_price) )

       
self.perform_trade_logic()

   
def perform_trade_logic(self):
       
if (self.is_position_opened == False and self.next_order_id() > -1):
           
self.limit=self.bid_price
           
print("dans trade logic avec self.bid_price = '%s'" % self.limit)
           
# create parent order(entry)
            CONTRACT = self.create_contract(self.symbol, self.secType, self.exchange, self.primary_exchange, self.currency)
            ORDER
= self.create_bracketorder(self.action, abs(int(self.nbshares)), self.limit+150, transmit=False)
           
self.tws_conn.placeOrder(self.next_order_id(), CONTRACT, ORDER)
           
print("2/Bracket order - parent orderId = '%s'" % self.next_order_id())


           
# create a profit take order of some kind
            ORDER = self.create_bracketorder(self.counter_action, abs(int(self.nbshares)), self.limit, profit_price=self.limit+300, parentId=self.next_order_id(),
                                   
transmit=False)
           
self.tws_conn.placeOrder(self.next_order_id()+1, CONTRACT, ORDER)


           
# create astop loss order, and THEN transmit(set transmit to true) the entire order by placing this last child order(note inTWS it looks like a tree with parent order and two sub orders inside)
            ORDER = self.create_bracketorder(self.counter_action, abs(int(self.nbshares)), self.limit, stop_price=self.limit, parentId=self.next_order_id(),
                                   
transmit=True)
           
self.tws_conn.placeOrder(self.next_order_id()+2, CONTRACT, ORDER)

           
self.is_position_opened = True

        elif self.is_position_opened:
           
self.monitor_position()

   
def monitor_position(self):
       
print 'Position:%s UPnL:%s RPnL:%s' % (self.position,
                                               
self.unrealized_pnl,
                                               
self.realized_pnl)

   
def create_contract(self, symbol, sec_type, exch, prim_exch, curr):
        contract
= Contract()
        contract
.m_symbol = symbol
        contract
.m_secType = sec_type
        contract
.m_exchange = exch
        contract
.m_primaryExch = prim_exch
        contract
.m_currency = curr
       
return contract

   
def create_order(self, order_type, quantity, action):
        order
= Order()
        order
.m_orderType = order_type
        order
.m_totalQuantity = quantity
        order
.m_action = action
       
return order

   
def create_bracketorder(self, action, qty, limit=None, profit_price=None, stop_price=None,

                                transmit
=True, parentId=None):
       
# https://www.interactivebrokers.com/en/software/api/apiguide/tables/supported_order_types.htm
        # https://www.interactivebrokers.com/en/software/api/apiguide/java/order.htm
        order = Order()

       
# is child order?
        if parentId is not None:
            order
.m_parentId = parentId

        order
.m_action = action
        order
.m_totalQuantity =
 qty

       
if profit_price is not None:

           
# This will set up out profit take
            order.m_orderType = 'LMT'
            if action == 'BUY':

               
# Precise the LMT price to close profit
                order.m_lmtPrice = profit_price
           
elif action == 'SELL':
                order
.m_lmtPrice = profit_price

           
print("4/Bracket order - stop profit price = '%s'" % order.m_lmtPrice)

       
elif stop_price is not None:

           
# This will set up out trailing stop
            order.m_orderType = 'Stop'
            if action == 'BUY':
               
# Precise the Stop Loss price
                order.m_auxPrice = stop_price
           
elif action == 'SELL':
                order
.m_auxPrice = stop_price

           
print("3/Bracket order - stop loss price = '%s'" % order.m_auxPrice)


       
elif limit is not None:
           
# A simple limit order
            order.m_orderType = 'STP'
            if action == 'BUY':
               
# Precise the STP price to invest
                order.m_auxPrice = limit
           
elif action == 'SELL':
                order
.m_auxPrice = limit

           
print("1/Bracket order - invest price  = '%s'" % order.m_auxPrice)


       
else:
           
# A simple market order
            order.m_orderType = 'MKT'

        # Important that we only send the order when all children are formed.
        order.m_transmit = transmit

       
return
order

   
def request_market_data(self, symbol_id, symbol):
        contract
= self.create_contract(symbol,
                                        secType
,
                                        exchange
,
                                        primary_exchange
,
                                        currency
)
       
self.tws_conn.reqMktData(symbol_id, contract, '', False)
        time
.sleep(1)

   
def cancel_market_data(self, symbol):
       
self.tws_conn.cancelMktData(symbol)
        time
.sleep(1)

   
def request_account_updates(self, account_code):
       
self.tws_conn.reqAccountUpdates(True, account_code)

   
def connect_to_tws(self):
       
self.tws_conn = Connection.create(port=self.port,
                                         
clientId=self.client_id)
       
self.tws_conn.connect()

   
def disconnect_from_tws(self):
       
if self.tws_conn is not None:
           
self.tws_conn.disconnect()

   
def register_callback_functions(self):
       
# Assign server messages handling function.
        self.tws_conn.registerAll(self.server_handler)

       
# Assign error handling function.
        self.tws_conn.register(self.error_handler, 'Error')

       
# Handle Order ID sent by Server
        self.tws_conn.register(self.save_order_id, 'NextValidId')

       
# Register market data events.
        self.tws_conn.register(self.tick_event,
                               message
.tickPrice,
                               message
.tickSize)

   
def start(self):
       
try:
           
self.connect_to_tws()
           
self.tws_conn.reqIds(1)
           
self.register_callback_functions()
           
self.request_market_data(self.symbol_id, self.symbol)
           
self.request_account_updates(self.account_code)

           
while True:
                time
.sleep(1)

       
except Exception, e:
           
print "Error:", e
           
self.cancel_market_data(self.symbol)

       
finally:
           
print "disconnected"
            self.disconnect_from_tws()



if __name__ == "__main__":
    symbol
= "IBDE30"
    secType = 'CFD'
    exchange = 'SMART'
    primary_exchange = 'SMART'
    currency = 'EUR'
    nbshares = 1
    action = 'BUY'
    counter_action = 'SELL'

    system = System(symbol, secType, exchange, primary_exchange, currency,
                        nbshares
, action, counter_action
                       
)
    system
.start()




Propa Spaz

unread,
May 26, 2020, 2:24:58 PM5/26/20
to IbPy Discuss
Hi Remi,

Thanks for the code here.

Was just wondering if you perhaps had an updated version of this code or perhaps some examples of using this code for placing a bracket order on a stock with multiple profit targets rather than just the one profit target, i.e. scale out of a trade?

For example, how would I call/use this code if I wanted to, say: 

go Long and BUY 50 shares of Tesla $TSLA 
for a Limit price 5 cents below the current ASK price and 
place 3 profit targets at 2%, 3% & 4% (respectively) above the entry price
taking 50% off the current position size when the 1st profit target is hit,
taking 35% off the remaining current position size when the 2nd profit target is hit,
taking 25% off the remaining current position size when the 3rd profit target is hit.


Many thanks.

Derek Tishler

unread,
Jun 27, 2020, 11:33:36 AM6/27/20
to IbPy Discuss
You may have luck using this guide to switch over to the official IB python api if you desire, or to better understand how to update Remi's code to use with your strategies/needs:
https://algotrading101.com/learn/interactive-brokers-python-api-native-guide/

Specifically the section:
https://algotrading101.com/learn/interactive-brokers-python-api-native-guide/#implement-stop-loss-take-profit

promotergeneral

unread,
Jun 27, 2020, 11:38:04 AM6/27/20
to IbPy Discuss
Thanks for your response.

Much appreciated.



Sent from BlueMail
--
You received this message because you are subscribed to the Google Groups "IbPy Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ibpy-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ibpy-discuss/208767d0-9044-4d42-a512-6a11df75952fn%40googlegroups.com.

ELIAS ABSAWI

unread,
Aug 20, 2020, 1:54:01 PM8/20/20
to IbPy Discuss
Greetings everyone, hope you are doing great.

I'm developing an IbPy trading algorithm and I would like to have a percentage based bracket order (in this case take profit).

If I'm not mistaken, this is the official TWS API documentation where they show bracket orders built on limit orders, so feel free to check it out.  
But I was looking for something else...

It will be very appreciated if you guys could help me build a bracket order based on percentage changes.

For example: Take profit at +75% from buy price

Best Regards,
Elias.


Reply all
Reply to author
Forward
0 new messages