Interactive brokers now have a native python API. An updated version of this post which uses that API is here: http://qoppac.blogspot.co.uk/2017/03/placing-orders-in-native-python-ib-api.html
Having got some prices and submitted some orders we want to know whether we made any money or not. Although the code is rather trivial, interpreting the results requires some understanding.
So once again you need to get the code from the following repo.
The example code to run is in test5_IB.py and wrapper_v5.py. This will give your results with live or simulated Gateway / TWS session running (it probably won't produce anything of interest with a demo account but you can still follow the code). Note that IB have recently updated their Gateway software so you might need to re-download.
The output from test5_IB.py should be something like what is in green below.
Expiry is 20140908
([('3KTB', '20140617', 12, 106.0, 1272000000.0, 105842090.65714166, 1894912.11, 0.0, 'DU99', 'KRW'), ('BTP', '20140606', 2, 123.2049942, 246409.99, 121025.33335, 4359.32, 0.0, 'DU99', 'EUR'), ('EMG', '', 1100000, 0.91125, 1002374.99, 0.85376155, 63237.28, 0.0, 'DU99', 'GBP')]
[('AccountCode', 'DU99', '', 'DU99'), ('AccountReady', 'true', '', 'DU99'), ('AccountType', 'INDIVIDUAL', '', 'DU99'),
, ('WarrantValue', '0', 'USD', 'DU99')]
Contract details - again?
Note we reuse the contract details code in http://qoppac.blogspot.co.uk/2014/05/the-placing-of-orders-to-interactive.html
The reason we do this is as before to correctly identify our positions we need the yyyymmdd expiry associated with the contract; although the matching up process isn't done here.
We're going to use a single client function to get both accounting and position data. However both of these are going to be looking at streamed accounting updates. This is returned by two different kinds of wrapper function.
Since writing this blog IB have introduced an API call to get positions directly - so there are less clunky ways of doing this than I show here.
From wrapper_v5.py, class IBclient:
## Turn on the streaming of accounting information
while not finished and not iserror:
if (time.time() - start_time) > MAX_WAIT_SECONDS:
print "Didn't get an end for account update, might be missing stuff"
## Turn off the streaming
## Note portfolio_structure will also be updated
print "Problem getting details"
return (account_value, portfolio_data)
From wrapper_v5.py, class IBWrapper:
if "data_portfoliodata" not in dir(self):
setattr(self, "data_portfoliodata", )
if "data_accountvalue" not in dir(self):
setattr(self, "data_accountvalue", )
setattr(self, "flag_finished_portfolio", False)
def updatePortfolio(self, contract, position, marketPrice, marketValue, averageCost, unrealizedPNL, realizedPNL, accountName):
Add a row to the portfolio structure
portfolio_structure.append((contract.symbol, contract.expiry, position, marketPrice, marketValue, averageCost,
unrealizedPNL, realizedPNL, accountName, contract.currency))
## account value
def updateAccountValue(self, key, value, currency, accountName):
Populates account value dictionary
account_value.append((key, value, currency, accountName))
def accountDownloadEnd(self, accountName):
Finished can look at portfolio_structure and account_value
setattr(self, "flag_finished_portfolio", True)
So once we begin streaming both the portfolio_structure and account_value global variables begin updating. Note that with portfolio_structure we have the same 'gotcha' as before, namely that we can't just drop the contract object into the global variable, as all we will get is a pointer that is meaningless outside of the wrapper method. Instead we need to save specific things of interest like contract.symbol.
Portfolio dataThe output portfolio_data will be a list of tuples (contract.symbol, contract.expiry, position, marketPrice, marketValue, averageCost, unrealizedPNL, realizedPNL, accountName, contract.currency). Note that the value, cost, PNL will be in local currency. You can extract exchange rates from the account_value information - which I discuss below.
Lets take an example:
('BTP', '20140606', 2, 123.2049942, 246409.99, 121025.33335, 4359.32, 0.0, 'DU99', 'EUR')
This is the June 2014 BTP (Italian 10 year bond) which I am long 2 in account DU99 (not my real account number) which is trading at 123.205 Euros per contract. I should use the contract information from above to match this to the yyyymm contracts my system knows about. My two contracts are worth Euro 246,410 because each contract price point is worth 1000 Euros (I can get this information from the contract details call).
I actually bought each of these things for 121,025 Euros each (so 121.025 in price points). This ill conceived lending of a quarter of a million Euros to the most unstable government in the Euro zone has so far earned me Euros 4359.32 (246,410 minus 2 * 121,025; or 2 * [123.205 - 121.025] * 1000).
Note my realized PnL is zero since I obviously haven't sold any of these futures yet (no quick profit taking for account DU99).
Here is the corresponding exchange rate from the account_value output.
[... ("ExchangeRate", 0.815491, "EUR", "DU99"),....
("ExchangeRate", 1.00000, "GBP", "DU99"),... ]
From this we can make out that my base currency is GBP, and 1 Euro is worth 0.815491 GBP. So I can convert my ill gotten gains in monopoly money ECB issued Euros 4359.32 * 0.815491 = £3,555 in real money.
For more information see the online documentation
C++ > Class EWrapper Functions > Account and Portfolio
Note be careful about using comparisions between these portfolio snapshots from different times to calculate your profits. They won't take trades into account very well, and if you have sold something completely or hadn't bought it for the first snapshot the comparision wont' work.
Finally also be very careful about using these snapshots to work out what positions you have. Firstly it is common to get the position coming back repeated times. So you will need to filter out duplicates. Secondly positions may sometimes not appear at all.
I use my own record of trades to find out what my current position should be. I compare this to the IB snapshot throughout the day. If there are any breaks in the reconciliation I temporarily halt trading. Occasionally this is because IB has sent me a fill I haven't picked up, or because the IB position snapshot is missing some contracts.
The account_value output will be a very long list of tuples. Each one consists of (keyname, value, currency, account number). Currency BASE indicates it is the accounts base currency (GBP for me). Here are some of the more interesting account value entries.
- ExchangeRate: This is what we use in the get positions example above.
- FuturesPNL: This is how much we have made trading futures today, by currency. BASE is the total in base currency.
- StockMarketValue: Self explanatory
- NetLiquidation: This is what is my account worth if I close all my positions out (ignoring commissions and bid-ask). Its what I use to ultimately determine the total profit and loss used for rescaling my risk capital.
- CashBalance: Quite self explanatory. Negative means you have borrowed money. BASE is the net of your balances converted into base currency.
When you initially do a futures trade in a non BASE country you will have to borrow money for initial margin. Only if you move into profit beyond this will you have no net borrowing. IB charges you for borrowing money! This is done at LIBOR+spread so is expensive for currencies with higher interest rates (this spread is also why I use IMM's to get direct currency exposure). You can flatten out your exposure by doing a spot FX trade. Personally I try and keep a small positive balance in all currencies, although not excessive as this means I am taking on currency risk. Note you can't trade all possible pairs eg if you find you can't buy AUDGBP then try selling GBPAUD instead. The exception is Korea where you can't hold any speculative currency exposure i.e. not arising from margin requirements in other kinds of trading. All you are allowed to do is flatten your Korean currency position back to zero.
There are many more keywords than shown above. The best advice I have for trying to understand what they all mean is to start with a clean simulated account (a demo account is no good since you are exposed to other peoples random trading, and the account will often be 'empty'). Take a dump of the account value output, then do a trade. Take another dump, then wait for prices to move. By comparing each dump you should be able to see how account value, margin, cash and so on interact. This is quite time consuming but definitely worth it for an insight into how the IB accounts operate for the kind of instruments you want to trade.
I haven't covered the full gamut of what you can get from the IB API. There are some newer methods put in since I began using it to get positions and account summary information. There is a much richer variety of price and option data that is available. I haven't looked at fundamental data, option data, scanners and managed accounts because I don't use them. However I hope there is enough meat in this series of examples to get you started using IB with swigibpy, and to avoid wasting time trying to understand some of the weirder behaviour.
This is the final of a series of five posts on constructing a simple interface in python to the IB API using swigiby. The first four posts are:
If you've found this series useful then your next steps might be to learn how to design a systematic trading strategy, and to understand the nuts and bolts of creating a fully automated system.