Connect, become ready, and disconnect
This page covers one connection epoch: open a socket to TWS or IB Gateway, finish the ib_async startup synchronization, decide when the application is ready, react to loss or staleness, and cleanly disconnect. It does not treat a live TCP socket as proof that account, market-data, or order state is usable.
Components and safe defaults
The transport path is:
Python process -> TCP socket -> TWS or IB Gateway -> authenticated IBKR session -> IBKR services/exchanges
Install the version used by this documentation:
python -m pip install "ib_async==2.1.0"
In TWS or IB Gateway, enable socket clients, choose the API port, and restrict any remote connection with network controls and Trusted IPs. Keep the API read-only unless the process is intentionally authorized to trade. Common defaults are:
| Application | Live | Paper |
|---|---|---|
| TWS | 7496 | 7497 |
| IB Gateway | 4001 | 4002 |
Ports are configurable and do not prove whether the authenticated session is live or paper. The examples below use the common paper Gateway port and readonly=True.
The current official connectivity guide describes socket opening, the version handshake, session account/order-ID data, Trusted IPs, and broken-socket callbacks. See Sources and applicability.
Minimal connection epoch
This example performs no trading operation. It waits for library startup synchronization, installs an inbound-idle signal, and always clears local session state on exit.
import asyncio
from ib_async import IB
async def main() -> None:
ib = IB()
try:
await ib.connectAsync(
host="127.0.0.1",
port=4002,
clientId=7,
timeout=10,
readonly=True,
raiseSyncErrors=True,
)
if not ib.isConnected():
raise ConnectionError("API session did not become ready")
ib.setTimeout(45)
# Safe application reads can begin after application-specific checks.
finally:
ib.disconnect()
asyncio.run(main())
connectAsync catches connection/startup failures, calls disconnect, and re-raises. Calling disconnect again in finally is safe: it returns without changing state when the client socket is already disconnected.
What connectAsync guarantees
For pinned ib_async 2.1.0, successful return means more than “TCP opened.” The method:
- Opens the client connection and completes the API version/session handshake.
- Obtains the accessible accounts and next valid request/order-ID basis used by
Client.isReady(). - Starts the configured startup requests. Positions are always requested; other groups depend on
readonly,account,fetchFields, server version, and the subaccount count. - Runs most startup requests concurrently, then requests executions after order synchronization.
- Optionally raises when startup requests timed out, verifies
Client.isReady(), emitsconnectedEvent, and returns the sameIBinstance.
The startup request callbacks can interleave. Do not build application logic around an incidental order between position, account, open-order, completed-order, or execution callbacks. connectedEvent handlers run before the coroutine caller resumes from the successful await, and they run again after each successful reconnect.
| Parameter | Pinned 2.1.0 behavior and boundary |
|---|---|
host, port | Address of the configured TWS/IB Gateway socket. Do not expose it directly to the public internet. |
clientId | Identifies this API client. Concurrent clients need distinct IDs. ID 0 also requests automatic binding of eligible manual orders. |
timeout | Bounds connection and startup waits. 0 or None disables the timeout in this library version. |
readonly | Skips startup order synchronization. It does not change TWS permissions. |
account | Selects traditional account updates. Empty auto-selects only when the session exposes exactly one account. |
raiseSyncErrors | Raises ConnectionError after startup timeouts instead of returning with only logged synchronization errors. |
fetchFields | Selects open/completed orders, account updates, subaccount updates, and executions. Positions remain unconditional in 2.1.0. |
Completed-order synchronization requires server version 150 or newer. Automatic per-subaccount synchronization is skipped when the accessible account count exceeds IB.MaxSyncedSubAccounts; that is an application scaling boundary, not proof that the omitted accounts do not exist.
Three readiness levels
Treat readiness as three separate questions:
| Level | Check | What it establishes | What it does not establish |
|---|---|---|---|
| Socket | ib.client.isConnected() | The client transport state is connected. | API handshake readiness, upstream IBKR connectivity, or synchronized application state. |
| Library API | ib.isConnected() or ib.client.isReady() | In 2.1.0, IB.isConnected() delegates to the client’s API-ready flag. | Market-data farm health, permissions, complete reconciliation, or your business invariants. |
| Application | An application-owned readiness gate | Required account scope, reconciliation, subscriptions, and operational policy have passed. | Future connectivity; readiness must be cleared on loss, staleness, or invariant failure. |
This corrects a common ambiguity: IB.isConnected() is not the raw-socket check in pinned 2.1.0. Use it as a library API-ready check, then apply stricter application rules.
Codes 1100, 1101, and 1102 describe the TWS/IB Gateway connection to IBKR. During 1100, the local API socket can remain open and IB.isConnected() can remain true. Clear application readiness and distinguish 1101 (“data lost”) from 1102 (“data maintained”) before rebuilding subscriptions.
Expected signals and failure handling
| Signal or failure | Interpretation | Required response |
|---|---|---|
connectedEvent | Library handshake and configured startup synchronization completed. | Re-run application invariants; do not assume prior subscriptions survived. |
disconnectedEvent | The local API socket ended or the application disconnected. | Clear readiness immediately, capture the connection epoch as ended, and reconnect with backoff if policy allows. |
timeoutEvent(idlePeriod) | No inbound message arrived for the configured interval. It fires once per connected session until reset/reconnect. | Mark the connection degraded and run a bounded health policy; quiet traffic alone does not prove socket failure. |
502 while connecting | The operating system could not open the socket; common causes include a closed/wrong API port, TWS/IB Gateway not running, firewall rules, or Trusted IP configuration. | Fix configuration or retry with bounded backoff. No server request was accepted through that socket. |
| Startup request timeout | One or more synchronization requests did not complete in time. | Prefer raiseSyncErrors=True; otherwise explicitly inspect/re-request the missing state before declaring application readiness. |
1300 | TWS reset the socket port and dropped the API connection. | Discover the configured port again, reconnect, and rebuild state. |
Handlers must be idempotent. A reconnect produces another connection epoch and another connectedEvent; loss, timeout, and upstream-status signals can occur close together. Clear readiness repeatedly without assuming one canonical failure ordering.
Production-pattern connection owner
Use one task to own a client ID, application readiness, disconnect handling, and retry timing. This example remains read-only and does not submit orders. Its account check is an example application invariant; later Phase 4 pages add reconciliation and subscription checks.
import asyncio
from ib_async import IB
ib = IB()
application_ready = asyncio.Event()
socket_lost = asyncio.Event()
stop_requested = asyncio.Event()
def on_disconnected() -> None:
application_ready.clear()
socket_lost.set()
def on_idle(_idle_period: float) -> None:
# Degrade readiness; a separate bounded probe/policy decides whether to reconnect.
application_ready.clear()
ib.disconnectedEvent += on_disconnected
ib.timeoutEvent += on_idle
async def wait_before_retry(delay: float) -> None:
try:
await asyncio.wait_for(stop_requested.wait(), timeout=delay)
except asyncio.TimeoutError:
pass
async def wait_for_stop_or_loss() -> None:
stop_waiter = asyncio.create_task(stop_requested.wait())
loss_waiter = asyncio.create_task(socket_lost.wait())
_done, pending = await asyncio.wait(
(stop_waiter, loss_waiter), return_when=asyncio.FIRST_COMPLETED
)
for waiter in pending:
waiter.cancel()
await asyncio.gather(*pending, return_exceptions=True)
async def connection_loop() -> None:
delay = 1.0
while not stop_requested.is_set():
application_ready.clear()
socket_lost.clear()
try:
await ib.connectAsync(
host="127.0.0.1",
port=4002,
clientId=7,
timeout=10,
readonly=True,
raiseSyncErrors=True,
)
ib.setTimeout(45)
if not ib.isConnected() or not ib.managedAccounts():
raise ConnectionError("connection invariants failed")
# Persist the new connection epoch here, after invariants pass.
application_ready.set()
delay = 1.0
await wait_for_stop_or_loss()
except (ConnectionError, OSError, asyncio.TimeoutError):
delay = min(delay * 2, 60.0)
finally:
application_ready.clear()
ib.disconnect()
if not stop_requested.is_set():
await wait_before_retry(delay)
Add jitter in a multi-process deployment. Enforce client-ID ownership outside the loop so two replicas cannot race with the same ID. The timeout handler intentionally does not reconnect by itself: a quiet but healthy session, farm degradation, and a broken socket require different responses.
Deliberate disconnect and persistence boundary
IB.disconnect() records connection statistics, disconnects the client, emits disconnectedEvent, and resets the wrapper’s synchronized session state. Capture durable information required for diagnostics or reconciliation before calling it. The method sends no cancel-order requests, so disconnect must not be treated as an order-cancellation mechanism.
The wrapper objects are an in-memory projection, not the durable record of the connection epoch. Persist stable identifiers and application state according to the later order/reconciliation slice; after reconnect, rebuild the projection from fresh synchronization rather than continuing to trust old objects.
Sources and applicability
Behavior is version- and configuration-specific:
- IBKR Campus: establishing an API connection —
official-current; retrieved2026-07-14T19:13:54.602937Z; supports socket opening, handshake, accessible-account/next-ID/connection-time session data, and common connection failures. - IBKR Campus: broken API socket connection —
official-current; retrieved2026-07-14T19:13:54.602937Z; supports connection-closed signaling and reconnect handling. IB.connectAsyncpinned source —library-source,ib_async2.1.0; retrieved2026-07-15T03:42:42Z; supports startup synchronization, timeout handling, readiness verification, cleanup, andconnectedEventemission.IB.isConnectedpinned source andClientreadiness states —library-source, 2.1.0; retrieved2026-07-15T03:42:42Z; distinguish raw socket and API-ready state.IB.setTimeoutpinned source —library-source, 2.1.0; retrieved2026-07-15T03:42:42Z; supports inbound-idle event semantics.IB.disconnectpinned source —library-source, 2.1.0; retrieved2026-07-15T03:42:42Z; supports event emission and wrapper reset.
No live-trading experiment is required for this page. The examples are compiled and their ib_async imports and call signatures are checked offline; they are not executed against TWS or IB Gateway in CI.