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

wboayue / rust-ibapi / 21299514581

23 Jan 2026 08:01PM UTC coverage: 86.685% (+0.006%) from 86.679%
21299514581

push

github

web-flow
fix: prevent bracket/OCA order ID collisions (#375)

Reserve all order IDs upfront by calling next_order_id() for each
order instead of using base_id + offset calculation.

Fixes #374

0 of 18 new or added lines in 2 files covered. (0.0%)

2 existing lines in 1 file now uncovered.

8698 of 10034 relevant lines covered (86.69%)

117.23 hits per line

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

0.0
/src/orders/builder/async_impl.rs
1
use super::{BracketOrderBuilder, BracketOrderIds, OrderBuilder, OrderId};
2
use crate::client::r#async::Client;
3
use crate::errors::Error;
4
use crate::orders;
5

6
#[cfg(test)]
7
mod tests;
8

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

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

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

35
        // Submit what-if order and get the response
36
        let mut subscription = orders::place_order(client, order_id, contract, &order).await?;
×
37

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

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

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

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

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

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

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

79
            orders::submit_order(client, order_id, contract, &order).await?;
×
80
        }
81

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

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

NEW
124
        for (contract, mut order) in orders.into_iter() {
×
NEW
125
            let order_id = self.next_order_id();
×
126
            order.order_id = order_id;
×
127
            order_ids.push(OrderId::new(order_id));
×
128
            orders::submit_order(self, order_id, &contract, &order).await?;
×
129
        }
130

131
        Ok(order_ids)
×
132
    }
133
}
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