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:
- read the NLV each minute … checked
- get the current price of each position minute by minute … checked
- change orders like the ones of stop and entry … checked
- close positions by market order … eh, just use
MarketOrder()
in the opposite direction of the entry (SELL
orBUY
) - know how many positions are open … use
len(pos)
afterpos = ib.positions()
- 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!
11 Comments
Alessandro
(9. March 2020 - 00:49)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!
Alexander
(15. March 2020 - 10:16)Thanks a lot, Alessandro!
Alessandro
(15. March 2020 - 23:58)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…
Alexander
(22. March 2020 - 13:45)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
.Alessandro
(17. March 2020 - 18:15)This article improved drastically (and just in a few days) my daily approach to the TWS!
Thank you!!!
Alessandro
(30. April 2020 - 15:24)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….
Alexander
(3. May 2020 - 15:01)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 oftime.sleep()
.Alessandro
(9. June 2020 - 16:40)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….
Alexander
(10. June 2020 - 13:05)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.
MANI
(21. April 2021 - 15:33)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?
Alexander
(22. April 2021 - 12:15)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.
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 withib.positions()
andib.fills()
.If there’s anything open, just ask again!