|
IBKR |
Architect |
Installation |
Download and install TWS or IB Gateway
“Before spending precious development time troubleshooting on the API side,it is recommended to first experiment with the TWS directly.” – IBKR docs
Configure TWS for API usage
Download and install the IBKR API
|
pip install architect-py
|
Connect To Client |
First, a compatible TWS or IB Gateway must be running.
If it crashes, you’ll lose your connection!
from ibapi.client import EClient # send requests
from ibapi.wrapper import EWrapper # recv callbacks
import threading
class IBApp(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.nextId = None
app = IBApp()
app.connect("127.0.0.1", 7497, clientId=1)
threading.Thread(target=app.run).start()
|
Create keys at the linked webpage.
from architect_py import Client
client = Client(
api_key="API_KEY",
api_secret="API_SECRET",
paper_trading=False
)
|
Get Front Month Future |
These functions must be run in the context of a class.
To make it fair we won’t rewrite any functions.
Getting the front future is left as an exercise because it isn’t trivial.
from ibapi.contract import Contract
NQ_lead_future: Contract | None = None
class App(EWrapper, EClient):
def contractDetails(self, reqId, cd):
self._cd.append(cd)
def contractDetailsEnd(self, reqId):
global NQ_lead_future
futs = [cd.contract for cd in self._cd
if cd.contract.secType == "FUT"]
NQ_lead_future = min(futs,
key=lambda c: c.lastTradeDateOrContractMonth
) # earliest active expiry
print("Lead NQ fut:",
NQ_lead_future.localSymbol)
self.disconnect()
q = Contract()
q.symbol, q.secType = "NQ", "FUT+CONTFUT"
q.exchange = "GLOBEX"
app.reqContractDetails(1, q)
|
NQ_lead_future = client.get_front_future(
"NQ CME Futures", "CME"
)
|
Fetch All Accounts |
class App(EWrapper, EClient):
def accountSummary(self, reqId, account,
tag, val, currency):
print(account, tag, val, currency)
def accountSummaryEnd(self, reqId):
self.disconnect()
app.reqAccountSummary(1, "All", "All")
|
accounts = client.list_accounts()
|
Fetch Historical Fills |
class App(EWrapper, EClient):
def execDetails(self, reqId, contract, execution):
print(execution.execId,
contract.localSymbol,
execution.side,
execution.shares,
execution.price
)
def execDetailsEnd(self, reqId):
self.disconnect()
app.reqExecutions(1, ExecutionFilter())
|
await client.get_fills()
|
Get The Midpoint Price |
mid = None
class App(EWrapper, EClient):
def tickPrice(self, reqId,
tickType, price, _attrib):
if tickType == 1: # BID
self.bid = price
elif tickType == 2: # ASK
self.ask = price
if self.bid and self.ask:
mid = (self.bid + self.ask) / 2
self.cancelMktData(reqId)
self.disconnect()
app.reqMktData(1, NQ_lead_future,
"", False, False, [])
|
s = await client.get_l1_book_snapshot(
NQ_lead_future, "CME")
mid = (s.best_ask[0] + s.best_bid[0]) / 2
|
Buy the Lead NQ Future At Midpoint Price |
from ibapi.order import Order
class App(EWrapper, EClient):
def nextValidId(self, orderId: int):
self.nextId = orderId
o = Order()
o.action = "BUY"
o.orderType = "LMT"
o.totalQuantity = 1
o.lmtPrice = MIDPOINT_PRICE
self.placeOrder(self.nextId, NQ_lead_future, o)
self.disconnect()
# Hard to control timing given network calls
|
from decimal import Decimal
from architect_py import *
order = await client.place_limit_order(
symbol=NQ_lead_future,
odir=OrderDir.BUY,
quantity=Decimal(1),
order_type=OrderType.LIMIT,
execution_venue="CME",
post_only=True,
limit_price=midpoint_price,
account=accounts[0].account.name,
time_in_force=TimeInForce.IOC,
)
|
API Docs |
IBKR API Docs
No search functionality.
|
Architect Python Docs
Cleaner docs with search.
|
Async and Sync Version? |
No – you’ll manage threading/async and limited type hints yourself. |
Both synchronous and native async clients available. |
Customer Support |
Customer-service live chat (see Reddit for complaints). |
Ultra-responsive, including a dedicated Slack channel. |