How to code all about orders with Interactive Brokers

In this article you’ll find how to get your positions, set, modify and cancel orders and get your account value and current unrealized profits by Python Code for Interactive Brokers (see below under Final Words what tasks are discussed in this article).

And yes, I found a simple library for all that, named ib_insync and created by Ewald de Wit!

Connect to Interactive Brokers

At first you have to install the library and the code start by importing the libraries and connecting to the broker:

from ib_insync import *
from random import choice

ib = IB()
ib.connect('127.0.0.1', 7496, clientId=1)

I imported choice to pick some random elements from the list. Of course, you only need it for our example.
And you have to check if the port is the same set in your API settings within TWS or Gateway.

Get all your running positions

Now we can read all positions from the server:

pos = ib.positions()

And here we pick one random position and show some details:

p = choice(pos)

# the account to which the position belongs:
print(p.account)
# the ticker symbol:
print(p.contract.symbol)
# the amount of shares (negative when sold):
print(p.position)
# the average price (including the commissions):
print(p.avgCost)

Get the current account value

Also, we can request the NetLiquidation value (NLV, current value of the whole account) and the unrealized profit (or loss):

avs = ib.accountValues()

for i in range(len(avs)):
    if avs[i].tag == "NetLiquidation":
        print(avs[i])
    elif avs[i].tag == "UnrealizedPnL" and avs[i].currency == "BASE":
        print(avs[i])

If you have several account under one login then it will show the data for both account.

Create a contract and get the current price

contract = Stock('JPM', 'SMART', 'USD')
print(contract)

bars = ib.reqHistoricalData(
        contract,
        endDateTime='',
        durationStr='1 D',
        barSizeSetting='1 min',
        whatToShow='MIDPOINT',
        useRTH=False,
        formatDate=1)
df = util.df(bars)

print("current price:", df.close.iloc[-1])

Easy, isn’t it? One of my first articles was about getting historical data with the original IB API and it was so complicated. And here it is: Simple, fast and I hope it’s easy to understand.

First, we define the contract for JPM and then we request some sample data for the 1 minute candles of the last day. But we only need the last close which is solved by .iloc[-1]. I set useRTH=False, so it shows also the last data of the after hours at weekends.

Set, modify and cancel orders

To place an order, we have to create an order object and place the order:

order = StopOrder('SELL', 10, 105.0)
print(order)
trade = ib.placeOrder(contract, order)
print(trade)

ib.sleep(1)
print(trade.log)

You can check the trade.log to get more informations, for example if the order is already submitted, …

Pay attention on using ib.sleep() instead of time.sleep()!

Now we wait 4 seconds before changing the stop price from 105.0 (as set above) to 104.9. We have to change the order element and then place the order again. It is not sent twice, it’s just to change the order:

ib.sleep(4)
order.auxPrice = 104.9
trade = ib.placeOrder(contract, order)
print(trade)

And finally, we can cancel the order:

ib.sleep(5)
print(ib.cancelOrder(order))

print(trade.log)

The sleep commands are only to have the possibility to check the whole process by watching the JPM chart in your TWS!

Final words

If you do need anything else or want to know more about one of the above steps then just comment below!

The reason for this article was a request of a friend of mine to solve the following:

  1. read the NLV each minute … checked
  2. get the current price of each position minute by minute … checked
  3. change orders like the ones of stop and entry … checked
  4. close positions by market order … eh, just use MarketOrder() in the opposite direction of the entry (SELL or BUY)
  5. know how many positions are open … use len(pos) after pos = ib.positions()
  6. know the average entry price of each position to calculate break even … checked

Here it is!
And I hope many of you could profit from this article about how to code all about orders with Interactive Brokers. It’s simple and everyone can code some little tools to save time with the everyday trading tasks.

Good profits!

Alexander

Alexander bought his first stock in October 2009 without knowing about the luck for this point of time. In 2016 he started to trade, since 2017 he notes down watchlists and statistics every day and because he knows how to code since he was a child, he uses Python, PHP, HTML5 and JS for making the daily to-dos easier. Because many of his friends wanted him not to stop writing about the markets he started this blog to share his ideas and tools.

