IBKR_API¶
Supporting Greed Monsters since 2019
IBKR_API Architecture¶
The IBKR_API is NOT some wrapper on top of the existing twsapi python API, but rather a complete redesign of the codebase. The new codebase was written with the following ideas in mind. One, a ‘design by contract’ approach was used, where each portion of the system has clearly defined responsibilities. For the most part these responsibilities are explicitly listed in their respective docstrings. The other governing principle was to keep the code ‘DRY’ and to avoid ‘speculative generality’. The codebase you see is the result of this philosophy.
Directory Structure¶
The table below describes various important directories within this API and their intended purpose
Directory | Description |
---|---|
base | The core application internals. Unless you are developing the API this code this code won’t be called directly |
classes/contracts | Various types of Contract objects such as Stock, Option, Put, Call, etc |
classes/enum | Various Enum and IntEnum classes that hold all legal values for whatever specific parameter they represent |
classes/orders | Objects that represent various types of orders that can be placed such as Limit , Discretionary, etc |
classes/stocks | Dow 30, S&P 500, etc (should/will probably be renamed to indexes…) |
api.py | IBKR_API interface. Use this if you are looking for a simple synchronized interface |
client_application.py | ClientApplication Interface. Use this if you are looking for a standard asynchronous event driven approach |
Interfaces¶
There are three primary interfaces to use. For basic usage the IBKR_API class is your best bet. This class hides the complexity of the underlying asynchronous interface provided by the application Bridge (TWS or the IB Gateway) and gives you a straight forward way to query data.
For those users looking to implement real time algorithmic trading systems the ClientApplication class is the right place to start. This class provides an interface similar to what is provided by the official API, minus the artificial complexity.
RabbitMQ¶
Two exchanges are being used trading desk for messages bound for the trading desk. actor for messages bound for the various actors.
Message Exchanges¶
Routing key: <message_type>.<Actor.code>
+==============+====================+=================================================================+ | Exchange | Queue Message Type | Meaning | +==============+====================+=================================================================+ | trading_desk | bridge | (API) Requests from Actors for the bridge application | +————–+——————–+—————————————————————–+ | trading_desk | multi_client | Responses from prior request | +————–+——————–+—————————————————————–+ | actor | bridge | Request for the MultiClientApplication to deliver to the bridge | +————–+——————–+—————————————————————–+ | actor | multi_client | Request from the MultiClientApplication | +————–+——————–+—————————————————————–+
Quick Start Guide¶
Now that we have ibkr_api installed. Let us do some real work.
Let’s start working with the data¶
Creating Your Application¶
- Create your own application class
- Implement your initialize action
- Read any configuration information
- Connect to your application’s database
- Get the initial valid order id
- Get the initial valid request id (next_valid_id
F.A.Q¶
How do I exit my application?¶
At the end of each event loop iteration. A call is made to your classes act() function. When your application wants to quit out, all you need to do is call the stop() function. This will set the still_running flag to false, and will then exit normally.
Contributing To This Codebase¶
General¶
Thanks for looking into contributing to this codebase. As many open source projects are handled differently, it is best to state some of my thinking in regards to contributions. Firstly, all contributions are welcome in this codebase. If you only feel comfortable making a small change, whether to improve some text or fix a variable name, please do.
Pull Requests¶
To minimize the pain of pull requests, my current plan is as follows on the second and last weekend of the month (US Mountain Time), I will actively look to merge any code that I can. One of my personal pet peeves is submitting a pull request and not getting any feedback. As such I will try my best to reply to pull requests in a timely fashion.
Found a Bug¶
Open up a ticket, and Ill discuss whatever you found. The more detailed you are in what you think the issue is and exact steps for someone to recreate will greatly aid in the debugging process.
IBKR_API Client Quick Start¶
IBKR_API provides an interface that hides the inherent complexity of an event driven asynchronous This page has several snippets for common tasks that you may want to do with this API. All the samples below assume that the code from the Initial Setup block have already been executed, otherwise the code shown should be self contained.
Initial Setup¶
from ibkr_api.api import IBKR_API
from ibkr_api.classes.contracts.contract import Contract
from ibkr_api.classes.stocks.dow30 import Dow30
from historical_data_types import HistoricalDataType as HDT
host = "127.0.0.1"
port =
ibkr = IBKR_API(host, port)
Working With Orders¶
Placing an Order¶
There are many various types of orders that can be placed and as such we will allow Interactive Brokers documentation to explain every option. (Even I as the developer of this API do not know all permutations at this point). The main endpoint to use is place_order . The order id simply must be a unique integer or a duplicate id error will be generated.
Placing a Limit Order¶
The sample below shows a limit order being placed to purchase 1 share of Bank of America Stock.
order_id = 60
contract = Stock('BAC')
contract.currency = "USD"
contract.exchange = "SMART"
total_quantity = 1
limit_price = 26.5
order = LimitOrder(OrderAction.BUY.value, contract, total_quantity, limit_price)
ibkr.place_order(order_id, order)
Get all open orders¶
Now that we know how to place an order. The next logical step is to check on that order. This can be done with a call to request_open_orders which will return a list of Order objects.
open_orders = ibkr.request_all_open_orders()
for open_order in open_orders:
print(open_order)
Working With Options¶
List all the option chains for TSLA¶
Get the option chains for all Dow 30 Stocks¶
dow30 = Dow30()
for stk in dow30.stocks():
stk = ibkr.request_contract_data(stk)
option_chains = ibkr.request_option_chains(stk)
for opt_chain in option_chains:
print(opt_chain)
Other Functionality¶
Get all linked accounts (aka ‘Family Codes’)¶
family_codes = ibkr.request_family_codes()
for code in family_codes:
desc = "{0} - {1}".format(code['account_id'],code['family_code'])
print(desc)
Find All Contracts that Match ‘TSLA’¶
request_id, contracts = ibkr.request_matching_symbols('TSLA')
for c in contracts:
print(c)
Display Account Positions¶
position_data = ibkr.request_positions()
for data in position_data:
c = data['contract']
desc = "{0:<10} {1:<10} {2:>20} {3:>30}".format(data['account'], c.local_symbol, data['position'], data['average_cost'])
print(desc)
Get the Last Year of Daily Prices for XOM¶
dow30 = Dow30()
# contract = Contract(symbol="XOM", security_type="STK") - Another way to get a contract
contract = dow30.XOM()
duration = "1 Y"
(message_id, request_id, bar_data) = ibkr.request_historical_data(contract, '', duration, "1 day", HDT.TRADES.value, 1, 1, False, [])
print("XOM Daily Closes")
for bar in bar_data:
print("{0}: {1}".format(bar.date, bar.close))
ClientApplication¶
To help get you started browse some representative usages of the API
How to Create a Market Scanner Subscription¶
First create a Scanner object. This will contain the primary criteria to scan the market by. Once we configure the scanner object, all we need to do is call request_scanner_subscription to start receiving data
scanner = Scanner()
scanner.instrument = "STK"
scanner.location_code = "STK.US.MAJOR"
scanner.scan_code = "HOT_BY_VOLUME"
request_id = self.get_local_request_id()
self.request_scanner_subscription(request_id, scanner, None, None)
The Bridge will periodically continue to refresh this information, so if the data is no longer required. It can be stopped by calling cancel_scanner_subscription with the same request id that was supplied to the initial request.
self.cancel_scanner_subscription(request_id)
General Data¶
This section describes some of the other functionality not already covered above
Getting All Linked Accounts (aka ‘Family Codes’)¶
To get linked account data, add the line below to either your application’s initialize or act method
Family Codes | |
---|---|
Response | Description |
family_codes | Normal response from the bridge |
self.request_family_codes()