• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wboayue / rust-ibapi / 24230759683

10 Apr 2026 06:56AM UTC coverage: 85.71% (-0.1%) from 85.822%
24230759683

push

github

web-flow
refactor: move Client methods into domain modules (#446)

* clean up CLAUDE.md: fix clippy commands, remove duplication, reorder sections, add branches and doc maintenance policy

* fix: timezone-aware IB timestamp parsing and StreamDecoder dedup (#443)

* fix: handle IB formatted timestamps and optional realtime integer fields

* fix clippy needless_borrow warnings for NEW_YORK references

* deduplicate StreamDecoder impls and next_date_time method

- next_date_time delegates to next_date_time_with_timezone(None), remove parse_ib_date_time wrapper
- move StreamDecoder impls for BidAsk, MidPoint, Bar, Trade, MarketDepths, TickTypes from async.rs to mod.rs, remove cfg guards since one of sync/async is always enabled

* revert optional int decoding — C# reference uses ReadInt() for all fields

* rename decode_head_timestamp_with_timezone to decode_head_timestamp

* add embedded timezone tests, error on unrecognized tz, use skip() in tests, add double-space comment

---------

Co-authored-by: Wil Boayue <wil.boayue@gmail.com>

* require PRs for changes to main and v2-stable

* fix: add-british-summer-time-zone-mapping (#445)

* fix: add-british-summer-time-zone-mapping

* refactor timezone mapping to table-driven lookup

---------

Co-authored-by: kinz <keith.kinz@gmail.com>
Co-authored-by: Wil Boayue <wil.boayue@gmail.com>

* fix: improve error context for parsing failures (#440)

* fix(messages): improve error context for parsing failures

- Wrap parse() calls in next_date_time() with Error::Parse to include field index and value
- Fix parse_unix_timestamp() to provide error context instead of generic ParseIntError
- Fix parse_bar_date() to provide error context instead of generic ParseIntError

This changes error messages from:
  'invalid digit found in string'
to:
  'parse error: <field_index> - <field_value> - <parse_error>'

Making it much easier to debug which IBKR message field is causing parsing issues.

Fixes issues where symbols like GOOGL, BT... (continued)

1013 of 1177 new or added lines in 27 files covered. (86.07%)

2 existing lines in 1 file now uncovered.

8781 of 10245 relevant lines covered (85.71%)

124.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/orders/builder/sync_impl.rs
1
use super::{BracketOrderBuilder, BracketOrderIds, OrderBuilder, OrderId};
2
use crate::client::sync::Client;
3
use crate::contracts::Contract;
4
use crate::errors::Error;
5
#[cfg(test)]
6
mod tests;
7

8
impl<'a> OrderBuilder<'a, Client> {
9
    /// Submit the order synchronously
10
    /// Returns the order ID assigned to the submitted order
11
    pub fn submit(self) -> Result<OrderId, Error> {
×
12
        let client = self.client;
×
13
        let contract = self.contract;
×
14
        let order_id = client.next_order_id();
×
15
        let order = self.build()?;
×
NEW
16
        client.submit_order(order_id, contract, &order)?;
×
17
        Ok(OrderId::new(order_id))
×
18
    }
19

20
    /// Build the order and return it without submitting
21
    /// Useful for batch operations or custom submission logic
22
    pub fn build_order(self) -> Result<crate::orders::Order, Error> {
×
23
        self.build().map_err(Into::into)
×
24
    }
25

26
    /// Analyze order for margin/commission (what-if)
27
    pub fn analyze(mut self) -> Result<crate::orders::OrderState, Error> {
×
28
        self.what_if = true;
×
29
        let client = self.client;
×
30
        let contract = self.contract;
×
31
        let order_id = client.next_order_id();
×
32
        let order = self.build()?;
×
33

34
        // Submit what-if order and get the response
NEW
35
        let responses = client.place_order(order_id, contract, &order)?;
×
36

37
        // Look for the order state in the responses
38
        for response in responses {
×
39
            if let crate::orders::PlaceOrder::OpenOrder(order_data) = response {
×
40
                if order_data.order_id == order_id {
×
41
                    return Ok(order_data.order_state);
×
42
                }
43
            }
44
        }
45

46
        Err(Error::Simple("What-if analysis did not return order state".to_string()))
×
47
    }
48
}
49

50
impl<'a> BracketOrderBuilder<'a, Client> {
51
    /// Submit bracket orders synchronously
52
    /// Returns BracketOrderIds containing all three order IDs
53
    pub fn submit_all(self) -> Result<BracketOrderIds, Error> {
×
54
        let client = self.parent_builder.client;
×
55
        let contract = self.parent_builder.contract;
×
56
        let orders = self.build()?;
×
57

58
        // Reserve all order IDs upfront to prevent collisions
59
        let parent_id = client.next_order_id();
×
60
        let tp_id = client.next_order_id();
×
61
        let sl_id = client.next_order_id();
×
62
        let reserved_ids = [parent_id, tp_id, sl_id];
×
63

64
        for (i, mut order) in orders.into_iter().enumerate() {
×
65
            let order_id = reserved_ids[i];
×
66
            order.order_id = order_id;
×
67

68
            // Update parent_id for child orders
69
            if i > 0 {
×
70
                order.parent_id = parent_id;
×
71
            }
72

73
            // Only transmit the last order
74
            if i == 2 {
×
75
                order.transmit = true;
×
76
            }
77

NEW
78
            client.submit_order(order_id, contract, &order)?;
×
79
        }
80

81
        Ok(BracketOrderIds::new(parent_id, tp_id, sl_id))
×
82
    }
83
}
84

85
/// Extension trait for submitting multiple OCA orders
86
impl Client {
87
    /// Submit multiple OCA (One-Cancels-All) orders
88
    ///
89
    /// When one order in the group is filled, all others are automatically cancelled.
90
    ///
91
    /// # Example
92
    /// ```no_run
93
    /// use ibapi::client::blocking::Client;
94
    /// use ibapi::contracts::Contract;
95
    ///
96
    /// let client = Client::connect("127.0.0.1:4002", 100).expect("connection failed");
97
    ///
98
    /// let contract1 = Contract::stock("AAPL").build();
99
    /// let contract2 = Contract::stock("MSFT").build();
100
    ///
101
    /// let order1 = client.order(&contract1)
102
    ///     .buy(100)
103
    ///     .limit(50.0)
104
    ///     .oca_group("MyOCA", 1)
105
    ///     .build_order().expect("order build failed");
106
    ///     
107
    /// let order2 = client.order(&contract2)
108
    ///     .buy(100)
109
    ///     .limit(45.0)
110
    ///     .oca_group("MyOCA", 1)
111
    ///     .build_order().expect("order build failed");
112
    ///
113
    /// let order_ids = client.submit_oca_orders(
114
    ///     vec![(contract1, order1), (contract2, order2)]
115
    /// ).expect("OCA submission failed");
116
    /// ```
117
    pub fn submit_oca_orders(&self, orders: Vec<(Contract, crate::orders::Order)>) -> Result<Vec<OrderId>, Error> {
×
118
        let mut order_ids = Vec::new();
×
119

120
        for (contract, mut order) in orders.into_iter() {
×
121
            let order_id = self.next_order_id();
×
122
            order.order_id = order_id;
×
123
            order_ids.push(OrderId::new(order_id));
×
NEW
124
            self.submit_order(order_id, &contract, &order)?;
×
125
        }
126

127
        Ok(order_ids)
×
128
    }
129
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc