ib-dx

ib-dx: direct connection engine for Interactive Brokers ib-dx: direct connection engine for Interactive Brokers

Talk directly to IBKR. The TWS API your program already uses, with no IB Gateway, no Trader Workstation and no JVM between you and the venue.

Get started Python recipes Rust recipes GitHub

For ib_async, use ib_async-dx, which runs it on this engine.

One line changes

A program written against the TWS API talks to IB Gateway or Trader Workstation over a socket on localhost, and that process talks to the venue. ib-dx takes the gateway's place: it logs in, holds the trading, market-data, historical and security-definition connections open, and gives your program the same calls and the same callbacks.

- client.connect("127.0.0.1", 4001, clientId=1)     # needs a gateway running
+ client.connect(username="...", password="...")    # no external process

port is still accepted, and client.port reads it back while the session is held, but nothing connects on it. There is no local process to point it at.

What goes away

The process

Nothing to install, launch, log into on a schedule, or restart.

The JVM

No Java runtime to install, and no heap to size.

The localhost socket

Callbacks are delivered in-process, on the thread that runs the dispatch: run() or poll() in Python, process_msgs in Rust.

The window

It runs headless: in a container, over ssh, on a machine with no display.

What you get

The shape you already have

EClient and EWrapper in Python, EClient and Wrapper in Rust, with the TWS API's method names and callbacks.

One engine, two languages

The Python module is the Rust core through PyO3, not a second implementation. A gate on every commit fails if the two surfaces stop agreeing on a call or a callback the TWS API documents.

Nothing in between

The engine runs on a thread of its own and can be pinned to a core. Quotes are published through a seqlock: the writer never blocks, and a reader takes a whole quote without a lock.

More than the API forwards

The session states things a gateway never passes on: the account's grants, the order types it will take, its algorithms, and data series with no documented call. See what.

Honest about its limits

A call the protocol cannot carry says why, instead of returning as though it acted. The limits are written down, over a coverage matrix regenerated from the source on every commit, and what a gateway answers the same way is on venue behaviour.

Where to go next

Status

Under active development. Every capability claim in this repository is assigned from a named artifact, a test, a script or a recorded server response, never from reading the code. The matrix is in capabilities.md, its counts are recomputed on every commit, and the build fails if one moves.

Both install routes build from the repository: see Getting started.