This guide walks through the changes required to upgrade from rust-ibapi v1.2.2 to v2.0.0.
- Async client is production ready and enabled by default.
- Blocking client remains available; when built alongside async it lives under
client::blocking. - Contracts, market data, and orders now use fluent, type-safe builders.
- Trading hour configuration uses the
TradingHoursenum instead of bare booleans. - Tracing, request helpers, and integration coverage have been expanded for both execution models.
Version 2.0 ships both asynchronous (Tokio) and blocking (threaded) clients. The async client is on by default, so a bare dependency activates it automatically.
| Scenario | Cargo.toml snippet | Primary client type |
|---|---|---|
| Async only (default) | ibapi = "2.0" |
ibapi::Client (async) |
| Blocking only | ibapi = { version = "2.0", default-features = false, features = ["sync"] } |
ibapi::client::blocking::Client |
| Both clients | ibapi = { version = "2.0", default-features = false, features = ["sync", "async"] } |
Async: ibapi::Client; Blocking: ibapi::client::blocking::Client |
When both features are enabled the top-level ibapi::Client continues to refer to the async implementation. Import the blocking client explicitly:
use ibapi::Client; // async client
use ibapi::client::blocking::Client; // blocking clientIf you disable default features without opting back into sync or async, the build fails with a compile error that lists the supported combinations.
In 1.x the Client type was blocking by default. In 2.0 the async client owns the root name and the blocking client, subscriptions, and trace helpers live under a blocking module.
// v1.x
use ibapi::Client;
// v2.0 (blocking)
use ibapi::client::blocking::Client;
let client = Client::connect("127.0.0.1:4002", 100)?;Related helpers gained matching namespaces when both features are compiled (for example trace::blocking::record_request and client::blocking::Subscription). Code that only enables the sync feature continues to work without the extra module path.
The contract API switched to fluent, type-safe builders. Every builder call must end with .build():
// v1.x
let contract = Contract::stock("AAPL");
// v2.0
let contract = Contract::stock("AAPL").build();
let futures = Contract::futures("ES").front_month().build();This change ensures required fields are set at compile time and prevents partially constructed contracts.
Client::market_data now returns a builder that configures the subscription before you call .subscribe().
// v1.x
let sub = client.market_data(&contract, &["233"], false, false)?;
// v2.0 (blocking)
let sub = client.market_data(&contract)
.generic_ticks(&["233"])
.subscribe()?;
// v2.0 (async)
let mut sub = client.market_data(&contract)
.snapshot()
.subscribe()
.await?;Snapshot mode, regulatory snapshots, and streaming toggles are now explicit builder methods, improving readability and discoverability.
All APIs that accepted a bool for regular versus extended trading hours now take the TradingHours enum:
// v1.x
client.realtime_bars(&contract, BarSize::Sec5, WhatToShow::Trades, true)?;
// v2.0
use ibapi::market_data::TradingHours;
client.realtime_bars(
&contract,
BarSize::Sec5,
WhatToShow::Trades,
TradingHours::Regular,
)?;The enum makes intent explicit, aligns with documentation, and leaves room for additional hour modes.
You can continue to construct Order manually, but the new builder dramatically reduces boilerplate and validates combinations at compile time:
use ibapi::orders::order_builder::OrderBuilder;
use ibapi::orders::Action;
let order = OrderBuilder::market(Action::Buy, 100).build();Builders exist for market, limit, stop, bracket, and combination orders, mirroring Interactive Brokers terminology.
If you call the trace API while building both clients, switch to the blocking namespace:
// v1.x
trace::record_request("REQ|123|AAPL|".into());
// v2.0 (blocking with async feature also enabled)
trace::blocking::record_request("REQ|123|AAPL|".into());Async tracing is available directly as trace::record_request and uses asynchronous storage under the hood.
- Update your dependency according to the execution model you need.
- Adjust imports to use
client::blocking::Client(andtrace::blocking,market_data::blocking, etc.) when compiling both features. - Add
.build()to every contract builder chain. - Switch market data calls to the new fluent builder with
.subscribe(). - Replace
use_rthbooleans withTradingHours. - (Optional) Adopt the order builder for new code and tests.
- Re-run
cargo fmt,cargo clippy --all-targets --all-features, and your test suite for each feature flag you support.
[dependencies]
ibapi = "2.0"
tokio = { version = "1", features = ["full"] }use ibapi::prelude::*;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::connect("127.0.0.1:4002", 100).await?;
let time = client.server_time().await?;
println!("Server time: {time:?}");
Ok(())
}To exercise both clients in CI, run:
cargo test # async (default)
cargo test --no-default-features --features sync
cargo test --all-features # async + blocking- Production-ready async client with reconnection helpers and
Client::is_connected(). - Fluent builders for contracts, market data subscriptions, and order placement.
- Safer trading hour handling via the
TradingHoursenum. - Expanded integration tests, recorded fixtures, and improved error messages.
- Interaction recording that works uniformly in both async and blocking modes.
- Examples:
examples/asyncandexamples/sync - Documentation: https://docs.rs/ibapi/2.0.0
- Issues: https://github.com/wboayue/rust-ibapi/issues