1use std::borrow::Cow;
2
3use serde::Serialize;
4
5#[derive(Debug, Clone, Default, Serialize)]
7pub struct AttachedAlgoOrderRequest {
8 #[serde(rename = "attachAlgoClOrdId", skip_serializing_if = "Option::is_none")]
9 attach_algo_cl_ord_id: Option<String>,
10 #[serde(rename = "tpTriggerPx", skip_serializing_if = "Option::is_none")]
11 tp_trigger_px: Option<String>,
12 #[serde(rename = "tpTriggerRatio", skip_serializing_if = "Option::is_none")]
13 tp_trigger_ratio: Option<String>,
14 #[serde(rename = "tpTriggerPxType", skip_serializing_if = "Option::is_none")]
15 tp_trigger_px_type: Option<String>,
16 #[serde(rename = "tpOrdPx", skip_serializing_if = "Option::is_none")]
17 tp_ord_px: Option<String>,
18 #[serde(rename = "slTriggerPx", skip_serializing_if = "Option::is_none")]
19 sl_trigger_px: Option<String>,
20 #[serde(rename = "slTriggerRatio", skip_serializing_if = "Option::is_none")]
21 sl_trigger_ratio: Option<String>,
22 #[serde(rename = "slTriggerPxType", skip_serializing_if = "Option::is_none")]
23 sl_trigger_px_type: Option<String>,
24 #[serde(rename = "slOrdPx", skip_serializing_if = "Option::is_none")]
25 sl_ord_px: Option<String>,
26}
27
28impl AttachedAlgoOrderRequest {
29 pub fn new() -> Self {
31 Self::default()
32 }
33
34 pub fn client_algo_order_id(mut self, value: impl Into<String>) -> Self {
36 self.attach_algo_cl_ord_id = Some(value.into());
37 self
38 }
39
40 pub fn take_profit(
42 mut self,
43 trigger_px: impl Into<String>,
44 order_px: impl Into<String>,
45 ) -> Self {
46 self.tp_trigger_px = Some(trigger_px.into());
47 self.tp_ord_px = Some(order_px.into());
48 self
49 }
50
51 pub fn take_profit_ratio(
53 mut self,
54 trigger_ratio: impl Into<String>,
55 order_px: impl Into<String>,
56 ) -> Self {
57 self.tp_trigger_ratio = Some(trigger_ratio.into());
58 self.tp_ord_px = Some(order_px.into());
59 self
60 }
61
62 pub fn take_profit_price_type(mut self, value: impl Into<String>) -> Self {
64 self.tp_trigger_px_type = Some(value.into());
65 self
66 }
67
68 pub fn stop_loss(mut self, trigger_px: impl Into<String>, order_px: impl Into<String>) -> Self {
70 self.sl_trigger_px = Some(trigger_px.into());
71 self.sl_ord_px = Some(order_px.into());
72 self
73 }
74
75 pub fn stop_loss_ratio(
77 mut self,
78 trigger_ratio: impl Into<String>,
79 order_px: impl Into<String>,
80 ) -> Self {
81 self.sl_trigger_ratio = Some(trigger_ratio.into());
82 self.sl_ord_px = Some(order_px.into());
83 self
84 }
85
86 pub fn stop_loss_price_type(mut self, value: impl Into<String>) -> Self {
88 self.sl_trigger_px_type = Some(value.into());
89 self
90 }
91}
92
93#[derive(Debug, Clone, Serialize)]
95pub struct SmartIcebergTriggerRequest {
96 #[serde(rename = "triggerAction")]
97 trigger_action: String,
98 #[serde(rename = "triggerStrategy")]
99 trigger_strategy: String,
100 #[serde(rename = "triggerPx", skip_serializing_if = "Option::is_none")]
101 trigger_px: Option<String>,
102 #[serde(rename = "triggerCond", skip_serializing_if = "Option::is_none")]
103 trigger_cond: Option<String>,
104 #[serde(skip_serializing_if = "Option::is_none")]
105 timeframe: Option<String>,
106 #[serde(skip_serializing_if = "Option::is_none")]
107 thold: Option<String>,
108 #[serde(rename = "timePeriod", skip_serializing_if = "Option::is_none")]
109 time_period: Option<String>,
110}
111
112impl SmartIcebergTriggerRequest {
113 pub fn new(trigger_strategy: impl Into<String>) -> Self {
115 Self {
116 trigger_action: "start".to_owned(),
117 trigger_strategy: trigger_strategy.into(),
118 trigger_px: None,
119 trigger_cond: None,
120 timeframe: None,
121 thold: None,
122 time_period: None,
123 }
124 }
125
126 pub fn price(mut self, trigger_px: impl Into<String>) -> Self {
128 self.trigger_px = Some(trigger_px.into());
129 self
130 }
131
132 pub fn condition(mut self, value: impl Into<String>) -> Self {
134 self.trigger_cond = Some(value.into());
135 self
136 }
137
138 pub fn timeframe(mut self, value: impl Into<String>) -> Self {
140 self.timeframe = Some(value.into());
141 self
142 }
143
144 pub fn threshold(mut self, value: impl Into<String>) -> Self {
146 self.thold = Some(value.into());
147 self
148 }
149
150 pub fn time_period(mut self, value: impl Into<String>) -> Self {
152 self.time_period = Some(value.into());
153 self
154 }
155}
156
157#[derive(Debug, Clone, Serialize)]
159pub struct AlgoOrderRequest {
160 #[serde(rename = "instId")]
161 inst_id: String,
162 #[serde(rename = "tdMode")]
163 td_mode: String,
164 side: String,
165 #[serde(rename = "ordType")]
166 ord_type: String,
167 #[serde(skip_serializing_if = "Option::is_none")]
168 sz: Option<String>,
169 #[serde(skip_serializing_if = "Option::is_none")]
170 ccy: Option<String>,
171 #[serde(rename = "posSide", skip_serializing_if = "Option::is_none")]
172 pos_side: Option<String>,
173 #[serde(rename = "reduceOnly", skip_serializing_if = "Option::is_none")]
174 reduce_only: Option<bool>,
175 #[serde(rename = "algoClOrdId", skip_serializing_if = "Option::is_none")]
176 algo_cl_ord_id: Option<String>,
177 #[serde(rename = "tgtCcy", skip_serializing_if = "Option::is_none")]
178 tgt_ccy: Option<String>,
179 #[serde(rename = "closeFraction", skip_serializing_if = "Option::is_none")]
180 close_fraction: Option<String>,
181 #[serde(rename = "tradeQuoteCcy", skip_serializing_if = "Option::is_none")]
182 trade_quote_ccy: Option<String>,
183 #[serde(rename = "triggerPx", skip_serializing_if = "Option::is_none")]
184 trigger_px: Option<String>,
185 #[serde(rename = "orderPx", skip_serializing_if = "Option::is_none")]
186 order_px: Option<String>,
187 #[serde(rename = "advanceOrdType", skip_serializing_if = "Option::is_none")]
188 advance_ord_type: Option<String>,
189 #[serde(rename = "triggerPxType", skip_serializing_if = "Option::is_none")]
190 trigger_px_type: Option<String>,
191 #[serde(rename = "tpTriggerPx", skip_serializing_if = "Option::is_none")]
192 tp_trigger_px: Option<String>,
193 #[serde(rename = "tpTriggerPxType", skip_serializing_if = "Option::is_none")]
194 tp_trigger_px_type: Option<String>,
195 #[serde(rename = "tpOrdPx", skip_serializing_if = "Option::is_none")]
196 tp_ord_px: Option<String>,
197 #[serde(rename = "tpOrdKind", skip_serializing_if = "Option::is_none")]
198 tp_ord_kind: Option<String>,
199 #[serde(rename = "slTriggerPx", skip_serializing_if = "Option::is_none")]
200 sl_trigger_px: Option<String>,
201 #[serde(rename = "slTriggerPxType", skip_serializing_if = "Option::is_none")]
202 sl_trigger_px_type: Option<String>,
203 #[serde(rename = "slOrdPx", skip_serializing_if = "Option::is_none")]
204 sl_ord_px: Option<String>,
205 #[serde(rename = "cxlOnClosePos", skip_serializing_if = "Option::is_none")]
206 cxl_on_close_pos: Option<bool>,
207 #[serde(rename = "attachAlgoOrds", skip_serializing_if = "Option::is_none")]
208 attach_algo_ords: Option<Vec<AttachedAlgoOrderRequest>>,
209 #[serde(rename = "callbackRatio", skip_serializing_if = "Option::is_none")]
210 callback_ratio: Option<String>,
211 #[serde(rename = "callbackSpread", skip_serializing_if = "Option::is_none")]
212 callback_spread: Option<String>,
213 #[serde(rename = "activePx", skip_serializing_if = "Option::is_none")]
214 active_px: Option<String>,
215 #[serde(rename = "chaseType", skip_serializing_if = "Option::is_none")]
216 chase_type: Option<String>,
217 #[serde(rename = "chaseVal", skip_serializing_if = "Option::is_none")]
218 chase_val: Option<String>,
219 #[serde(rename = "maxChaseType", skip_serializing_if = "Option::is_none")]
220 max_chase_type: Option<String>,
221 #[serde(rename = "maxChaseVal", skip_serializing_if = "Option::is_none")]
222 max_chase_val: Option<String>,
223 #[serde(rename = "pxVar", skip_serializing_if = "Option::is_none")]
224 px_var: Option<String>,
225 #[serde(rename = "pxSpread", skip_serializing_if = "Option::is_none")]
226 px_spread: Option<String>,
227 #[serde(rename = "szLimit", skip_serializing_if = "Option::is_none")]
228 sz_limit: Option<String>,
229 #[serde(rename = "pxLimit", skip_serializing_if = "Option::is_none")]
230 px_limit: Option<String>,
231 #[serde(rename = "timeInterval", skip_serializing_if = "Option::is_none")]
232 time_interval: Option<String>,
233 #[serde(rename = "lmtOrderNumber", skip_serializing_if = "Option::is_none")]
234 lmt_order_number: Option<String>,
235 #[serde(skip_serializing_if = "Option::is_none")]
236 aggressiveness: Option<String>,
237 #[serde(rename = "triggerParams", skip_serializing_if = "Option::is_none")]
238 trigger_params: Option<Vec<SmartIcebergTriggerRequest>>,
239 #[serde(skip_serializing_if = "Option::is_none")]
240 tag: Option<String>,
241}
242
243impl AlgoOrderRequest {
244 pub fn new(
246 inst_id: impl Into<String>,
247 td_mode: impl Into<String>,
248 side: impl Into<String>,
249 ord_type: impl Into<String>,
250 sz: impl Into<String>,
251 ) -> Self {
252 Self {
253 inst_id: inst_id.into(),
254 td_mode: td_mode.into(),
255 side: side.into(),
256 ord_type: ord_type.into(),
257 sz: Some(sz.into()),
258 ccy: None,
259 pos_side: None,
260 reduce_only: None,
261 algo_cl_ord_id: None,
262 tgt_ccy: None,
263 close_fraction: None,
264 trade_quote_ccy: None,
265 trigger_px: None,
266 order_px: None,
267 advance_ord_type: None,
268 trigger_px_type: None,
269 tp_trigger_px: None,
270 tp_trigger_px_type: None,
271 tp_ord_px: None,
272 tp_ord_kind: None,
273 sl_trigger_px: None,
274 sl_trigger_px_type: None,
275 sl_ord_px: None,
276 cxl_on_close_pos: None,
277 attach_algo_ords: None,
278 callback_ratio: None,
279 callback_spread: None,
280 active_px: None,
281 chase_type: None,
282 chase_val: None,
283 max_chase_type: None,
284 max_chase_val: None,
285 px_var: None,
286 px_spread: None,
287 sz_limit: None,
288 px_limit: None,
289 time_interval: None,
290 lmt_order_number: None,
291 aggressiveness: None,
292 trigger_params: None,
293 tag: None,
294 }
295 }
296
297 pub fn full_close(mut self) -> Self {
299 self.sz = None;
300 self.close_fraction = Some("1".to_owned());
301 self
302 }
303
304 pub fn currency(mut self, value: impl Into<String>) -> Self {
306 self.ccy = Some(value.into());
307 self
308 }
309
310 pub fn position_side(mut self, value: impl Into<String>) -> Self {
312 self.pos_side = Some(value.into());
313 self
314 }
315
316 pub fn reduce_only(mut self, value: bool) -> Self {
318 self.reduce_only = Some(value);
319 self
320 }
321
322 pub fn client_algo_order_id(mut self, value: impl Into<String>) -> Self {
324 self.algo_cl_ord_id = Some(value.into());
325 self
326 }
327
328 pub fn target_currency(mut self, value: impl Into<String>) -> Self {
330 self.tgt_ccy = Some(value.into());
331 self
332 }
333
334 pub fn trade_quote_currency(mut self, value: impl Into<String>) -> Self {
336 self.trade_quote_ccy = Some(value.into());
337 self
338 }
339
340 pub fn trigger(mut self, px: impl Into<String>, order_px: impl Into<String>) -> Self {
342 self.trigger_px = Some(px.into());
343 self.order_px = Some(order_px.into());
344 self
345 }
346
347 pub fn advance_order_type(mut self, value: impl Into<String>) -> Self {
349 self.advance_ord_type = Some(value.into());
350 self
351 }
352
353 pub fn trigger_price_type(mut self, value: impl Into<String>) -> Self {
355 self.trigger_px_type = Some(value.into());
356 self
357 }
358
359 pub fn take_profit(
361 mut self,
362 trigger_px: impl Into<String>,
363 order_px: impl Into<String>,
364 ) -> Self {
365 self.tp_trigger_px = Some(trigger_px.into());
366 self.tp_ord_px = Some(order_px.into());
367 self
368 }
369
370 pub fn limit_take_profit(mut self, order_px: impl Into<String>) -> Self {
372 self.tp_ord_kind = Some("limit".to_owned());
373 self.tp_ord_px = Some(order_px.into());
374 self
375 }
376
377 pub fn take_profit_price_type(mut self, value: impl Into<String>) -> Self {
379 self.tp_trigger_px_type = Some(value.into());
380 self
381 }
382
383 pub fn stop_loss(mut self, trigger_px: impl Into<String>, order_px: impl Into<String>) -> Self {
385 self.sl_trigger_px = Some(trigger_px.into());
386 self.sl_ord_px = Some(order_px.into());
387 self
388 }
389
390 pub fn stop_loss_price_type(mut self, value: impl Into<String>) -> Self {
392 self.sl_trigger_px_type = Some(value.into());
393 self
394 }
395
396 pub fn cancel_on_close_position(mut self, value: bool) -> Self {
398 self.cxl_on_close_pos = Some(value);
399 self
400 }
401
402 pub fn attached_algo_orders(mut self, values: Vec<AttachedAlgoOrderRequest>) -> Self {
404 self.attach_algo_ords = Some(values);
405 self
406 }
407
408 pub fn callback_ratio(mut self, value: impl Into<String>) -> Self {
410 self.callback_ratio = Some(value.into());
411 self
412 }
413
414 pub fn callback_spread(mut self, value: impl Into<String>) -> Self {
416 self.callback_spread = Some(value.into());
417 self
418 }
419
420 pub fn active_price(mut self, value: impl Into<String>) -> Self {
422 self.active_px = Some(value.into());
423 self
424 }
425
426 pub fn chase(mut self, chase_type: impl Into<String>, chase_val: impl Into<String>) -> Self {
428 self.chase_type = Some(chase_type.into());
429 self.chase_val = Some(chase_val.into());
430 self
431 }
432
433 pub fn maximum_chase(
435 mut self,
436 chase_type: impl Into<String>,
437 chase_val: impl Into<String>,
438 ) -> Self {
439 self.max_chase_type = Some(chase_type.into());
440 self.max_chase_val = Some(chase_val.into());
441 self
442 }
443
444 pub fn twap_by_variance(
446 mut self,
447 px_var: impl Into<String>,
448 sz_limit: impl Into<String>,
449 px_limit: impl Into<String>,
450 time_interval: impl Into<String>,
451 ) -> Self {
452 self.px_var = Some(px_var.into());
453 self.px_spread = None;
454 self.sz_limit = Some(sz_limit.into());
455 self.px_limit = Some(px_limit.into());
456 self.time_interval = Some(time_interval.into());
457 self
458 }
459
460 pub fn twap_by_spread(
462 mut self,
463 px_spread: impl Into<String>,
464 sz_limit: impl Into<String>,
465 px_limit: impl Into<String>,
466 time_interval: impl Into<String>,
467 ) -> Self {
468 self.px_var = None;
469 self.px_spread = Some(px_spread.into());
470 self.sz_limit = Some(sz_limit.into());
471 self.px_limit = Some(px_limit.into());
472 self.time_interval = Some(time_interval.into());
473 self
474 }
475
476 pub fn smart_iceberg(
478 mut self,
479 sz_limit: impl Into<String>,
480 lmt_order_number: impl Into<String>,
481 aggressiveness: impl Into<String>,
482 ) -> Self {
483 self.sz_limit = Some(sz_limit.into());
484 self.lmt_order_number = Some(lmt_order_number.into());
485 self.aggressiveness = Some(aggressiveness.into());
486 self
487 }
488
489 pub fn price_limit(mut self, value: impl Into<String>) -> Self {
491 self.px_limit = Some(value.into());
492 self
493 }
494
495 pub fn smart_iceberg_triggers(mut self, values: Vec<SmartIcebergTriggerRequest>) -> Self {
497 self.trigger_params = Some(values);
498 self
499 }
500
501 pub fn tag(mut self, value: impl Into<String>) -> Self {
503 self.tag = Some(value.into());
504 self
505 }
506}
507
508#[derive(Debug, Clone, Serialize)]
510pub struct CancelAlgoOrderRequest<'a> {
511 #[serde(rename = "algoId", skip_serializing_if = "Option::is_none")]
512 algo_id: Option<Cow<'a, str>>,
513 #[serde(rename = "algoClOrdId", skip_serializing_if = "Option::is_none")]
514 algo_cl_ord_id: Option<Cow<'a, str>>,
515 #[serde(rename = "instId")]
516 inst_id: Cow<'a, str>,
517}
518
519impl<'a> CancelAlgoOrderRequest<'a> {
520 pub fn new(algo_id: impl Into<Cow<'a, str>>, inst_id: impl Into<Cow<'a, str>>) -> Self {
522 Self {
523 algo_id: Some(algo_id.into()),
524 algo_cl_ord_id: None,
525 inst_id: inst_id.into(),
526 }
527 }
528
529 pub fn by_client_algo_order_id(
531 algo_cl_ord_id: impl Into<Cow<'a, str>>,
532 inst_id: impl Into<Cow<'a, str>>,
533 ) -> Self {
534 Self {
535 algo_id: None,
536 algo_cl_ord_id: Some(algo_cl_ord_id.into()),
537 inst_id: inst_id.into(),
538 }
539 }
540}
541
542#[derive(Debug, Clone, Serialize)]
544pub struct AmendAlgoOrderRequest<'a> {
545 #[serde(rename = "instId")]
546 inst_id: Cow<'a, str>,
547 #[serde(rename = "algoId", skip_serializing_if = "Option::is_none")]
548 algo_id: Option<Cow<'a, str>>,
549 #[serde(rename = "algoClOrdId", skip_serializing_if = "Option::is_none")]
550 algo_cl_ord_id: Option<Cow<'a, str>>,
551 #[serde(rename = "reqId", skip_serializing_if = "Option::is_none")]
552 req_id: Option<Cow<'a, str>>,
553 #[serde(rename = "newSz", skip_serializing_if = "Option::is_none")]
554 new_sz: Option<Cow<'a, str>>,
555 #[serde(rename = "newTpTriggerPx", skip_serializing_if = "Option::is_none")]
556 new_tp_trigger_px: Option<Cow<'a, str>>,
557 #[serde(rename = "newTpOrdPx", skip_serializing_if = "Option::is_none")]
558 new_tp_ord_px: Option<Cow<'a, str>>,
559 #[serde(rename = "newTpTriggerPxType", skip_serializing_if = "Option::is_none")]
560 new_tp_trigger_px_type: Option<Cow<'a, str>>,
561 #[serde(rename = "newSlTriggerPx", skip_serializing_if = "Option::is_none")]
562 new_sl_trigger_px: Option<Cow<'a, str>>,
563 #[serde(rename = "newSlOrdPx", skip_serializing_if = "Option::is_none")]
564 new_sl_ord_px: Option<Cow<'a, str>>,
565 #[serde(rename = "newSlTriggerPxType", skip_serializing_if = "Option::is_none")]
566 new_sl_trigger_px_type: Option<Cow<'a, str>>,
567 #[serde(rename = "cxlOnFail", skip_serializing_if = "Option::is_none")]
568 cancel_on_fail: Option<bool>,
569}
570
571impl<'a> AmendAlgoOrderRequest<'a> {
572 pub fn new(inst_id: impl Into<Cow<'a, str>>) -> Self {
574 Self {
575 inst_id: inst_id.into(),
576 algo_id: None,
577 algo_cl_ord_id: None,
578 req_id: None,
579 new_sz: None,
580 new_tp_trigger_px: None,
581 new_tp_ord_px: None,
582 new_tp_trigger_px_type: None,
583 new_sl_trigger_px: None,
584 new_sl_ord_px: None,
585 new_sl_trigger_px_type: None,
586 cancel_on_fail: None,
587 }
588 }
589
590 pub fn algo_id(mut self, value: impl Into<Cow<'a, str>>) -> Self {
592 self.algo_id = Some(value.into());
593 self
594 }
595
596 pub fn client_algo_order_id(mut self, value: impl Into<Cow<'a, str>>) -> Self {
598 self.algo_cl_ord_id = Some(value.into());
599 self
600 }
601
602 pub fn request_id(mut self, value: impl Into<Cow<'a, str>>) -> Self {
604 self.req_id = Some(value.into());
605 self
606 }
607
608 pub fn new_size(mut self, value: impl Into<Cow<'a, str>>) -> Self {
610 self.new_sz = Some(value.into());
611 self
612 }
613
614 pub fn take_profit(
616 mut self,
617 trigger_px: impl Into<Cow<'a, str>>,
618 order_px: impl Into<Cow<'a, str>>,
619 ) -> Self {
620 self.new_tp_trigger_px = Some(trigger_px.into());
621 self.new_tp_ord_px = Some(order_px.into());
622 self
623 }
624
625 pub fn take_profit_price_type(mut self, value: impl Into<Cow<'a, str>>) -> Self {
627 self.new_tp_trigger_px_type = Some(value.into());
628 self
629 }
630
631 pub fn delete_take_profit(mut self) -> Self {
633 self.new_tp_trigger_px = Some(Cow::Borrowed("0"));
634 self.new_tp_ord_px = None;
635 self.new_tp_trigger_px_type = None;
636 self
637 }
638
639 pub fn stop_loss(
641 mut self,
642 trigger_px: impl Into<Cow<'a, str>>,
643 order_px: impl Into<Cow<'a, str>>,
644 ) -> Self {
645 self.new_sl_trigger_px = Some(trigger_px.into());
646 self.new_sl_ord_px = Some(order_px.into());
647 self
648 }
649
650 pub fn stop_loss_price_type(mut self, value: impl Into<Cow<'a, str>>) -> Self {
652 self.new_sl_trigger_px_type = Some(value.into());
653 self
654 }
655
656 pub fn delete_stop_loss(mut self) -> Self {
658 self.new_sl_trigger_px = Some(Cow::Borrowed("0"));
659 self.new_sl_ord_px = None;
660 self.new_sl_trigger_px_type = None;
661 self
662 }
663
664 pub fn cancel_on_fail(mut self, value: bool) -> Self {
666 self.cancel_on_fail = Some(value);
667 self
668 }
669}
670
671#[derive(Debug, Clone, Serialize)]
673pub struct AlgoOrderListRequest<'a> {
674 #[serde(rename = "ordType")]
675 ord_type: Cow<'a, str>,
676 #[serde(rename = "algoId", skip_serializing_if = "Option::is_none")]
677 algo_id: Option<Cow<'a, str>>,
678 #[serde(rename = "instType", skip_serializing_if = "Option::is_none")]
679 inst_type: Option<Cow<'a, str>>,
680 #[serde(rename = "instId", skip_serializing_if = "Option::is_none")]
681 inst_id: Option<Cow<'a, str>>,
682 #[serde(skip_serializing_if = "Option::is_none")]
683 after: Option<Cow<'a, str>>,
684 #[serde(skip_serializing_if = "Option::is_none")]
685 before: Option<Cow<'a, str>>,
686 #[serde(skip_serializing_if = "Option::is_none")]
687 limit: Option<u32>,
688}
689
690impl<'a> AlgoOrderListRequest<'a> {
691 pub fn new(ord_type: impl Into<Cow<'a, str>>) -> Self {
693 Self {
694 ord_type: ord_type.into(),
695 algo_id: None,
696 inst_type: None,
697 inst_id: None,
698 after: None,
699 before: None,
700 limit: None,
701 }
702 }
703
704 pub fn algo_id(mut self, value: impl Into<Cow<'a, str>>) -> Self {
706 self.algo_id = Some(value.into());
707 self
708 }
709
710 pub fn inst_type(mut self, value: impl Into<Cow<'a, str>>) -> Self {
712 self.inst_type = Some(value.into());
713 self
714 }
715
716 pub fn inst_id(mut self, value: impl Into<Cow<'a, str>>) -> Self {
718 self.inst_id = Some(value.into());
719 self
720 }
721
722 pub fn after(mut self, value: impl Into<Cow<'a, str>>) -> Self {
724 self.after = Some(value.into());
725 self
726 }
727
728 pub fn before(mut self, value: impl Into<Cow<'a, str>>) -> Self {
730 self.before = Some(value.into());
731 self
732 }
733
734 pub fn limit(mut self, value: u32) -> Self {
736 self.limit = Some(value);
737 self
738 }
739}
740
741#[derive(Debug, Clone, Serialize)]
743pub struct AlgoOrderHistoryRequest<'a> {
744 #[serde(flatten)]
745 common: AlgoOrderListRequest<'a>,
746 #[serde(skip_serializing_if = "Option::is_none")]
747 state: Option<Cow<'a, str>>,
748}
749
750impl<'a> AlgoOrderHistoryRequest<'a> {
751 pub fn new(ord_type: impl Into<Cow<'a, str>>) -> Self {
753 Self {
754 common: AlgoOrderListRequest::new(ord_type),
755 state: None,
756 }
757 }
758
759 pub fn state(mut self, value: impl Into<Cow<'a, str>>) -> Self {
761 self.state = Some(value.into());
762 self
763 }
764
765 pub fn algo_id(mut self, value: impl Into<Cow<'a, str>>) -> Self {
767 self.common = self.common.algo_id(value);
768 self
769 }
770
771 pub fn inst_type(mut self, value: impl Into<Cow<'a, str>>) -> Self {
773 self.common = self.common.inst_type(value);
774 self
775 }
776
777 pub fn inst_id(mut self, value: impl Into<Cow<'a, str>>) -> Self {
779 self.common = self.common.inst_id(value);
780 self
781 }
782
783 pub fn after(mut self, value: impl Into<Cow<'a, str>>) -> Self {
785 self.common = self.common.after(value);
786 self
787 }
788
789 pub fn before(mut self, value: impl Into<Cow<'a, str>>) -> Self {
791 self.common = self.common.before(value);
792 self
793 }
794
795 pub fn limit(mut self, value: u32) -> Self {
797 self.common = self.common.limit(value);
798 self
799 }
800}
801
802#[derive(Debug, Clone, Default, Serialize)]
804pub struct AlgoOrderDetailsRequest<'a> {
805 #[serde(rename = "algoId", skip_serializing_if = "Option::is_none")]
806 algo_id: Option<Cow<'a, str>>,
807 #[serde(rename = "algoClOrdId", skip_serializing_if = "Option::is_none")]
808 algo_cl_ord_id: Option<Cow<'a, str>>,
809}
810
811impl<'a> AlgoOrderDetailsRequest<'a> {
812 pub fn by_algo_id(value: impl Into<Cow<'a, str>>) -> Self {
814 Self {
815 algo_id: Some(value.into()),
816 algo_cl_ord_id: None,
817 }
818 }
819
820 pub fn by_client_algo_order_id(value: impl Into<Cow<'a, str>>) -> Self {
822 Self {
823 algo_id: None,
824 algo_cl_ord_id: Some(value.into()),
825 }
826 }
827}
828
829#[cfg(test)]
830mod tests {
831 use super::*;
832
833 #[test]
834 fn twap_official_example_validates_and_serializes() {
835 let request = AlgoOrderRequest::new("BTC-USDT-SWAP", "cross", "buy", "twap", "10")
836 .position_side("net")
837 .twap_by_spread("10", "10", "100", "10");
838
839 assert_eq!(
840 serde_json::to_value(&request).unwrap(),
841 serde_json::json!({
842 "instId": "BTC-USDT-SWAP",
843 "tdMode": "cross",
844 "side": "buy",
845 "ordType": "twap",
846 "sz": "10",
847 "posSide": "net",
848 "pxSpread": "10",
849 "szLimit": "10",
850 "pxLimit": "100",
851 "timeInterval": "10"
852 })
853 );
854 }
855
856 #[test]
857 fn smart_iceberg_official_example_validates_and_serializes() {
858 let trigger = SmartIcebergTriggerRequest::new("price")
859 .price("90000")
860 .condition("cross_down");
861 let request = AlgoOrderRequest::new("BTC-USDT", "cash", "buy", "smart_iceberg", "100")
862 .smart_iceberg("10", "5", "conservative")
863 .price_limit("95000")
864 .smart_iceberg_triggers(vec![trigger]);
865
866 assert_eq!(
867 serde_json::to_value(&request).unwrap(),
868 serde_json::json!({
869 "instId": "BTC-USDT",
870 "tdMode": "cash",
871 "side": "buy",
872 "ordType": "smart_iceberg",
873 "sz": "100",
874 "szLimit": "10",
875 "pxLimit": "95000",
876 "lmtOrderNumber": "5",
877 "aggressiveness": "conservative",
878 "triggerParams": [{
879 "triggerAction": "start",
880 "triggerStrategy": "price",
881 "triggerPx": "90000",
882 "triggerCond": "cross_down"
883 }]
884 })
885 );
886 }
887
888 #[test]
889 fn amend_allows_both_identifiers_and_documented_delete_sentinel() {
890 let request = AmendAlgoOrderRequest::new("BTC-USDT")
891 .algo_id("1")
892 .client_algo_order_id("client1")
893 .delete_take_profit();
894 assert_eq!(
895 serde_json::to_value(&request).unwrap(),
896 serde_json::json!({
897 "instId": "BTC-USDT",
898 "algoId": "1",
899 "algoClOrdId": "client1",
900 "newTpTriggerPx": "0"
901 })
902 );
903 }
904}