Repository navigation
v4.2.0
What's New
OrderBuilder reaches every enum-typed Order field (#832, #833)
New setters trigger_method, origin, short_sale_slot, designated_location, volatility_type, reference_price_type, rule_80_a and open_close — fields that reached TWS but could only be set by hand-building Order. oca_group now takes OcaType instead of a bare i32.
use ibapi::orders::{OcaType, Rule80A};
use ibapi::orders::conditions::TriggerMethod;
let order = client
.order(&contract)
.sell(100)
.stop(140.0)
.trigger_method(TriggerMethod::Last)
.rule_80_a(Rule80A::Agency)
.oca_group("MyOCA", OcaType::CancelWithBlock)
.submit()
.await?;One TimeInForce, with GTX and round-tripping of unknown values (#822, #826)
orders::builder::TimeInForce is merged into orders::TimeInForce; variants are spelled "till" (GoodTillCanceled, GoodTillDate, DayTillCanceled). Adds GoodTillCrossing (GTX) and Unknown(String), so a TIF this crate doesn't model survives a read/write round trip instead of becoming DAY. good_till_cancel() is renamed good_till_canceled().
let order = client
.order(&contract)
.buy(100)
.limit(50.0)
.good_till_crossing()
.submit()
.await?;Thanks to @tradatious for the contribution.
Order enums preserve values IB adds later (#825, #829)
Rule80A and OrderOpenClose gain Unknown(String); OcaType, OrderOrigin, ShortSaleSlot, VolatilityType, ReferencePriceType and TriggerMethod gain Unknown(i32). String enums parse through FromStr; variant as i32 becomes i32::from(variant).
use ibapi::orders::{OcaType, Rule80A};
let rule: Rule80A = "Z".parse()?; // Rule80A::Unknown("Z")
let code = i32::from(OcaType::CancelWithBlock); // 1Thanks to @tradatious for the contribution.
Async Subscription<T> dispatches statically (#823)
The async Subscription::new(receiver) constructor is removed; every async subscription is built by Client methods and decodes through T directly, as the blocking one does. clone() no longer has a panicking path.
Thanks to @tradatious for the contribution.
Bug Fixes
historical_data(..).between(start, end) returns the requested range (#835)
It sent the wall-clock span as trading seconds, so a one-day range returned ~3.7 sessions and anything over a day was rejected with code 321. Bars outside [start, end) are now dropped.
let bars = client
.historical_data(&contract, HistoricalBarSize::Hour)
.between(datetime!(2023-04-08 0:00 UTC), datetime!(2023-04-15 0:00 UTC))
.fetch()
.await?;Thanks to @Johan3F for the report.
Dead subscriptions fail at the socket drop (#816, #817, #818)
In-flight subscriptions and one-shots fail with Error::ConnectionReset as soon as the socket read fails, instead of hanging until the reconnect finished (up to 7.5 min). Sends while the session is down are refused, and TRANSPORT_RECONNECT_CODE is published once the new session is live.
while let Some(item) = subscription.next().await {
match item {
Ok(bar) => println!("{bar:?}"),
Err(Error::ConnectionReset) => break, // resubscribe on TRANSPORT_RECONNECT_CODE
Err(e) => return Err(e.into()),
}
}Thanks to @tradatious for the report and the contribution.
time minimum raised to 0.3.47 (#820)
Blocks resolution of versions affected by RUSTSEC-2026-0009.
Breaking changes are covered in docs/migration-4.0.md §12–§15. Full changelog: CHANGELOG.md.