4 Querying account and portfolio data
4.1 Account information
IB user accounts have numerous internal properties/parameters, ranging from the account currency to cash balance, margin information etc. You can retrieve this information in Matlab using the following simple command:
>> data = IBMatlab('action','account_data') % or: IBMatlab('account')
data =
AccountCode: 'DU12345'
accountName: 'DU12345'
AccountReady: 'true'
AccountType: 'INDIVIDUAL'
AccruedCash: [1x9 struct]
AccruedCash_C: [1x1 struct]
AccruedCash_S: [1x1 struct]
AccruedDividend: [1x1 struct]
AccruedDividend_C: [1x1 struct]
AccruedDividend_S: [1x1 struct]
AvailableFunds: [1x1 struct]
(and so on ... – dozens of different account parameters)
As can be seen, the returned data object is a simple Matlab struct, whose fields match the IB account properties. To access a specific field use standard Matlab dot notation:
>> myDividends = data.AccruedDividend
myDividends =
value: 12345.67
currency: 'AUD'
When the account has information in various currencies, the corresponding data field is an array of Matlab structs.22 For example:
>> data.AccruedCash(1) % A Matlab struct of a specific currency
ans =
value: 1040
currency: 'AUD'
>> data.AccruedCash(2) % A Matlab struct of a specific currency
ans =
value: 1039
currency: 'BASE'
>> [data.AccruedCash.value] % A numeric array of all currency values
ans =
1040 1039 0 0 0 -7 0 0 0
>> {data.AccruedCash.currency} % A corresponding Matlab cell array
ans =
'AUD' 'BASE' 'CAD' 'CHF' 'DKK' 'NOK' 'NZD' 'SEK' 'USD'
Some account data fields have several variants, for example, AccruedCash, AccruedCash_C and AccruedCash_S. Until you trade a commodity, AccruedCash_C=0 and AccruedCash_S=AccruedCash. After trading a commodity, AccruedCash_C holds the value for commodities, AccruedCash_S for securities, and AccruedCash for the total. Several other fields also have these _S and _C variants.
If your TWS account is linked to multiple IB accounts (as is common for financial advisors), then you should specify the AccountName input parameter, so that IB would know which IB account to access:23
>> data = IBMatlab('action','account', 'AccountName','DU12345');
To get data for all accounts in a consolidated manner, set AccountName to 'All':24
>> data = IBMatlab('action','account', 'AccountName','All')
data =
DF12344: [1x1 struct]
DU12345: [1x1 struct]
DU12346: [1x1 struct]
SummaryData: [1x1 struct]
ManagedAccounts: {'DF12344' 'DU12345' 'DU12346'}
where the returned struct fields contain the account data for each specific account, as shown at the beginning of this section, plus a SummaryData struct field for all accounts. The final field, ManagedAccounts, is a cell array of all the managed account names.
Note: IB has changed the behavior for AccountName='All' in 2015. The description above is accurate as of November 2015, but with your IB accounts you might still see the previous behavior, receiving a single unified data struct, as for a single account.
The AccountName parameter is only used when managing multiple accounts. If you manage just a single account, then the AccountName parameter is ignored - you will always receive the detailed data struct for the account, as shown at the beginning of this section, even if you specify an invalid AccountName, or omit it altogether.
In some cases, IB might return empty data in response to account requests. Two workarounds have been found for this, although they might not cover all cases. The workarounds are to simply re-request the information, and to force a programmatic reconnection to IB (more on connection issue in §13 below):
data = IBMatlab('action','account');
if isempty(data) % empty data – try to re-request the same data
data = IBMatlab('action','account');
end
if isempty(data) % still empty data – try to disconnect/reconnect
IBMatlab('disconnect'); % disconnect from IB
pause(1); % let IB cool down a bit
data = IBMatlab('action','account'); % will automatically reconnect
end
4.2 Portfolio data
To retrieve an IB account’s portfolio (list of held securities), use 'portfolio' action:
>> data = IBMatlab('action','portfolio')
data =
1x12 struct array with fields:
symbol
localSymbol
exchange
secType
currency
right
expiry
strike
position
marketValue
marketPrice
averageCost
realizedPnL
unrealizedPnL
contract
This returns a Matlab array of structs, where each struct element in the array represents a different security held in the IB account. For example:
>> data(2)
ans =
symbol: 'AMZN'
localSymbol: 'AMZN'
exchange: 'NASDAQ'
secType: 'STK'
currency: 'USD'
right: '0'
expiry: ''
strike: 0
position: 920
marketValue: 171580
marketPrice: 186.5
averageCost: 169.03183335
realizedPnL: 7513.78
unrealizedPnL: 16070.71
contract: [1x1 struct]
The marketPrice value is reflected in TWS’s Quote Monitor as the “Mark Price”. It is defined as the last price, clamped to ask (if ask<last) or bid (if bid>last) as needed.25
It is highly advisable for robustness to compare the account’s StockMarketValue26 to the sum of non-cash portfolio marketValues. Be careful to sum only non-cash securities (i.e., ~strcmpi(data.secType,'cash')). Shorted securities will appear with a negative marketValue in the portfolio struct array, while long securities will have a positive value. The sum of these values, which should be equal to the account’s StockMarketValue, may be positive or negative, indicating whether the overall portfolio is long or short. If you are only interested in the total monetary value of the security positions (i.e., their absolute marketValues), then the sum in this case should equal the account’s GrossPositionValue. Note that there may be small differences between the portfolio marketValue sums and the account StockMarketValue or GrossPositionValue, due to market changes that occurred between the time that the account data was collected, and the time that the portfolio data was requested. If you run these requests immediately one after another, then in the vast majority of the cases the data will match exactly.
In the returned data struct, the contract field is itself a struct, which contains basic information about the security.27 The only important piece of information that is not already included in the main struct is the contract Id stored in data.contract.conId:
>> data(2).contract
ans =
conId: 3691937
symbol: 'AMZN'
secType: 'STK'
currency: 'USD'
primaryExch: 'NASDAQ'
...
As with account data requests,, if multiple IB accounts are connected to our IB login, then we need to ensure that we request data for the correct account. Many frustrations can be avoided by specifically stating the AccountName parameter whenever we use IBMatlab in a multi-account environment. If you are unsure of the account name, set AccountName to 'All' (read the related discussion at the end of §4.1):
>> data = IBMatlab('action','portfolio', 'AccountName','All')
data =
DF12344: [0x0 struct]
DU12345: [1x7 struct]
DU12346: [1x3 struct]
As with account data requests, IB might return empty data in response to portfolio requests. Two workarounds have been found for this, although they might not cover all cases.28 The workarounds are to simply re-request the information, and to force a programmatic reconnection to IB (more on the connection issue in §13 below):
data = IBMatlab('action','portfolio');
if isempty(data) % empty data – try to re-request the same data
data = IBMatlab('action','portfolio');
end
if isempty(data) % still empty data – try to disconnect/reconnect
IBMatlab('disconnect'); % disconnect from IB
pause(1); % let IB cool down a bit
data = IBMatlab('action','portfolio'); % will automatically reconnect
end
In some cases, even with the retry workaround above, IB still returns empty portfolio data. A more reliable (and much faster) mechanism for retrieving portfolio data is to limit the request only to the portfolio positions, by setting the Type parameter to 'positions'. IB will return the data much faster and more reliably, except for the marketValue, marketPrice, and averageCost fields, which are returned empty:
>> data = IBMatlab('action','portfolio', 'type','positions');
>> data(5)
ans =
symbol: 'ZL'
localSymbol: 'ZL DEC 15'
exchange: ''
secType: 'FUT'
currency: 'USD'
right: ''
expiry: '20151214'
strike: 0
position: -1
marketValue: []
marketPrice: []
averageCost: []
realizedPnL: []
unrealizedPnL: []
contract: [1x1 struct]
In this example, we have a short position of -1 for the ZL 12/2015 future, and no market information is included in the returned data.
Here is a short Matlab code example showing how to retrieve the position (number of portfolio shares) of a specific security ('GOOG' in this example):
portfolioData = IBMatlab('action','portfolio', 'type','positions');
symbols = {portfolioData.localSymbol};
idx = strcmpi('GOOG', symbols);
position = portfolioData(idx).position;
if isempty(position)
position = 0;
end
The position information is often sufficient. For example, an automated trading algorithm may need to determine if a position is currently open, and to compute the trade-order quantity required to open/reverse/close it. In such cases, limiting the portfolio request to position-only data is advisable. If you also need market data, you can use a standard portfolio request, or to retrieve the market data in a separate query.
Finally, note that IB will only send Forex (cash) position in the portfolio data if the relevant option is selected in the API settings:
22 IB-Matlab versions prior to Oct 20, 2014 did not make a distinction between various currencies, so the reported value might be misleading if your account holds values in various currencies.
23 If you don’t specify the AccountName, you will get stale or empty account data.
24 TWS/IB-Gateway API setting "Master API Client ID" may need to be empty (even if correct) for this to work (see installation step 5c in §2 above).
26 As reported by the IBMatlab('action','account') command – see §4.1 for details
27 Use §5.4 below to retrieve detailed contract information; the fields are explained here: http://interactivebrokers.com/php/whiteLabel/Interoperability/Socket_Client_Java/java_properties.htm
28 For example, the IB API has a known limitation that it does not return the portfolio position if the clearing house is not IB