Requests, delivery and shutdown

Requests and cancels return after admission. The engine holds work while it waits for contract naming, order replay, account download, an option's model, or an earlier exchange to finish. A cancel withdraws its own kind of request, including one still waiting, except cancel_contract_data and cancel_historical_ticks, which withdraw nothing, as on a gateway (see Venue behaviour). Cancelling a question that is ready follows its answer; cancelling one still waiting prevents that answer. A request for a contract the venue names no single contract for is over, as it is at a gateway: its number holds nothing, a cancel under it is refused as one of nothing held, and it can be asked under again.

Requests and callbacks

Rust request and cancel methods return (). Their refusals arrive on Wrapper::error_from or Wrapper::error. Request methods take no wrapper: pass the wrapper to process_msgs to receive their answers. The answering conveniences, such as historical_data, contract_details and qualify_contract, wait and return their results.

Records are delivered in session order. Refusals, immediate answers, connection notices, registrations and order reports share that order. Quotes, positions, account figures and other conflated state follow the records of a read. A record arriving during a read waits for the next read. A fill and its status from one report are delivered as order_status, then exec_details; the commission report follows where the venue states it. It carries the realized P&L and a bond's yield where the venue states them beside the charge, and the unset value where it states none, states nan or, for the P&L, zero. The commission is unset in the same way. A record stating neither the charge nor the other amount beside it is not delivered, and neither is one stating a figure or a sending time that cannot be read. The venue states the day's executions and their charges again at every reconnect. An execution is delivered once for the session, however many the day has. A charge is delivered once for the day its record was sent on, counted on the session's time zone, as a gateway keeps it: only a later revision of one is delivered again, with the P&L the one before it realized added to its own, and one stated again after midnight there is delivered again.

Python request refusals also wait for poll() or run(). A 504 about a feed or trading connection that ended within an admitted session follows the earlier records. With no session, “not connected” is reported inside the call, as in the reference client.

A Rust answering convenience with keep_record delivers a whole read through that record and its answer collector. Without a kept record, it takes only its own answers and leaves other callbacks for process_msgs.

Error origins

Every error reaches error_from. Its default forwards to the error callback, so a wrapper that implements only error receives every error there. Rust ErrorOrigin distinguishes:

OriginMeaning
Request { id, ends }A numbered request; ends distinguishes a refusal from a notice followed by more answers
Order { id, op }An order's placement, modification, cancellation, exercise, or a venue report
Question { q, ends }A request without an id, such as positions, open orders or scanner parameters
SessionA connection notice or another session-wide outcome
Internal(id)An engine lookup

Python ErrorOrigin exposes kind, id, ends, op and question. ends is None for origins other than requests and questions; op and question are None when inapplicable. Ordinary ibapi wrappers receive error with the original number and code, with the arguments the wrapper's error declares: reqId, errorCode, errorString as ibapi 9.81 calls it, advancedOrderRejectJson after them as the releases before errorTime did, or errorTime second as the current release does. An error declared with three or four is called directly, without error_from.

A call that answers asks under a number this client took for that call. What answers it after the call has returned — the end of a lookup that was refused, an answer that came after the wait ran out — reaches no wrapper on either surface.

refuse(origin, code, msg) adds a caller-side refusal to the same stream, on both surfaces. Python makes the origin from the fields it reads back: ErrorOrigin(kind, id=-1, ends=True, op=None, question=None). question_retired(Question) marks the ordered cancellation of positions or account updates; its default does nothing. Python delivers no cancellation callback for these questions.

Shutdown

Python disconnect() finishes the engine's wire work, calls connectionClosed before returning, and discards queued callbacks.

Rust disconnect() returns Shutdown { logout_sent, engine }. The engine result is EngineEnd::Ended or EngineEnd::Panicked; either confirms that the engine thread ended. Concurrent callers wait for the same end. Call process_msgs afterwards to receive the remaining records and final state, followed by connection_closed. Nothing from that session follows the close. Orders already admitted finish before logout or are refused under their order numbers. Orders kept with transmit = false are not sent.

EClientConfig.cancel can take back a connect during socket operations, second-factor polling and client construction. Name resolution and a supplied code provider must return before cancellation completes. Shutdown waits for recovery workers to finish, including those calls, and logs out a session that opened while cancellation was underway.

Admission and wakeups

Admission uses an unbounded channel: a call hands the engine its command and returns, however far behind the loop is. Released work and new commands share a limit of 64 commands per engine lap. A caller that limits admission must still allow the transmitting order or cancellation that releases its staged orders.

Rust on_data(Some(hook)) installs a wake hook; None removes it. The hook runs on the engine thread, outside engine locks, after a record or state change, at most once until the next process_msgs begins. It must return immediately and must not call disconnect or drop the last client owner. A panicking hook is logged and removed. Bound an idle wait when relying on completions whose deadlines are evaluated by process_msgs, such as snapshots and smart components.

