Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- `orders::TimeInForce` variants are spelled "till", matching IB's `goodTillDate`, `Order.good_till_date` and the builder setters: `GoodTilCanceled` → `GoodTillCanceled`, `GoodTilDate` → `GoodTillDate`, `DayTilCanceled` → `DayTillCanceled`. Wire strings are unchanged (#822).
- `OrderBuilder::time_in_force` takes `orders::TimeInForce`; exhaustive matches on `orders::TimeInForce` need `GoodTillCrossing` and `Unknown(raw)` arms. See `docs/migration-4.0.md` §13 (#822).
- `OrderBuilder::good_till_cancel()` is renamed `good_till_canceled()`, matching the `TimeInForce::GoodTillCanceled` variant it sets and the neighbouring `day_till_canceled()` (#826).
- `orders::TimeInForce` serializes as the TWS wire string (`"GTC"`) rather than the variant name (`"GoodTilCanceled"`), in both directions, and its `utoipa` schema is a plain string — matching `OrderStatusKind`. Stored JSON and downstream consumers that read the old variant names need updating (#822).

### Removed
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ pub fn main() {
let order_id = client.order(&contract)
.sell(50)
.limit(150.00)
.good_till_cancel()
.good_till_canceled()
.outside_rth()
.submit()
.expect("order submission failed!");
Expand Down
4 changes: 2 additions & 2 deletions docs/migration-4.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ Rename the variants from either 3.x enum:
| `Auction` | `Auction` | `Auction` |
| `OpeningAuction` | `OnOpen` | `OnOpen` |

The named setters (`.day_order()`, `.good_till_cancel()`, `.good_till_date(..)`, `.fill_or_kill()`, `.immediate_or_cancel()`) are unchanged, and `.good_till_crossing()` and `.day_till_canceled()` are added. `.time_in_force(TimeInForce::GoodTillDate)` without a date still fails `build()` with `ValidationError::MissingRequiredField("good_till_date")`. The builder keeps the GTD date only in the field written by `.good_till_date(..)` / `.good_till_time(..)`; in 3.x a date carried in the `GoodTillDate { date }` payload took precedence over one set through those methods; now the last one set wins.
The named setters (`.day_order()`, `.good_till_date(..)`, `.fill_or_kill()`, `.immediate_or_cancel()`) are unchanged; `.good_till_cancel()` is renamed `.good_till_canceled()`, matching the variant it sets and its `.day_till_canceled()` neighbour, and `.good_till_crossing()` and `.day_till_canceled()` are added. `.time_in_force(TimeInForce::GoodTillDate)` without a date still fails `build()` with `ValidationError::MissingRequiredField("good_till_date")`. The builder keeps the GTD date only in the field written by `.good_till_date(..)` / `.good_till_time(..)`; in 3.x a date carried in the `GoodTillDate { date }` payload took precedence over one set through those methods; now the last one set wins.

`orders::TimeInForce` is also an open enum now, like `OrderStatusKind` in [§9](#9-orderstatuskind-gains-unknownstring): a TIF string this crate does not model decodes as `Unknown(raw)` carrying the value TWS sent, instead of being coerced to `Day`. Sending an `Unknown` back — through `.time_in_force(..)` or `Order.tif` — puts the raw string on the wire unchanged, so an order read from TWS round-trips. Matching is exact and case-sensitive, so a case-variant such as `"gtc"` lands in `Unknown` rather than being coerced to the nearest known variant.

Expand Down Expand Up @@ -406,7 +406,7 @@ No code changes required, but observable at runtime:
10. If you serialize market-data types to JSON, update downstream consumers: sizes are now `number | null` instead of `integer`, and notices may carry `request_id`.
11. Add an `OrderUpdate::OrderBound(binding)` arm to exhaustive matches on order updates, and read bindings from `order_update_stream()` — they never reach `place_order` subscriptions; see [§11](#11-orderupdate-gains-orderbound).
12. Replace any `Subscription::new(rx)` over your own channel with `tokio_stream::wrappers::UnboundedReceiverStream::new(rx)` (add `tokio-stream` to your dependencies), and give any generic helper over the async `Subscription<T>` a concrete item type — see [§12](#12-the-async-subscriptionnewreceiver-constructor-is-removed).
13. Use `ibapi::orders::TimeInForce` everywhere (`ibapi::orders::builder::TimeInForce` is gone) and spell the variants "till": `GoodTilCanceled` → `GoodTillCanceled`, `GoodTilDate` → `GoodTillDate`, `DayTilCanceled` → `DayTillCanceled`; from the builder enum, `GoodTillCancel` → `GoodTillCanceled`, `OpeningAuction` → `OnOpen`, `GoodTillDate { date }` → `GoodTillDate` plus `.good_till_date(date)`. Add `GoodTillCrossing` and `Unknown(raw)` arms to exhaustive matches, and re-read any stored JSON — the field is the wire string now — see [§13](#13-one-timeinforce-ordersbuildertimeinforce-is-removed-and-the-variants-are-spelled-till).
13. Use `ibapi::orders::TimeInForce` everywhere (`ibapi::orders::builder::TimeInForce` is gone) and spell the variants "till": `GoodTilCanceled` → `GoodTillCanceled`, `GoodTilDate` → `GoodTillDate`, `DayTilCanceled` → `DayTillCanceled`; from the builder enum, `GoodTillCancel` → `GoodTillCanceled`, `OpeningAuction` → `OnOpen`, `GoodTillDate { date }` → `GoodTillDate` plus `.good_till_date(date)`. Rename `.good_till_cancel()` calls to `.good_till_canceled()`, add `GoodTillCrossing` and `Unknown(raw)` arms to exhaustive matches, and re-read any stored JSON — the field is the wire string now — see [§13](#13-one-timeinforce-ordersbuildertimeinforce-is-removed-and-the-variants-are-spelled-till).
14. Re-run `cargo fmt`, `cargo clippy --all-targets --all-features -- -D warnings`, and your test suite for each feature flag you support.

## Need help?
Expand Down
4 changes: 2 additions & 2 deletions docs/order-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ let order_id = client.order(&contract)
.and_condition(volume(265598, "SMART").greater_than(80_000_000))
.and_condition(time().greater_than("20251230 10:00:00 US/Eastern"))
.and_condition(margin().greater_than(40))
.good_till_cancel()
.good_till_canceled()
.submit()?;
```

Expand Down Expand Up @@ -1217,7 +1217,7 @@ Control how long an order remains active:
let order_id = client.order(&contract)
.buy(100)
.limit(150.00)
.good_till_cancel()
.good_till_canceled()
.submit()?;

// Good till specific date
Expand Down
2 changes: 1 addition & 1 deletion src/orders/async_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ async fn submit_all_reserves_three_ids_and_wires_the_bracket() {
let ids = client
.order(&contract)
.buy(100)
.good_till_cancel()
.good_till_canceled()
.bracket()
.entry_limit(50.0)
.take_profit(55.0)
Expand Down
6 changes: 3 additions & 3 deletions src/orders/builder/order_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,8 +422,8 @@ impl<'a, C> OrderBuilder<'a, C> {
self
}

/// Good till cancelled order
pub fn good_till_cancel(mut self) -> Self {
/// Good till canceled order
pub fn good_till_canceled(mut self) -> Self {
self.time_in_force = TimeInForce::GoodTillCanceled;
self
}
Expand All @@ -441,7 +441,7 @@ impl<'a, C> OrderBuilder<'a, C> {
self
}

/// Day till cancelled order
/// Day till canceled order
pub fn day_till_canceled(mut self) -> Self {
self.time_in_force = TimeInForce::DayTillCanceled;
self
Expand Down
4 changes: 2 additions & 2 deletions src/orders/builder/order_builder/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ fn test_time_conditions() {
assert_eq!(order.tif, TimeInForce::Day);

// Test Good Till Cancel
let builder = OrderBuilder::new(&client, &contract).buy(100).market().good_till_cancel();
let builder = OrderBuilder::new(&client, &contract).buy(100).market().good_till_canceled();

let order = builder.build().unwrap();
assert_eq!(order.tif, TimeInForce::GoodTillCanceled);
Expand Down Expand Up @@ -1447,7 +1447,7 @@ fn bracket_order_propagates_tif() {

let orders = OrderBuilder::new(&client, &contract)
.buy(100)
.good_till_cancel()
.good_till_canceled()
.bracket()
.entry_limit(50.0)
.take_profit(55.0)
Expand Down
2 changes: 1 addition & 1 deletion src/orders/sync_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,7 @@ fn submit_all_reserves_three_ids_and_wires_the_bracket() {
let ids = client
.order(&contract)
.buy(100)
.good_till_cancel()
.good_till_canceled()
.bracket()
.entry_limit(50.0)
.take_profit(55.0)
Expand Down
Loading