Skip to main content

ibapi/orders/builder/
async_impl.rs

1use super::{BracketOrderBuilder, BracketOrderIds, OrderBuilder, OrderId};
2use crate::client::r#async::Client;
3use crate::errors::Error;
4use crate::orders;
5
6#[cfg(test)]
7mod tests;
8
9impl<'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
51impl<'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
60        let parent_id = client.next_order_id();
61        let tp_id = client.next_order_id();
62        let sl_id = client.next_order_id();
63        let reserved_ids = [parent_id, tp_id, sl_id];
64
65        for (i, mut order) in orders.into_iter().enumerate() {
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 {
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
82        Ok(BracketOrderIds::new(parent_id, tp_id, sl_id))
83    }
84}
85
86/// Extension trait for submitting multiple OCA orders
87impl 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
124        for (contract, mut order) in orders.into_iter() {
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}