Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

What drop-in means

The promise is the one an ib_async user would ask for: an existing program changes its import and its connect line, and nothing else. The connect line gains credentials, or, for a paper account, stays as it was where IB_USERNAME and IB_PASSWORD are set, because nothing local is addressed: then only the import changes, as a gateway keeps its login in its own settings. A live account adds paper=False.

- from ib_async import IB, Stock
+ from ib_async_dx import IB, Stock

  ib = IB()
- ib.connect("127.0.0.1", 4001, clientId=1)    # a gateway on localhost
+ ib.connect(username="...", password="...")   # a paper session; paper=False for live

What the import gives

ib_async_dx is ib_async. It exports ib_async’s __all__, all 103 names, and every one of them is ib_async’s own object — the same class, the same function, the same enum, the same __version__ — except two:

  • IB, a subclass of ib_async.IB. Its connect and connectAsync put the engine in place of ib_async’s Client and then run ib_async’s own connect. Everything else on it is ib_async’s, apart from the four bug fixes and the added calls.
  • IBC, a subclass of ib_async.IBC with no gateway to launch: starting it holds the login it names for the connects made in the same context, and terminating it ends every session that login opened. ib_async’s own Watchdog, handed one, connects its IB with that login and connects it again when the session ends (Limits has the detail).

Client is ib_async’s own socket client, re-exported unchanged like every other name: a program that builds one itself still addresses a gateway. IB is what runs on the engine.

__version__ and __version_info__ are ib_async’s, so a program that checks the API level it runs on reads what it always did. This package’s own version is __ib_async_dx_version__.

ib_async’s submodules resolve here as themselves, so both import forms work: import ib_async_dx.order and from ib_async_dx.util import df. ib_async_dx.ib is ib_async’s ib module with IB replaced, and ib_async_dx.ibcontroller its ibcontroller module with IB and IBC replaced. Because the objects are ib_async’s own, isinstance checks, pickles and a module that still imports Stock from ib_async all agree with the rest of the program.

The connect line

connect is ib_async’s signature, with its parameters and defaults, and four keyword-only parameters after them: username, password, paper and sessionFile. Getting started writes it out.

  • host and port are accepted and not used. The port does not choose paper or live: the session is paper unless paper=False.
  • clientId is carried into the login, where it keys this session’s orders. One program per login: a second program on the same login takes the session from the first.
  • username and password, left empty, are an IBC’s login where one was started in the same context, and otherwise IB_USERNAME and IB_PASSWORD.
  • readonly=True makes a read-only session, which refuses to send anything that places, changes or withdraws an order, as a gateway set to read-only does.
  • timeout bounds each request ib_async makes as the session opens, as it does against a gateway. It does not bound the login, which a gateway also makes before a program connects, nor the engine’s wait of up to three seconds, inside the login, for the venue to name the working orders: a live login waits on its second factor for as long as the engine allows.

The rest is ib_async’s own connect: as it does against a gateway, it asks for the account’s values, its positions, its open and completed orders and its executions, as fetchFields says.

How it is proven

The package against ib_async, on every run. test_the_package_is_ib_async.py checks that ib_async_dx.__all__ equals ib_async’s and that every name in it is ib_async’s own object but IB and IBC, __version__ among them; that all 13 of ib_async’s submodules resolve under both import forms; that IB and IBC are subclasses of ib_async’s; and that connect and connectAsync are ib_async’s parameters, defaults and kinds with the four keyword-only ones after them. That is the parity check: a name ib_async adds to __all__, or a change to its connect, fails here before it reaches a program.

Against ib_async’s own source, on every run. test_every_call_their_library_makes_is_carried reads every call ib_async’s IB makes on its client out of ib_async’s installed source — 67 at 2.1.0 — and fails if any one of them does not land on the engine. It is not a list kept by hand, so a call ib_async adds is a failing test here rather than a program that stops. And test_a_raw_message_is_the_request_it_names.py runs each of the 80 requests ib_async’s client writes as a message, through its own send, and checks that each reads back into the message it was and reaches the engine exactly as the same request made by name.

Against ib_async’s own tests. tests/ib_async_upstream/conftest.py runs ib_async’s test suite against the engine instead of against a gateway: their shared ib fixture is an ib_async_dx.IB, connected with the login in the environment, and so is the ib_async.IB() a test builds for itself. The suite is theirs, fetched from their repository rather than copied into this one. It has not been run against the venue at this revision; what each of its three tests asks, and how to run them, is in Running ib_async itself.

Against the venue. Two tests take a live login, each with ib_async’s own IB attached. One runs an unmodified ib_async program — connect, qualify, bars, quotes through pendingTickersEvent. The other takes an order through its whole life in ib_async’s objects: priced as a what-if, placed, changed and withdrawn. Both are skipped where IB_USERNAME and IB_PASSWORD are not set, and neither has been run against the venue at this revision. The scripts under scripts/ do the same through ib_async_dx.IB against a paper account, and the notebooks do it a cell at a time. Neither has been run against the venue through ib_async_dx.IB yet, so Evidence rates both paths ✅ Offline.

What crosses, offline. The other 316 tests need no session: that a combination keeps its legs on every request path, that a fill’s cost reaches ib_async as its own CommissionReport, that a refused order reaches its Trade, that connect takes its login from the environment or an IBC and is paper unless told otherwise, that a session opens and closes once, on the program’s loop, however a connect is cancelled, overtaken or failed, and that each bug fix answers what ib_async 2.1 does not. Evidence lists what they cover.

In Rust

Coming: ib_async’s model and names, in Rust spelling, on the engine’s public API. It is not in this repository yet.