Following your TWS API Python based client development, next things to look into is equity data: order data retrieval, positions and completed orders. Arguably, this is the most important in all of the trading steps. We will look into the basics of what needs to be done to request such data in the following sections.
Is connection established?
Assuming the connection is already established between your API client and TWS/Gateway.
If not, you can test with the following code:
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
class IBapi(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
app = IBapi()
app.connect('127.0.0.1', 7496, 0)
app.run()
If more attempts to reconnect are required, use the following code:
import time
time.sleep(2)
app.disconnect()
The first part of the code snippet will establish the connection. The second part sends retries, if for example, the port was not ready. The sleep function is also required, as we are using asynchronous API, so the program won’t wait for response and may continue working.
Output will have several Market data farm connection statuses.
Requesting Contract Information
This step is actually required to actually know what equity do you want to work with.
All of the contract information you need for this step can be acquired via TWS.
In watchlist, enter any stock you are interested in, for example AAPL. This will offer all of the available contracts having similar or exact names available in TWS.
If you select Stock@SMART, the Apple Stock at SMART exchange will populate the watchlist. Please note, that SMART exchange value is IBKR’s own system, that takes the best prices available from multiple traded exchanges, like NASDAQ, NYSE, etc.
Right clicking the instrument -> selecting Financial Information -> clicking on Description will open a new window with all valid current contract information. We can use this data to populate the contract in our Python client.
The following code snippet points at AAPL@SMART contract:
#Create contract object
apple_contract = Contract()
apple_contract.symbol = 'AAPL'
apple_contract.secType = 'STK'
apple_contract.exchange = 'SMART'
apple_contract.currency = 'USD'
Now we can use this contract to start actually receiving the market data.
Streaming market data
One of the requirements to start streaming any instrument’s live data is having the correct market data subscription. Valid subscriptions can be checked in TWS with your live account by right clicking the instrument in the watchlist -> Launch Market Data Subscription Manager.
But, if you are on your paper account with no subscriptions and no intention to subscribe to any of the required packages, you can still use Delayed data. It is still live data, although delayed by 10-15-20 minutes depending on the exchange.
To keep the text short, only the new lines would be added on top of the connection code snippet.
Before you request any market data, first you may need to specify if it’s live or delayed data you are after.
public virtual void marketDataType(int reqId, int marketDataType)
{
Console.WriteLine("MarketDataType. "+reqId+", Type: "+marketDataType+"\n");
}
The Market data type has 4 Ids:
1 – Live
2 – Frozen
3 – Delayed
4 – Delayed Frozen
For more information about them please look into https://interactivebrokers.github.io/tws-api/market_data_type.html article.
#Request Market Data
app.reqMktData(1, apple_contract, '236, 456', False, False, [])
The composition of this line is in left to right order:
tickerId | the request's identifier |
contract | the Contract for which the data is being requested |
genericTickList | Available list here: https://interactivebrokers.github.io/tws-api/tick_types.html |
snapshot | for users with corresponding real time market data subscriptions. A true value will return a one-time snapshot, while a false value will provide streaming data. |
Regulatory | snapshot for US stocks requests NBBO snapshots for users which have “US Securities Snapshot Bundle” subscription but not corresponding Network A, B, or C subscription necessary for streaming * market data. One-time snapshot of current market price that will incur a fee of 1 cent to the account per snapshot. |
The market data is then delivered, depending on the tick type selected via tickPrice, tickSize, tickString or tickGeneric.
TickPrice:
public virtual void tickPrice(int tickerId, int field, double price, TickAttrib attribs)
{
Console.WriteLine("Tick Price. Ticker Id:" + tickerId + ", Field: " + field + ", Price: " + Util.DoubleMaxString(price) + ", CanAutoExecute: " + attribs.CanAutoExecute +
", PastLimit: " + attribs.PastLimit + ", PreOpen: " + attribs.PreOpen);
}
TickSize:
public virtual void tickSize(int tickerId, int field, decimal size)
{
Console.WriteLine("Tick Size. Ticker Id:" + tickerId + ", Field: " + field + ", Size: " + Util.DecimalMaxString(size));
}
TickGeneric:
public virtual void tickGeneric(int tickerId, int field, double value)
{
Console.WriteLine("Tick Generic. Ticker Id:" + tickerId + ", Field: " + field + ", Value: " + Util.DoubleMaxString(value));
}
tickString:
public virtual void tickString(int tickerId, int tickType, string value)
{
Console.WriteLine("Tick string. Ticker Id:" + tickerId + ", Type: " + tickType + ", Value: " + value);
}
The above functions return any given tick associated with the relative function. Without implementing above methods, the data will not be delivered.
Historical Data
Obtaining historical data is done in similar fashion as requesting streaming market data.
We will use Forex EUR.USD example to retrieve historical data. Because historical data is only available to market data subscription holders. Forex is an exception and it is available for free.
eurusd_contract = Contract()
eurusd_contract.symbol = 'EUR'
eurusd_contract.secType = 'CASH'
eurusd_contract.exchange = 'IDEALPRO'
eurusd_contract.currency = 'USD'
#Request historical candles
app.reqHistoricalData(1, eurusd_contract, '', '1 W', '1 day', 'BID', 0, 1, False, [])
The above function requests daily bars for the last week. Note how end data is not defined, thus this function will return last week of available daily bars.
Below is the description of those properties:
tickerId, A unique identifier which will serve to identify the incoming data.
contract, The IBApi.Contract you are interested in.
endDateTime, The request's end date and time (the empty string indicates current present moment).
durationString, The amount of time (or Valid Duration String units) to go back from the request's given end date and time.
barSizeSetting, The data's granularity or Valid Bar Sizes
whatToShow, The type of data to retrieve. See Historical Data Types
useRTH, Whether (1) or not (0) to retrieve data generated only within Regular Trading Hours (RTH)
formatDate, The format in which the incoming bars' date should be presented. Note that for day bars, only yyyyMMdd format is available.
keepUpToDate, Whether a subscription is made to return updates of unfinished real time bars as they are available (True), or all data is returned on a one-time basis (False). Available starting with API v973.03+ and TWS v965+. If True, and endDateTime cannot be specified.
Historical data then is returned via historicalData function:
public virtual void historicalData(int reqId, Bar bar)
{
Console.WriteLine("HistoricalData. " + reqId + " - Time: " + bar.Time + ", Open: " + Util.DoubleMaxString(bar.Open) + ", High: " + Util.DoubleMaxString(bar.High) +
", Low: " + Util.DoubleMaxString(bar.Low) + ", Close: " + Util.DoubleMaxString(bar.Close) + ", Volume: " + Util.DecimalMaxString(bar.Volume) +
", Count: " + Util.IntMaxString(bar.Count) + ", WAP: " + Util.DecimalMaxString(bar.WAP));
}
Please note, that when setting keepUpToData to true, you would need to implement historicalDataUpdate function. This is working in similar manner as reqMktData, that it sends all of the new data continuously.
public void historicalDataUpdate(int reqId, Bar bar)
{
Console.WriteLine("HistoricalDataUpdate. " + reqId + " - Time: " + bar.Time + ", Open: " + Util.DoubleMaxString(bar.Open) + ", High: " + Util.DoubleMaxString(bar.High) +
", Low: " + Util.DoubleMaxString(bar.Low) + ", Close: " + Util.DoubleMaxString(bar.Close) + ", Volume: " + Util.DecimalMaxString(bar.Volume) +
", Count: " + Util.IntMaxString(bar.Count) + ", WAP: " + Util.DecimalMaxString(bar.WAP));
}
If you have no keepUpToData specified, the historicalDataEnd must be called.
public virtual void historicalDataEnd(int reqId, string startDate, string endDate)
{
Console.WriteLine("HistoricalDataEnd - "+reqId+" from "+startDate+" to "+endDate);
}
Disclosure: Interactive Brokers
The analysis in this material is provided for information only and is not and should not be construed as an offer to sell or the solicitation of an offer to buy any security. To the extent that this material discusses general market activity, industry or sector trends or other broad-based economic or political conditions, it should not be construed as research or investment advice. To the extent that it includes references to specific securities, commodities, currencies, or other instruments, those references do not constitute a recommendation by IBKR to buy, sell or hold such investments. This material does not and is not intended to take into account the particular financial conditions, investment objectives or requirements of individual customers. Before acting on this material, you should consider whether it is suitable for your particular circumstances and, as necessary, seek professional advice.
The views and opinions expressed herein are those of the author and do not necessarily reflect the views of Interactive Brokers, its affiliates, or its employees.
Disclosure: API Examples Discussed
Throughout the lesson, please keep in mind that the examples discussed are purely for technical demonstration purposes, and do not constitute trading advice. Also, it is important to remember that placing trades in a paper account is recommended before any live trading.
Disclosure: Order Types / TWS
The order types available through Interactive Brokers LLC's Trader Workstation are designed to help you limit your loss and/or lock in a profit. Market conditions and other factors may affect execution. In general, orders guarantee a fill or guarantee a price, but not both. In extreme market conditions, an order may either be executed at a different price than anticipated or may not be filled in the marketplace.
Disclosure: Forex
There is a substantial risk of loss in foreign exchange trading. The settlement date of foreign exchange trades can vary due to time zone differences and bank holidays. When trading across foreign exchange markets, this may necessitate borrowing funds to settle foreign exchange trades. The interest rate on borrowed funds must be considered when computing the cost of trades across multiple markets.