Both surfaces expose traffic(): bytes_sent, bytes_received, messages_sent and messages_received for the session. Bytes are protocol frames before TLS encryption and after decryption. Complete frames count as messages, including one message per compressed outer frame. Initial authentication is outside these counts; replacement connections preserve them.

Order IDs

Both surfaces state next_valid_id once a session has connected, after the venue has named the orders the account is working: Python before connect() returns, Rust on the first process_msgs read after that naming.

Rust order_id_floor() reads the ID next_valid_id would state, without waiting; next_shared_id() answers the request-compatible one. next_shared_id_within(timeout) adds a bound to the replay wait and observes EClientConfig.cancel. next_order_id() is an answering call; an exercise that asks the engine to assign its number returns immediately and is numbered after replay.

The order-id file keeps a separate next ID for each account and API client ID across sessions; the order_id_file setting selects it. See order IDs across sessions for its default location, reservations and moving the file.

Settings and request values

There are 17 carried settings, on Rust EClientConfig.gateway and Python ib_dx.configure(), and 15 settings recorded as inapplicable here. Registration is held by the engine and does not wait on a caller thread.

Historical news takes signed total_results: i32. Values above 300 are sent as 300; zero and negative values pass through. Historical ticks carry ignore_size. Order-condition margin percentages and price trigger methods are signed i32 and are sent unchanged.

Rust req_scanner_subscription takes a final scanner_setting_pairs: &str; pass "" when none are stated. Both surfaces accept these pairs and warn once that they are not carried to the venue. Scanner subscriptions first load permission metadata. Missing permissions produce error 490 and prevent the subscription, or warning 492 while the scan continues. Notices name the scan and requested filters; range names omit the trailing “below” regardless of letter case. A range name containing an ellipsis is given as the venue states it, where a gateway may shorten it to the words before the ellipsis. Metadata fetched for a subscription produces no unsolicited scanner_parameters callback.

When a real-time bar ticker is reassigned to a different contract, its bars reach the new contract's subscriptions. Existing subscriptions retain their assigned cancellation number. Readers of the same contract share its stream and price and size increments.

Bond order messages use Govt, Muni, Corp and Agency issuer labels. An unknown issuer category is omitted. A replacement preserves a venue-provided external instruction identifier, including nonnumeric identifiers.

Accounts, exercises and snapshots

Named-account updates, positions, profit and multi requests keep the account they name. An All summary includes every account held by the login. Concurrent profit requests have separate subscriptions. Multi answers echo the requested model label on the initial and subsequent rows. Model selection, AllNonProp membership and advisor groups are not applied and produce a warning once per selection and session.

An exercise requires a positive position in the selected account. It requests tick 493 and waits for its in-the-money figure when necessary, even with override. Without override it applies the exercise/lapse check. Its quantity is limited to the whole-contract position captured before waiting. Shutdown refuses an exercise still waiting for that figure. The alternate exercise transport is not implemented.

Snapshot registration follows contract naming, including options given only by contract id. Its eleven-second bound starts when the engine takes the named subscription. A snapshot is sent each kind of tick once, the first the quote states, and the bid's, ask's and last's sizes only beside their prices, each right after its price. The snapshot waits for bid, ask, last, open and close; OPT, FOP, IOPT, WAR and EC also wait for model computation 13 and the bid's, ask's and last's computations 10 to 12, or 83 and 80 to 82 for delayed data. Delayed snapshots also wait for tick string 88. As a gateway does, a snapshot is sent no open, and does not wait for one, on any type but STK, FUT, CMDTY and CRYPTO; no volume or last size on CASH, IND, FUND, CMDTY, FIXED and EC; and no last or last exchange on CASH, CMDTY, FIXED and EC; nor, where a contract's definition says it is quoted at its midpoint, a volume or a last. Each computation is sent to a snapshot once and only with all eight figures stated; at the end it is sent each one it has not been sent where any figure is stated. On a frozen or delayed-frozen feed the model is also sent once whatever it states, and at the end a side only with all eight figures stated and the model again where it was not sent that way. A snapshot of an option on an index or a future, or of one whose definition the venue has not answered, is sent no 10 to 12 here and so runs the full eleven seconds.

Lower-level Rust users

from_parts, engine constructors and core command senders use std::sync::mpsc::Sender<ControlCommand>. Order, market-data and question commands carry their inputs to the engine. MarketDataTaken carries the slot generation and registration time. Order records share immutable cached reports. Ask and Answer multi-account variants carry the account and model label. A global cancellation is one order-buffer request. An automatically numbered exercise carries its caller's shared allocator until replay completes.

SharedState.portfolio is an Arc, and named accounts have separate stores. Profit request and cancellation commands distinguish account and single-position subscriptions. Connection::new takes TlsStream<LogonSocket>; explicit socket construction wraps the TCP stream with LogonSocket::new. Established connections keep their ordinary timeouts.

Per-client order views, outcomes for children of refused placements and changes behind a refused or withdrawn placement, complete option greeks, account-group and model application, alternate exercise transport and scanner settings-pair carriage are limited as Limits describes.