Repository navigation
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)andrequest_id()onOptionChainBuilder, andbuffer_limit(n)onHistoricalDataBuilder::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
BRTandBrasilia Standard Time, sent by pt-BR gateways. Thanks to @milkway for the report (#964). client::blockingexports the blockingTickSubscription, its iterators andDisplayGroupSubscription. 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_orderreturnsError::ServerVersionforOrder::deactivatebelow server 216 androute_marketable_to_bbobelow 217, instead of sending them unchecked (#978).- The blocking
order_update_stream()can be reopened right aftercancel()(#932).
Deprecated
- 53
protocol::Featuresconstants at or below server version 213, the connection floor; they always pass and will be removed in 6.0 (#990). contracts::MAX_BUFFER_LIMIT: usesubscriptions::MAX_BUFFER_LIMIT.generic_tick::ETF_NAV_FROZEN_LAST("578") andETF_NAV_BID("576"), which TWS rejects. UseETF_FROZEN_NAV_LASTfor 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).