11 Comments

  • Dear Alexander,
    after months spent, trying to decode the extremely tedious and complicated IB API documentation, and giving up hundreds of times, I finally managed to place an ORDER from my python app, change it, retrieve my NLV and other extremely exciting things. This took almost 3 minutes, thanks to your article! I can only say THANK YOU thousand times!

  • Dear Alexander,
    while coding, I was blocked out by the warning message for CSCO and MSFT
    “The contract description specified for MSFT is ambiguous”

    This message is mostly triggered for stock symbols, such as MSFT and CSCO, that are obviously listed on multiple primary exchanges.

    In your example above:
    contract = Stock(‘JPM’, ‘SMART’, ‘USD’)

    Just to be sure, I would change it to:
    contract = Stock(‘JPM’, ‘SMART’, ‘USD’, primaryExchange=’ISLAND’)

    As you already wrote in one of your previous article, we simply could write “ISLAND” when referring to US Stocks (instead of NASDAQ or NYSE).

    I think the same approach could be adopted here: I tested and it worked…however I’m not 100% sure, if it’s the academic way of doing it…

    • If you need one special contract, I would prefer to check the exact primary exchange in TWS.
      But if you want to get the data of many US stocks, just use ISLAND.

  • This article improved drastically (and just in a few days) my daily approach to the TWS!
    Thank you!!!

  • Dear Alexander…

    “Pay attention on using ib.sleep() instead of time.sleep()!”…

    I’ve missed this detail of your Article, but it is actually very important…
    could you explain why it actually does make a difference? I can’t really fully understand….

    • The function time.sleep() just stops the current commands in a row for a defined time. But the IB API uses threads and several threads are running at the same time. So, ib.sleep() pauses everything, so that requests/threads can finish their work until new commands follow.
      As soon as you’re using the IB API I would recommend to always use ib.sleep() instead of time.sleep().

  • Dear Alexander,

    About modifying existing orders: I think it’s worth sharing what literally took me half a day to figure out…

    If you wish to modify an existing order (like a pending StopLoss or a TargetPrice Order) which was originally placed through your application, BUT during a different TWS session (basically with a different ClientID than the current one), you should first connect again with the same ClientID you used when you placed that order.

    In other words: only the same API clientId can modify its order.

    If that order was placed manually from the TWS, then your application must first connect with ClientID = 0, then you must call the reqOpenOrders() to bind that order, and ONLY THEN you can modify that order from your application…

    Maybe that’s an interesting information for your readers, who are trying to accomplish the same task….

    • Sure, thanks for this additional experience!
      I am using an individual ClientId for every program, so I can run each of them beside another without getting ugly error messages for the same ClientId.
      That’s nice because I can run 3-4 live pyplot-charts and check my portfolio from time to time while only run the Gateway and not the TWS requiring a lot more memory.

  • Thank you so much for this, I can’t even put into words how much this has helped me progress with my project!

    I’m currently trying to get the status of orders that I placed in the last week but I’m not entirely sure how to do so. I simply want to find out if they closed in profit or out of profit.

    Would you have an idea how I could do that?

    • Thank you so much for this, I can’t even put into words how much this has helped me progress with my project!

      That makes me happy. Sadly, just a few people on earth seem to code their trading tools themselves. Therefore I stopped this project for a while. I would like to add more helpful articles and to create a little community around. But the statistics are against it. But if you want an article to a theme or need help, feel free to ask in the comments every time.

      I’m currently trying to get the status of orders that I placed in the last week but I’m not entirely sure how to do so. I simply want to find out if they closed in profit or out of profit.

      The API of IB does only show what the TWS shows. And you can get only the last 7 days of filled orders in both.
      To get the fills you can use trade.log to get the log data of a current trade or you can play with ib.positions() and ib.fills().

      If there’s anything open, just ask again!

Leave a Reply

Your email address will not be published. Required fields are marked *