Skip to content

v5.1.0

Latest

Choose a tag to compare

@wboayue wboayue released this 12 Oct 00:18
· 17 commits to main since this release
726407c

5.1 adds order fill waits, account summary snapshots, an opt-in outbound rate limiter, and time bounds for requests that end, plus TCP-shutdown and historical-data fixes. No breaking changes; a few constants are deprecated ahead of 6.0.

What's New

Wait for an order to fill (#951)

wait_for_fill returns once the order fills, is cancelled or becomes inactive, is rejected, or the timeout elapses. A timeout leaves the order working.

let order_id = client.order(&contract).buy(100).market().submit()?;

match client.wait_for_fill(order_id, Duration::from_secs(30))? {
    OrderOutcome::Filled(status) => println!("filled {} @ {:?}", status.filled, status.average_fill_price),
    OrderOutcome::Ended(status) => println!("ended {} after {} filled", status.status, status.filled),
    OrderOutcome::Rejected(notice) => eprintln!("rejected: {notice}"),
    OrderOutcome::TimedOut(status) => println!("still working: {status:?}"),
}

order_status_stream(order_id) streams one order's statuses, starting with the latest one this client has seen, and OrderStatus::outcome() gives the same rule for your own waits.

Account summary snapshots (#957, #977)

account_summary_snapshots yields the latest value of every row by account, tag and currency. TWS sends End only after the first dump, so later snapshots close when no row has arrived for quiet.

let snapshots = client.account_summary_snapshots(&group, &[AccountSummaryTags::NET_LIQUIDATION], Duration::from_secs(1))?;
for snapshot in snapshots {
    println!("{} rows", snapshot?.len());
}

The batching behind it is now generic: Subscription::next_batch(quiet) works on positions, account updates and the other streams that dump and then push. Thanks to @faysou for the contribution.

Outbound rate limiter (#950)

Opt-in cap on the messages a client sends. Over-budget sends wait rather than fail, and clones share one budget across clients of the same gateway.

let client = Client::builder()
    .address("127.0.0.1:4002")
    .client_id(100)
    .rate_limiter(RateLimiter::per_second(40))
    .connect()?;

Time-bound requests that end (#965)

collect_to_end_within(timeout) collects until TWS's end marker or fails with the new Error::Timeout.

let subscription = client.contract_details_stream(&contract).subscribe()?;
match subscription.collect_to_end_within(Duration::from_secs(30)) {
    Ok(details) => println!("{} contracts", details.len()),
    Err(Error::Timeout) => eprintln!("no answer in 30s"), // drop sends the cancel
    Err(e) => eprintln!("request failed: {e}"),
}

Thanks to @spoxus for the question that led to it.

More

  • buffer_limit(n) and request_id() on OptionChainBuilder, and buffer_limit(n) on HistoricalDataBuilder::stream(); subscriptions::MAX_BUFFER_LIMIT (#902).
  • generic_tick::ETF_FROZEN_NAV_LAST ("623", tick 97). Thanks to @tradatious for the contribution (#946).
  • Time zone aliases BRT and Brasilia Standard Time, sent by pt-BR gateways. Thanks to @milkway for the report (#964).
  • client::blocking exports the blocking TickSubscription, its iterators and DisplayGroupSubscription. Thanks to @tradatious for the contribution (#958).

Bug Fixes

Disconnect closes the TCP connection (#966, #979)

disconnect() and dropping the client now close the socket even while subscriptions or client clones are still held, on both the async and blocking clients. Before, TWS could keep the session open. Thanks to @mjarvel for the async fix.

Historical downloads require the end marker (#967)

historical_data(..).fetch() used to return bars as complete, with start/end at the epoch, when the response closed early. It now returns UnexpectedEndOfStream. Thanks to @mjarvel for the contribution.

Blocking news cancels (#947)

Cancelling or dropping a blocking contract_news / broad_tape_news subscription now sends cancelMktData, as async already did. Thanks to @tradatious for the contribution.

Also fixed

  • place_order returns Error::ServerVersion for Order::deactivate below server 216 and route_marketable_to_bbo below 217, instead of sending them unchecked (#978).
  • The blocking order_update_stream() can be reopened right after cancel() (#932).

Deprecated

  • 53 protocol::Features constants at or below server version 213, the connection floor; they always pass and will be removed in 6.0 (#990).
  • contracts::MAX_BUFFER_LIMIT: use subscriptions::MAX_BUFFER_LIMIT.
  • generic_tick::ETF_NAV_FROZEN_LAST ("578") and ETF_NAV_BID ("576"), which TWS rejects. Use ETF_FROZEN_NAV_LAST for tick 97.

See CHANGELOG.md for the full list.

Thanks to @tradatious for the internal cleanups in this release as well (#959, #960, #961, #962).