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

Notebooks

notebooks/ holds eight notebooks, one on each of ib_async’s own subjects, written against ib_async itself — its IB, its contracts, its events, its util.df — and run on the engine through ib_async_dx.IB. None of them starts a gateway, and every one opens a paper session.

Each begins the same way. It is the one cell that differs from a notebook written for a gateway: the import names ib_async_dx, and connect takes the login.

import os
from dotenv import load_dotenv
from ib_async_dx import IB, util

util.startLoop()
load_dotenv()

ib = IB()
ib.connect(
    username=os.environ["IB_USERNAME"],
    password=os.environ["IB_PASSWORD"],
    paper=True,
)

util.startLoop() is ib_async’s own: it applies nest_asyncio so that ib_async’s blocking calls can run inside the notebook’s loop, as it does over a gateway. A handler can make one too, a request on an error or a connect when the session ends. nest_asyncio cannot run asyncio’s timeouts on Python 3.14, so there ib_async’s own calls fail under it, over a gateway as here: run the notebooks on Python 3.11 to 3.13.

The eight

NotebookWhat it showsib_async calls
basicsWhat the account is worth, what it holds, and one quoteaccountSummary, positions, qualifyContracts, reqMktData, cancelMktData
contract_detailsWhat the venue knows about a contract, how it answers a description that matches more than one, and a search by namereqContractDetails, reqMatchingSymbols
bar_dataHow far back the venue holds a series, the bars themselves as a frame, and a series kept up to datereqHeadTimeStamp, reqHistoricalData, util.df, keepUpToDate=True, cancelHistoricalData
tick_dataTop of book on three contracts as it changes, and every print as it happensreqMktData, pendingTickersEvent, reqTickByTickData, ticker.tickByTicks
market_depthWhich venues will answer for a book, a ten-level book, and the book movingreqMktDepthExchanges, reqMktDepth, ticker.domBids, ticker.domAsks, ticker.updateEvent
scannersWhat the venue can scan for, one scan run, and its rows as a framereqScannerParameters, ScannerSubscription, reqScannerData, util.df
orderingAn order placed, watched, moved and withdrawn, and one previewed rather than sentplaceOrder, LimitOrder, trade.log, cancelOrder, openTrades, whatIfOrder
option_chainThe S&P 500 index’s option chains, the options within 20 points of it on the next three monthly expiries, and their quotes and model greeksreqMarketDataType, reqTickers, reqSecDefOptParams, qualifyContracts, ticker.modelGreeks

A few things they show along the way:

  • A quote wants a qualified contract. ib_async keys a Ticker by the contract, and a contract without its conId cannot be a key, so qualifyContracts comes first.
  • One Ticker per contract, amended in place. pendingTickersEvent fires with the tickers that changed, rather than on a timer; tick-by-tick is the trade stream itself rather than a summary of it.
  • A kept-up-to-date series amends its last bar as it forms, rather than repeating it.
  • A book asked for at a named venue is answered by that venue. Asked for at none, it is acknowledged and may produce nothing, which is what an account with no aggregate entitlement is told.
  • The venue states its scanner parameters as one XML document, and the notebook reads the scan codes out of it.
  • A Trade is amended as the venue reports on it, and its log is the whole history of the order. A modification is the same order under the same id, at a new price; whatIfOrder asks what an order would cost the account and sends nothing.
  • An option chain is every expiry against every strike. The notebook takes the options it wants from that matrix and qualifies them in one call.

Note

ordering places a real order on the paper account: a buy at half the last price, meant to rest unfilled until a later cell withdraws it. A price is not a guarantee; the trade’s status says what happened. Run the notebook through, or withdraw it yourself.

Running them

pip install "git+https://github.com/userFRM/ib-dx@c18523506144df7b9f81fdbb82b68405f24f13ea"
pip install "ib_async-dx @ git+https://github.com/userFRM/ib_async-dx" \
    jupyter python-dotenv pandas
git clone https://github.com/userFRM/ib_async-dx
jupyter lab ib_async-dx/notebooks

util.df needs pandas, which ib_async does not install on its own. The credentials come from a .env file at the repository root, read by python-dotenv, as IB_USERNAME and IB_PASSWORD. The repository ignores that file; keep it that way.

One thing to keep

ib.sleep(), never time.sleep(). The library runs its event loop on the calling thread, so a plain sleep stops it: quotes stop arriving, and every stream reads as dead when it is only unattended.