Repository navigation
v5.6.0
5.6 lets non-blocking loops over blocking streams tell "nothing yet" from "finished" with is_terminated(), and adds extended-hours sessions to historical schedule requests. No breaking changes.
What's New
is_terminated() on blocking streams (#1141)
On the blocking Subscription, TickSubscription and NoticeStream, try_next and next_timeout return None both while nothing has arrived and once the stream has ended. is_terminated() tells the two apart, so a polling loop over a finite request (contract details, historical ticks) knows when to stop. It becomes true after TWS's end marker, a terminal error, or Err(Error::Cancelled) after cancel(). A snapshot's end tick does not set it; that tick is itself the completion signal. The async types are unchanged: None from next().await already means ended.
use ibapi::prelude::*;
use std::time::Duration;
let contract = Contract::stock("AAPL").build();
let subscription = client.contract_details_stream(&contract).subscribe()?;
loop {
match subscription.try_next() {
Some(Ok(item)) => println!("{item:?}"),
Some(Err(e)) => return Err(e),
None if subscription.is_terminated() => break, // stream ended
None => std::thread::sleep(Duration::from_millis(100)), // nothing yet
}
}Thanks to @tradatious for the contribution (#1141).
Extended-hours trading schedules (#1147)
historical_schedules(..).trading_hours(TradingHours::Extended) (sync and async) returns a product's full session instead of regular trading hours only. For example, ES gives 17:00 (prior day) – 16:00 CT instead of 08:30–16:00, and AAPL 04:00–20:00 ET instead of 09:30–16:00. An extended futures session is dated by its trade date, so the session dated Monday opens Sunday evening. The default is still TradingHours::Regular.
use ibapi::prelude::*;
use ibapi::market_data::historical::ToDuration;
let es = Contract::futures("ES").next_quarter().on_exchange("CME").build();
let schedule = client
.historical_schedules(&es, 5.days())
.trading_hours(TradingHours::Extended)
.fetch()?;
for session in &schedule.sessions {
// e.g. 2026-11-02: 2026-11-01 17:00 CT -> 2026-11-02 16:00 CT
println!("{}: {} -> {}", session.reference, session.start, session.end);
}Thanks to @garnermccloud for the contribution (#1147).
Examples
examples/async/historical_schedules.rsno longer fails on GC futures: it asked for the expired2025-02contract and now uses the front month. It now also compares regular- with extended-hours ES sessions, andexamples/sync/historical_schedules.rstakes--extended(#1149).
See CHANGELOG.md for the full list.