Skip to content

v5.6.0

Choose a tag to compare

@wboayue wboayue released this 04 Nov 04:19
· 45 commits to main since this release
04fe672

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.rs no longer fails on GC futures: it asked for the expired 2025-02 contract and now uses the front month. It now also compares regular- with extended-hours ES sessions, and examples/sync/historical_schedules.rs takes --extended (#1149).

See CHANGELOG.md for the full list.