1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
use super::order_builder::{AttachedOrdersBuilder, BracketOrderBuilder, ClientBound, OrderBuilder};
use super::types::{AttachedOrderIds, BracketOrderIds};
use crate::client::sync::Client;
use crate::contracts::Contract;
use crate::errors::Error;
use crate::orders::OrderId;
use crate::orders::PlaceOrder;
impl OrderBuilder<ClientBound<'_, Client>> {
/// Submit the order synchronously
/// Returns the order ID assigned to the submitted order
pub fn submit(self) -> Result<OrderId, Error> {
let ClientBound { client, contract } = self.target;
let order_id = client.next_order_id();
let order = self.build()?;
client.submit_order(order_id, contract, &order)?;
Ok(OrderId::new(order_id))
}
/// Build the order and return it without submitting
/// Useful for batch operations or custom submission logic
pub fn build_order(self) -> Result<crate::orders::Order, Error> {
self.build().map_err(Into::into)
}
/// Analyze order for margin/commission (what-if)
pub fn analyze(mut self) -> Result<crate::orders::OrderState, Error> {
self.what_if = true;
let ClientBound { client, contract } = self.target;
let order_id = client.next_order_id();
let order = self.build()?;
// Submit what-if order and get the response
let responses = client.place_order(order_id, contract, &order)?;
// Look for the order state in the responses. `?` propagates a rejected
// what-if order; the earlier `if let Ok(..)` read discarded it, so the
// caller saw `UnexpectedEndOfStream` instead of TWS's reason (#735).
for response in responses.iter_data() {
if let PlaceOrder::OpenOrder(order_data) = response? {
if order_data.order_id == order_id {
return Ok(order_data.order_state);
}
}
}
Err(Error::UnexpectedEndOfStream)
}
}
impl BracketOrderBuilder<'_, Client> {
/// Submit bracket orders synchronously
/// Returns BracketOrderIds containing all three order IDs
pub fn submit_all(self) -> Result<BracketOrderIds, Error> {
let ClientBound { client, contract } = self.parent_builder.target;
let orders = self.build()?;
// Reserve all order IDs upfront to prevent collisions
let parent_id = client.next_order_id();
let tp_id = client.next_order_id();
let sl_id = client.next_order_id();
let reserved_ids = [parent_id, tp_id, sl_id];
for (i, mut order) in orders.into_iter().enumerate() {
let order_id = reserved_ids[i];
order.order_id = order_id;
// Update parent_id for child orders
if i > 0 {
order.parent_id = parent_id;
}
// Only transmit the last order
if i == 2 {
order.transmit = true;
}
client.submit_order(order_id, contract, &order)?;
}
Ok(BracketOrderIds::new(parent_id, tp_id, sl_id))
}
}
impl AttachedOrdersBuilder<'_, Client> {
/// Submit the order with its preset children synchronously.
///
/// Allocates the parent id, then one id per requested child, and sends a single
/// place-order request. Fire-and-forget: whether TWS attached the children shows up only
/// on the order update stream — see [`Order::preset_stop_loss_order_id`](crate::orders::Order::preset_stop_loss_order_id).
///
/// # Examples
///
/// ```no_run
/// use ibapi::client::blocking::Client;
/// use ibapi::contracts::Contract;
///
/// let client = Client::connect("127.0.0.1:4002", 100).expect("connection failed");
/// let contract = Contract::stock("AAPL").build();
/// let ids = client
/// .order(&contract)
/// .buy(100)
/// .limit(150.0)
/// .preset_stop_loss()
/// .preset_profit_taker()
/// .submit()
/// .expect("submit failed");
/// println!("parent {} stop-loss {:?} profit-taker {:?}", ids.parent, ids.stop_loss, ids.profit_taker);
/// ```
pub fn submit(self) -> Result<AttachedOrderIds, Error> {
let ClientBound { client, contract } = self.parent_builder.target;
let (order, ids) = self.build_with_ids(|| client.next_order_id())?;
client.submit_order(order.order_id, contract, &order)?;
Ok(ids)
}
}
/// Submitting several OCA orders in one call.
impl Client {
/// Submit multiple OCA (One-Cancels-All) orders
///
/// When one order in the group is filled, all others are automatically cancelled.
///
/// # Example
/// ```no_run
/// use ibapi::client::blocking::Client;
/// use ibapi::contracts::Contract;
/// use ibapi::orders::OcaType;
///
/// let client = Client::connect("127.0.0.1:4002", 100).expect("connection failed");
///
/// let contract1 = Contract::stock("AAPL").build();
/// let contract2 = Contract::stock("MSFT").build();
///
/// let order1 = client.order(&contract1)
/// .buy(100)
/// .limit(50.0)
/// .oca_group("MyOCA", OcaType::CancelWithBlock)
/// .build_order().expect("order build failed");
///
/// let order2 = client.order(&contract2)
/// .buy(100)
/// .limit(45.0)
/// .oca_group("MyOCA", OcaType::CancelWithBlock)
/// .build_order().expect("order build failed");
///
/// let order_ids = client.submit_oca_orders(
/// vec![(contract1, order1), (contract2, order2)]
/// ).expect("OCA submission failed");
/// ```
pub fn submit_oca_orders(&self, orders: Vec<(Contract, crate::orders::Order)>) -> Result<Vec<OrderId>, Error> {
let mut order_ids = Vec::new();
for (contract, mut order) in orders.into_iter() {
let order_id = self.next_order_id();
order.order_id = order_id;
order_ids.push(OrderId::new(order_id));
self.submit_order(order_id, &contract, &order)?;
}
Ok(order_ids)
}
}