1use prost::Message;
16use tokio::sync::oneshot;
17
18use crate::payload;
19use crate::proto::common::*;
20use crate::{client::Client, error::Error};
21
22impl Client {
25 async fn send_order(&self, req: ProtoOaNewOrderReq) -> Result<ProtoOaExecutionEvent, Error> {
40 let (_tx, rx) = oneshot::channel::<Result<ProtoOaExecutionEvent, crate::error::Error>>();
42 let mut payload_bytes = Vec::new();
46 req.encode(&mut payload_bytes)?;
47
48 let envelope = ProtoMessage {
51 payload_type: payload::OA_NEW_ORDER_REQ as u32,
52 payload: Some(payload_bytes),
53 client_msg_id: None,
54 };
55
56 let mut frame = Vec::new();
57 envelope.encode(&mut frame)?;
58 self.transport.send(&frame).await?;
59
60 tokio::time::timeout(self.config.deadline, rx)
61 .await
62 .map_err(|_| Error::Timeout)?
63 .map_err(|_| Error::Disconnected)?
64 }
65
66 pub async fn new_market_order(
83 &self,
84 ctid_trader_account_id: i64,
85 symbol_id: i64,
86 trade_side: ProtoOaTradeSide,
87 volume: i64,
88 ) -> Result<ProtoOaExecutionEvent, Error> {
89 self.send_order(ProtoOaNewOrderReq {
90 ctid_trader_account_id,
91 symbol_id,
92 trade_side: trade_side as i32,
93 volume,
94 order_type: ProtoOaOrderType::Market as i32,
95 payload_type: Some(payload::OA_NEW_ORDER_REQ as i32),
96 ..Default::default()
97 })
98 .await
99 }
100
101 pub async fn new_market_order_with_sltp(
117 &self,
118 ctid_trader_account_id: i64,
119 symbol_id: i64,
120 trade_side: ProtoOaTradeSide,
121 volume: i64,
122 relative_stop_loss: i64,
123 relative_take_profit: i64,
124 ) -> Result<ProtoOaExecutionEvent, Error> {
125 self.send_order(ProtoOaNewOrderReq {
126 ctid_trader_account_id,
127 symbol_id,
128 trade_side: trade_side as i32,
129 volume,
130 order_type: ProtoOaOrderType::Market as i32,
131 relative_stop_loss: Some(relative_stop_loss),
132 relative_take_profit: Some(relative_take_profit),
133 payload_type: Some(payload::OA_NEW_ORDER_REQ as i32),
134 ..Default::default()
135 })
136 .await
137 }
138
139 pub async fn new_market_order_with_trailing_sl(
152 &self,
153 ctid_trader_account_id: i64,
154 symbol_id: i64,
155 trade_side: ProtoOaTradeSide,
156 volume: i64,
157 relative_stop_loss: i64,
158 ) -> Result<ProtoOaExecutionEvent, Error> {
159 self.send_order(ProtoOaNewOrderReq {
160 ctid_trader_account_id,
161 symbol_id,
162 trade_side: trade_side as i32,
163 volume,
164 order_type: ProtoOaOrderType::Market as i32,
165 relative_stop_loss: Some(relative_stop_loss),
166 trailing_stop_loss: Some(true),
167 payload_type: Some(payload::OA_NEW_ORDER_REQ as i32),
168 ..Default::default()
169 })
170 .await
171 }
172
173 pub async fn new_market_range_order(
186 &self,
187 ctid_trader_account_id: i64,
188 symbol_id: i64,
189 trade_side: ProtoOaTradeSide,
190 volume: i64,
191 base_slippage_price: f64,
192 slippage_in_points: i32,
193 ) -> Result<ProtoOaExecutionEvent, Error> {
194 self.send_order(ProtoOaNewOrderReq {
195 volume,
196 symbol_id,
197 ctid_trader_account_id,
198 trade_side: trade_side as i32,
199 slippage_in_points: Some(slippage_in_points),
200 base_slippage_price: Some(base_slippage_price),
201 order_type: ProtoOaOrderType::MarketRange as i32,
202 payload_type: Some(payload::OA_NEW_ORDER_REQ as i32),
203 ..Default::default()
204 })
205 .await
206 }
207
208 pub async fn new_limit_order(
223 &self,
224 ctid_trader_account_id: i64,
225 symbol_id: i64,
226 trade_side: ProtoOaTradeSide,
227 volume: i64,
228 limit_price: f64,
229 stop_loss: Option<f64>,
230 take_profit: Option<f64>,
231 ) -> Result<ProtoOaExecutionEvent, Error> {
232 self.send_order(ProtoOaNewOrderReq {
233 volume,
234 symbol_id,
235 stop_loss,
236 take_profit,
237 ctid_trader_account_id,
238 limit_price: Some(limit_price),
239 trade_side: trade_side as i32,
240 order_type: ProtoOaOrderType::Limit as i32,
241 payload_type: Some(payload::OA_NEW_ORDER_REQ as i32),
242 ..Default::default()
243 })
244 .await
245 }
246
247 pub async fn new_stop_order(
262 &self,
263 ctid_trader_account_id: i64,
264 symbol_id: i64,
265 trade_side: ProtoOaTradeSide,
266 volume: i64,
267 stop_price: f64,
268 stop_loss: Option<f64>,
269 take_profit: Option<f64>,
270 ) -> Result<ProtoOaExecutionEvent, Error> {
271 self.send_order(ProtoOaNewOrderReq {
272 volume,
273 symbol_id,
274 stop_loss,
275 take_profit,
276 ctid_trader_account_id,
277 stop_price: Some(stop_price),
278 trade_side: trade_side as i32,
279 order_type: ProtoOaOrderType::Stop as i32,
280 payload_type: Some(payload::OA_NEW_ORDER_REQ as i32),
281 ..Default::default()
282 })
283 .await
284 }
285
286 pub async fn new_stop_limit_order(
300 &self,
301 ctid_trader_account_id: i64,
302 symbol_id: i64,
303 trade_side: ProtoOaTradeSide,
304 volume: i64,
305 stop_price: f64,
306 slippage_in_points: i32,
307 stop_loss: Option<f64>,
308 take_profit: Option<f64>,
309 ) -> Result<ProtoOaExecutionEvent, Error> {
310 self.send_order(ProtoOaNewOrderReq {
311 volume,
312 symbol_id,
313 stop_loss,
314 take_profit,
315 ctid_trader_account_id,
316 stop_price: Some(stop_price),
317 trade_side: trade_side as i32,
318 slippage_in_points: Some(slippage_in_points),
319 order_type: ProtoOaOrderType::StopLimit as i32,
320 payload_type: Some(payload::OA_NEW_ORDER_REQ as i32),
321 ..Default::default()
322 })
323 .await
324 }
325
326 pub async fn cancel_order(
344 &self,
345 ctid_trader_account_id: i64,
346 order_id: i64,
347 ) -> Result<ProtoOaExecutionEvent, Error> {
348 let req = ProtoOaCancelOrderReq {
349 order_id,
350 ctid_trader_account_id,
351 payload_type: Some(payload::OA_CANCEL_ORDER_REQ as i32),
352 };
353
354 self.command(
355 payload::OA_CANCEL_ORDER_REQ,
356 req,
357 payload::OA_EXECUTION_EVENT,
358 )
359 .await
360 }
361
362 pub async fn amend_order(
381 &self,
382 ctid_trader_account_id: i64,
383 order_id: i64,
384 volume: Option<i64>,
385 limit_price: Option<f64>,
386 stop_price: Option<f64>,
387 stop_loss: Option<f64>,
388 take_profit: Option<f64>,
389 trailing_stop_loss: Option<bool>,
390 expiration_timestamp: Option<i64>,
391 ) -> Result<ProtoOaExecutionEvent, Error> {
392 let req = ProtoOaAmendOrderReq {
393 order_id,
394 volume,
395 limit_price,
396 stop_price,
397 stop_loss,
398 take_profit,
399 trailing_stop_loss,
400 expiration_timestamp,
401 ctid_trader_account_id,
402 payload_type: Some(payload::OA_AMEND_ORDER_REQ as i32),
403 ..Default::default()
404 };
405 self.command(
406 payload::OA_AMEND_ORDER_REQ,
407 req,
408 payload::OA_EXECUTION_EVENT,
409 )
410 .await
411 }
412
413 pub async fn reconcile(
429 &self,
430 ctid_trader_account_id: i64,
431 return_protection_orders: bool,
432 ) -> Result<ProtoOaReconcileRes, Error> {
433 let req = ProtoOaReconcileReq {
434 ctid_trader_account_id,
435 payload_type: Some(payload::OA_RECONCILE_REQ as i32),
436 return_protection_orders: Some(return_protection_orders),
437 };
438 self.command(payload::OA_RECONCILE_REQ, req, payload::OA_RECONCILE_RES)
439 .await
440 }
441
442 pub async fn order_list(
457 &self,
458 ctid_trader_account_id: i64,
459 from_timestamp: Option<i64>,
460 to_timestamp: Option<i64>,
461 ) -> Result<ProtoOaOrderListRes, Error> {
462 let req = ProtoOaOrderListReq {
463 to_timestamp,
464 from_timestamp,
465 ctid_trader_account_id,
466 payload_type: Some(payload::OA_ORDER_LIST_REQ as i32),
467 };
468 self.command(payload::OA_ORDER_LIST_REQ, req, payload::OA_ORDER_LIST_RES)
469 .await
470 }
471
472 pub async fn order_details(
488 &self,
489 ctid_trader_account_id: i64,
490 order_id: i64,
491 ) -> Result<ProtoOaOrderDetailsRes, Error> {
492 let req = ProtoOaOrderDetailsReq {
493 order_id,
494 ctid_trader_account_id,
495 payload_type: Some(payload::OA_ORDER_DETAILS_REQ as i32),
496 };
497 self.command(
498 payload::OA_ORDER_DETAILS_REQ,
499 req,
500 payload::OA_ORDER_DETAILS_RES,
501 )
502 .await
503 }
504
505 pub async fn get_order_list_by_position(
522 &self,
523 ctid_trader_account_id: i64,
524 position_id: i64,
525 from_timestamp: Option<i64>,
526 to_timestamp: Option<i64>,
527 ) -> Result<ProtoOaOrderListByPositionIdRes, Error> {
528 let req = ProtoOaOrderListByPositionIdReq {
529 position_id,
530 to_timestamp,
531 from_timestamp,
532 ctid_trader_account_id,
533 payload_type: Some(payload::OA_ORDER_LIST_BY_POSITION_ID_REQ as i32),
534 };
535 self.command(
536 payload::OA_ORDER_LIST_BY_POSITION_ID_REQ,
537 req,
538 payload::OA_ORDER_LIST_BY_POSITION_ID_RES,
539 )
540 .await
541 }
542}
543
544#[cfg(test)]
545mod tests {
546
547 #[tokio::test]
548 async fn test() {}
549}