1use derive_builder::Builder;
19#[cfg(test)]
20use nautilus_core::string::secret::REDACTED;
21use nautilus_core::string::secret::SecretString;
22use serde::{Deserialize, Serialize};
23use zeroize::Zeroize;
24
25use crate::common::{
26 enums::{
27 BybitAccountType, BybitBboSideType, BybitExecType, BybitInstrumentStatus,
28 BybitKlineInterval, BybitMarginMode, BybitMarketUnit, BybitOpenOnly, BybitOptionType,
29 BybitOrderFilter, BybitOrderSide, BybitOrderSmpType, BybitOrderStatus, BybitOrderType,
30 BybitPositionIdx, BybitPositionMode, BybitProductType, BybitStopOrderType,
31 BybitTimeInForce, BybitTpSlMode, BybitTriggerDirection, BybitTriggerType,
32 },
33 parse::opt_bool_as_int,
34};
35
36#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
41#[serde(rename_all = "camelCase")]
42#[builder(default)]
43#[builder(setter(into))]
44pub struct BybitInstrumentsInfoParams {
45 pub category: BybitProductType,
46 #[builder(setter(strip_option))]
47 #[serde(skip_serializing_if = "Option::is_none")]
48 pub symbol: Option<String>,
49 #[builder(setter(strip_option))]
50 #[serde(skip_serializing_if = "Option::is_none")]
51 pub status: Option<BybitInstrumentStatus>,
52 #[builder(setter(strip_option))]
53 #[serde(skip_serializing_if = "Option::is_none")]
54 pub base_coin: Option<String>,
55 #[builder(setter(strip_option))]
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub limit: Option<u32>,
58 #[builder(setter(strip_option))]
59 #[serde(skip_serializing_if = "Option::is_none")]
60 pub cursor: Option<String>,
61}
62
63#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
68#[serde(rename_all = "camelCase")]
69#[builder(default)]
70#[builder(setter(into))]
71pub struct BybitTickersParams {
72 pub category: BybitProductType,
73 #[serde(skip_serializing_if = "Option::is_none")]
74 #[builder(setter(strip_option))]
75 pub symbol: Option<String>,
76 #[serde(skip_serializing_if = "Option::is_none")]
77 #[builder(setter(strip_option))]
78 pub base_coin: Option<String>,
79 #[serde(skip_serializing_if = "Option::is_none")]
80 #[builder(setter(strip_option))]
81 pub exp_date: Option<String>,
82}
83
84#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
89#[serde(rename_all = "camelCase")]
90#[builder(setter(into, strip_option), default)]
91pub struct BybitKlinesParams {
92 pub category: BybitProductType,
93 pub symbol: String,
94 pub interval: BybitKlineInterval,
95 #[serde(skip_serializing_if = "Option::is_none")]
96 pub start: Option<i64>,
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub end: Option<i64>,
99 #[serde(skip_serializing_if = "Option::is_none")]
100 pub limit: Option<u32>,
101}
102
103impl Default for BybitKlinesParams {
104 fn default() -> Self {
105 Self {
106 category: BybitProductType::Linear,
107 symbol: String::new(),
108 interval: BybitKlineInterval::Minute1,
109 start: None,
110 end: None,
111 limit: None,
112 }
113 }
114}
115
116#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
121#[serde(rename_all = "camelCase")]
122#[builder(setter(into, strip_option), default)]
123pub struct BybitTradesParams {
124 pub category: BybitProductType,
125 pub symbol: String,
126 #[serde(skip_serializing_if = "Option::is_none")]
127 pub base_coin: Option<String>,
128 #[serde(skip_serializing_if = "Option::is_none")]
129 pub option_type: Option<BybitOptionType>,
130 #[serde(skip_serializing_if = "Option::is_none")]
131 pub limit: Option<u32>,
132}
133
134impl Default for BybitTradesParams {
135 fn default() -> Self {
136 Self {
137 category: BybitProductType::Linear,
138 symbol: String::new(),
139 base_coin: None,
140 option_type: None,
141 limit: None,
142 }
143 }
144}
145
146#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
151#[serde(rename_all = "camelCase")]
152#[builder(setter(into, strip_option), default)]
153pub struct BybitFundingParams {
154 pub category: BybitProductType,
155 pub symbol: String,
156 #[serde(skip_serializing_if = "Option::is_none")]
157 pub start_time: Option<i64>,
158 #[serde(skip_serializing_if = "Option::is_none")]
159 pub end_time: Option<i64>,
160 #[serde(skip_serializing_if = "Option::is_none")]
161 pub limit: Option<u32>,
162}
163
164impl Default for BybitFundingParams {
165 fn default() -> Self {
166 Self {
167 category: BybitProductType::Linear,
168 symbol: String::new(),
169 start_time: None,
170 end_time: None,
171 limit: None,
172 }
173 }
174}
175
176#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
181#[builder(setter(into, strip_option), default)]
182pub struct BybitOrderbookParams {
183 pub category: BybitProductType,
184 pub symbol: String,
185 #[serde(skip_serializing_if = "Option::is_none")]
186 pub limit: Option<u32>,
187}
188
189impl Default for BybitOrderbookParams {
190 fn default() -> Self {
191 Self {
192 category: BybitProductType::Linear,
193 symbol: String::new(),
194 limit: None,
195 }
196 }
197}
198
199#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
204#[serde(rename_all = "camelCase")]
205#[builder(default)]
206#[builder(setter(into))]
207pub struct BybitCoinInfoParams {
208 #[serde(skip_serializing_if = "Option::is_none")]
209 #[builder(setter(strip_option))]
210 pub coin: Option<String>,
211}
212
213#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
218#[serde(rename_all = "camelCase")]
219#[builder(default)]
220#[builder(setter(into))]
221pub struct BybitFeeRateParams {
222 pub category: BybitProductType,
223 #[builder(setter(strip_option))]
224 #[serde(skip_serializing_if = "Option::is_none")]
225 pub symbol: Option<String>,
226 #[builder(setter(strip_option))]
227 #[serde(skip_serializing_if = "Option::is_none")]
228 pub base_coin: Option<String>,
229}
230
231#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
236#[serde(rename_all = "camelCase")]
237pub struct BybitWalletBalanceParams {
238 pub account_type: BybitAccountType,
239 #[serde(skip_serializing_if = "Option::is_none")]
240 #[builder(setter(strip_option))]
241 pub coin: Option<String>,
242}
243
244#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
249#[serde(rename_all = "camelCase")]
250#[builder(default)]
251#[builder(setter(into))]
252pub struct BybitPositionListParams {
253 pub category: BybitProductType,
254 #[serde(skip_serializing_if = "Option::is_none")]
255 #[builder(setter(strip_option))]
256 pub symbol: Option<String>,
257 #[serde(skip_serializing_if = "Option::is_none")]
258 #[builder(setter(strip_option))]
259 pub base_coin: Option<String>,
260 #[serde(skip_serializing_if = "Option::is_none")]
261 #[builder(setter(strip_option))]
262 pub settle_coin: Option<String>,
263 #[serde(skip_serializing_if = "Option::is_none")]
264 #[builder(setter(strip_option))]
265 pub limit: Option<u32>,
266 #[serde(skip_serializing_if = "Option::is_none")]
267 #[builder(setter(strip_option))]
268 pub cursor: Option<String>,
269}
270
271#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
276#[serde(rename_all = "camelCase")]
277pub struct BybitSetMarginModeParams {
278 pub set_margin_mode: BybitMarginMode,
279}
280
281#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
286#[serde(rename_all = "camelCase")]
287pub struct BybitSetLeverageParams {
288 pub category: BybitProductType,
289 pub symbol: String,
290 pub buy_leverage: String,
291 pub sell_leverage: String,
292}
293
294#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
299#[serde(rename_all = "camelCase")]
300pub struct BybitSwitchModeParams {
301 pub category: BybitProductType,
302 #[builder(default)]
303 #[serde(skip_serializing_if = "Option::is_none")]
304 #[builder(setter(strip_option))]
305 pub symbol: Option<String>,
306 #[builder(default)]
307 #[serde(skip_serializing_if = "Option::is_none")]
308 #[builder(setter(strip_option))]
309 pub coin: Option<String>,
310 pub mode: BybitPositionMode,
311}
312
313#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
318#[serde(rename_all = "camelCase")]
319pub struct BybitSetTradingStopParams {
320 pub category: BybitProductType,
321 pub symbol: String,
322 pub position_idx: BybitPositionIdx,
323 #[serde(skip_serializing_if = "Option::is_none")]
324 pub take_profit: Option<String>,
325 #[serde(skip_serializing_if = "Option::is_none")]
326 pub stop_loss: Option<String>,
327 #[serde(skip_serializing_if = "Option::is_none")]
328 pub trailing_stop: Option<String>,
329 #[serde(skip_serializing_if = "Option::is_none")]
330 pub tp_trigger_by: Option<BybitTriggerType>,
331 #[serde(skip_serializing_if = "Option::is_none")]
332 pub sl_trigger_by: Option<BybitTriggerType>,
333 #[serde(skip_serializing_if = "Option::is_none")]
334 pub active_price: Option<String>,
335 #[serde(skip_serializing_if = "Option::is_none")]
336 pub tpsl_mode: Option<BybitTpSlMode>,
337 #[serde(skip_serializing_if = "Option::is_none")]
338 pub tp_size: Option<String>,
339 #[serde(skip_serializing_if = "Option::is_none")]
340 pub sl_size: Option<String>,
341 #[serde(skip_serializing_if = "Option::is_none")]
342 pub tp_limit_price: Option<String>,
343 #[serde(skip_serializing_if = "Option::is_none")]
344 pub sl_limit_price: Option<String>,
345 #[serde(skip_serializing_if = "Option::is_none")]
346 pub tp_order_type: Option<BybitOrderType>,
347 #[serde(skip_serializing_if = "Option::is_none")]
348 pub sl_order_type: Option<BybitOrderType>,
349}
350
351#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
357#[serde(rename_all = "camelCase")]
358pub struct BybitBorrowParams {
359 pub coin: String,
360 pub amount: String,
361}
362
363#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
369#[serde(rename_all = "camelCase")]
370pub struct BybitNoConvertRepayParams {
371 pub coin: String,
372 #[serde(skip_serializing_if = "Option::is_none")]
373 #[builder(setter(strip_option), default)]
374 pub amount: Option<String>,
375}
376
377#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
383#[serde(rename_all = "camelCase")]
384pub struct BybitRepayParams {
385 #[serde(skip_serializing_if = "Option::is_none")]
386 #[builder(setter(strip_option), default)]
387 pub coin: Option<String>,
388 #[serde(skip_serializing_if = "Option::is_none")]
389 #[builder(setter(strip_option), default)]
390 pub amount: Option<String>,
391 #[serde(skip_serializing_if = "Option::is_none")]
392 #[builder(setter(strip_option), default)]
393 pub repayment_type: Option<String>,
394}
395
396#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
401#[serde(rename_all = "camelCase")]
402pub struct BybitBatchPlaceOrderEntry {
403 pub symbol: String,
404 #[builder(default)]
405 #[serde(skip_serializing_if = "Option::is_none")]
406 pub is_leverage: Option<i32>,
407 pub side: BybitOrderSide,
408 pub order_type: BybitOrderType,
409 pub qty: String,
410 #[builder(default)]
411 #[serde(skip_serializing_if = "Option::is_none")]
412 pub price: Option<String>,
413 #[builder(default)]
414 #[serde(skip_serializing_if = "Option::is_none")]
415 pub market_unit: Option<BybitMarketUnit>,
416 #[builder(default)]
417 #[serde(skip_serializing_if = "Option::is_none")]
418 pub trigger_direction: Option<BybitTriggerDirection>,
419 #[builder(default)]
420 #[serde(skip_serializing_if = "Option::is_none")]
421 pub order_filter: Option<BybitOrderFilter>,
422 #[builder(default)]
423 #[serde(skip_serializing_if = "Option::is_none")]
424 pub trigger_price: Option<String>,
425 #[builder(default)]
426 #[serde(skip_serializing_if = "Option::is_none")]
427 pub trigger_by: Option<BybitTriggerType>,
428 #[builder(default)]
429 #[serde(skip_serializing_if = "Option::is_none")]
430 pub order_iv: Option<String>,
431 #[builder(default)]
432 #[serde(skip_serializing_if = "Option::is_none")]
433 pub time_in_force: Option<BybitTimeInForce>,
434 #[builder(default)]
435 #[serde(skip_serializing_if = "Option::is_none")]
436 pub position_idx: Option<BybitPositionIdx>,
437 #[builder(default)]
438 #[serde(skip_serializing_if = "Option::is_none")]
439 #[builder(setter(strip_option))]
440 pub order_link_id: Option<String>,
441 #[builder(default)]
442 #[serde(skip_serializing_if = "Option::is_none")]
443 pub take_profit: Option<String>,
444 #[builder(default)]
445 #[serde(skip_serializing_if = "Option::is_none")]
446 pub stop_loss: Option<String>,
447 #[builder(default)]
448 #[serde(skip_serializing_if = "Option::is_none")]
449 pub tp_trigger_by: Option<BybitTriggerType>,
450 #[builder(default)]
451 #[serde(skip_serializing_if = "Option::is_none")]
452 pub sl_trigger_by: Option<BybitTriggerType>,
453 #[builder(default)]
454 #[serde(skip_serializing_if = "Option::is_none")]
455 pub reduce_only: Option<bool>,
456 #[builder(default)]
457 #[serde(skip_serializing_if = "Option::is_none")]
458 pub close_on_trigger: Option<bool>,
459 #[builder(default)]
460 #[serde(skip_serializing_if = "Option::is_none")]
461 pub smp_type: Option<BybitOrderSmpType>,
462 #[builder(default)]
463 #[serde(skip_serializing_if = "Option::is_none")]
464 pub mmp: Option<bool>,
465 #[builder(default)]
466 #[serde(skip_serializing_if = "Option::is_none")]
467 pub tpsl_mode: Option<BybitTpSlMode>,
468 #[builder(default)]
469 #[serde(skip_serializing_if = "Option::is_none")]
470 pub tp_limit_price: Option<String>,
471 #[builder(default)]
472 #[serde(skip_serializing_if = "Option::is_none")]
473 pub sl_limit_price: Option<String>,
474 #[builder(default)]
475 #[serde(skip_serializing_if = "Option::is_none")]
476 pub tp_order_type: Option<BybitOrderType>,
477 #[builder(default)]
478 #[serde(skip_serializing_if = "Option::is_none")]
479 pub sl_order_type: Option<BybitOrderType>,
480 #[builder(default)]
481 #[serde(skip_serializing_if = "Option::is_none")]
482 pub bbo_side_type: Option<BybitBboSideType>,
483 #[builder(default)]
484 #[serde(skip_serializing_if = "Option::is_none")]
485 pub bbo_level: Option<String>,
486}
487
488#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
493#[serde(rename_all = "camelCase")]
494pub struct BybitBatchPlaceOrderParams {
495 pub category: BybitProductType,
496 pub request: Vec<BybitBatchPlaceOrderEntry>,
497}
498
499#[derive(Debug, Clone, Default)]
510pub struct BybitNativeTpSlParams {
511 pub take_profit: Option<String>,
512 pub stop_loss: Option<String>,
513 pub tp_trigger_by: Option<BybitTriggerType>,
514 pub sl_trigger_by: Option<BybitTriggerType>,
515 pub tp_order_type: Option<BybitOrderType>,
516 pub sl_order_type: Option<BybitOrderType>,
517 pub tp_limit_price: Option<String>,
518 pub sl_limit_price: Option<String>,
519 pub tpsl_mode: Option<BybitTpSlMode>,
520 pub close_on_trigger: Option<bool>,
521 pub order_iv: Option<String>,
522 pub mmp: Option<bool>,
523}
524
525impl BybitNativeTpSlParams {
526 #[must_use]
528 pub fn is_empty(&self) -> bool {
529 self.take_profit.is_none()
530 && self.stop_loss.is_none()
531 && self.tp_trigger_by.is_none()
532 && self.sl_trigger_by.is_none()
533 && self.tp_order_type.is_none()
534 && self.sl_order_type.is_none()
535 && self.tp_limit_price.is_none()
536 && self.sl_limit_price.is_none()
537 && self.tpsl_mode.is_none()
538 && self.close_on_trigger.is_none()
539 && self.order_iv.is_none()
540 && self.mmp.is_none()
541 }
542}
543
544#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
549#[serde(rename_all = "camelCase")]
550pub struct BybitPlaceOrderParams {
551 #[serde(flatten)]
552 pub order: BybitBatchPlaceOrderEntry,
553 pub category: BybitProductType,
554 #[builder(default)]
555 #[serde(skip_serializing_if = "Option::is_none")]
556 pub slippage_tolerance_type: Option<String>,
557 #[builder(default)]
558 #[serde(skip_serializing_if = "Option::is_none")]
559 pub slippage_tolerance: Option<String>,
560}
561
562#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
567#[serde(rename_all = "camelCase")]
568pub struct BybitBatchAmendOrderEntry {
569 pub symbol: String,
570 #[builder(default)]
571 #[serde(skip_serializing_if = "Option::is_none")]
572 #[builder(setter(strip_option))]
573 pub order_id: Option<String>,
574 #[builder(default)]
575 #[serde(skip_serializing_if = "Option::is_none")]
576 #[builder(setter(strip_option))]
577 pub order_link_id: Option<String>,
578 #[builder(default)]
579 #[serde(skip_serializing_if = "Option::is_none")]
580 pub order_iv: Option<String>,
581 #[builder(default)]
582 #[serde(skip_serializing_if = "Option::is_none")]
583 pub trigger_price: Option<String>,
584 #[builder(default)]
585 #[serde(skip_serializing_if = "Option::is_none")]
586 pub qty: Option<String>,
587 #[builder(default)]
588 #[serde(skip_serializing_if = "Option::is_none")]
589 pub price: Option<String>,
590 #[builder(default)]
591 #[serde(skip_serializing_if = "Option::is_none")]
592 pub tpsl_mode: Option<BybitTpSlMode>,
593 #[builder(default)]
594 #[serde(skip_serializing_if = "Option::is_none")]
595 pub take_profit: Option<String>,
596 #[builder(default)]
597 #[serde(skip_serializing_if = "Option::is_none")]
598 pub stop_loss: Option<String>,
599 #[builder(default)]
600 #[serde(skip_serializing_if = "Option::is_none")]
601 pub tp_trigger_by: Option<BybitTriggerType>,
602 #[builder(default)]
603 #[serde(skip_serializing_if = "Option::is_none")]
604 pub sl_trigger_by: Option<BybitTriggerType>,
605 #[builder(default)]
606 #[serde(skip_serializing_if = "Option::is_none")]
607 pub trigger_by: Option<BybitTriggerType>,
608 #[builder(default)]
609 #[serde(skip_serializing_if = "Option::is_none")]
610 pub tp_limit_price: Option<String>,
611 #[builder(default)]
612 #[serde(skip_serializing_if = "Option::is_none")]
613 pub sl_limit_price: Option<String>,
614}
615
616#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
621#[serde(rename_all = "camelCase")]
622pub struct BybitBatchAmendOrderParams {
623 pub category: BybitProductType,
624 pub request: Vec<BybitBatchAmendOrderEntry>,
625}
626
627#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
632#[serde(rename_all = "camelCase")]
633pub struct BybitAmendOrderParams {
634 #[serde(flatten)]
635 pub order: BybitBatchAmendOrderEntry,
636 pub category: BybitProductType,
637}
638
639#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
644#[serde(rename_all = "camelCase")]
645pub struct BybitBatchCancelOrderEntry {
646 pub symbol: String,
647 #[builder(default)]
648 #[serde(skip_serializing_if = "Option::is_none")]
649 #[builder(setter(strip_option))]
650 pub order_id: Option<String>,
651 #[builder(default)]
652 #[serde(skip_serializing_if = "Option::is_none")]
653 #[builder(setter(strip_option))]
654 pub order_link_id: Option<String>,
655 #[builder(default)]
656 #[serde(skip_serializing_if = "Option::is_none")]
657 pub order_filter: Option<BybitOrderFilter>,
658}
659
660#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
665#[serde(rename_all = "camelCase")]
666pub struct BybitBatchCancelOrderParams {
667 pub category: BybitProductType,
668 pub request: Vec<BybitBatchCancelOrderEntry>,
669}
670
671#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
676#[serde(rename_all = "camelCase")]
677pub struct BybitCancelOrderParams {
678 #[serde(flatten)]
679 pub order: BybitBatchCancelOrderEntry,
680 pub category: BybitProductType,
681}
682
683#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
688#[serde(rename_all = "camelCase")]
689#[builder(default)]
690#[builder(setter(into))]
691pub struct BybitCancelAllOrdersParams {
692 pub category: BybitProductType,
693 #[serde(skip_serializing_if = "Option::is_none")]
694 #[builder(setter(strip_option))]
695 pub symbol: Option<String>,
696 #[serde(skip_serializing_if = "Option::is_none")]
697 #[builder(setter(strip_option))]
698 pub base_coin: Option<String>,
699 #[serde(skip_serializing_if = "Option::is_none")]
700 #[builder(setter(strip_option))]
701 pub settle_coin: Option<String>,
702 #[serde(skip_serializing_if = "Option::is_none")]
703 #[builder(setter(strip_option))]
704 pub order_filter: Option<BybitOrderFilter>,
705 #[serde(skip_serializing_if = "Option::is_none")]
706 #[builder(setter(strip_option))]
707 pub stop_order_type: Option<BybitStopOrderType>,
708}
709
710#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
715#[serde(rename_all = "camelCase")]
716#[builder(default)]
717#[builder(setter(into))]
718pub struct BybitOpenOrdersParams {
719 pub category: BybitProductType,
720 #[serde(skip_serializing_if = "Option::is_none")]
721 #[builder(setter(strip_option))]
722 pub symbol: Option<String>,
723 #[serde(skip_serializing_if = "Option::is_none")]
724 #[builder(setter(strip_option))]
725 pub base_coin: Option<String>,
726 #[serde(skip_serializing_if = "Option::is_none")]
727 #[builder(setter(strip_option))]
728 pub settle_coin: Option<String>,
729 #[serde(skip_serializing_if = "Option::is_none")]
730 #[builder(setter(strip_option))]
731 pub order_id: Option<String>,
732 #[serde(skip_serializing_if = "Option::is_none")]
733 #[builder(setter(strip_option))]
734 pub order_link_id: Option<String>,
735 #[serde(skip_serializing_if = "Option::is_none")]
736 #[builder(setter(strip_option))]
737 pub open_only: Option<BybitOpenOnly>,
738 #[serde(skip_serializing_if = "Option::is_none")]
739 #[builder(setter(strip_option))]
740 pub order_filter: Option<BybitOrderFilter>,
741 #[serde(skip_serializing_if = "Option::is_none")]
742 #[builder(setter(strip_option))]
743 pub limit: Option<u32>,
744 #[serde(skip_serializing_if = "Option::is_none")]
745 #[builder(setter(strip_option))]
746 pub cursor: Option<String>,
747}
748
749#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
754#[serde(rename_all = "camelCase")]
755#[builder(default)]
756#[builder(setter(into))]
757pub struct BybitOrderHistoryParams {
758 pub category: BybitProductType,
759 #[serde(skip_serializing_if = "Option::is_none")]
760 #[builder(setter(strip_option))]
761 pub symbol: Option<String>,
762 #[serde(skip_serializing_if = "Option::is_none")]
763 #[builder(setter(strip_option))]
764 pub base_coin: Option<String>,
765 #[serde(skip_serializing_if = "Option::is_none")]
766 #[builder(setter(strip_option))]
767 pub settle_coin: Option<String>,
768 #[serde(skip_serializing_if = "Option::is_none")]
769 #[builder(setter(strip_option))]
770 pub order_id: Option<String>,
771 #[serde(skip_serializing_if = "Option::is_none")]
772 #[builder(setter(strip_option))]
773 pub order_link_id: Option<String>,
774 #[serde(skip_serializing_if = "Option::is_none")]
775 #[builder(setter(strip_option))]
776 pub open_only: Option<BybitOpenOnly>,
777 #[serde(skip_serializing_if = "Option::is_none")]
778 #[builder(setter(strip_option))]
779 pub order_filter: Option<BybitOrderFilter>,
780 #[serde(skip_serializing_if = "Option::is_none")]
781 #[builder(setter(strip_option))]
782 pub order_status: Option<BybitOrderStatus>,
783 #[serde(skip_serializing_if = "Option::is_none")]
784 #[builder(setter(strip_option))]
785 pub start_time: Option<i64>,
786 #[serde(skip_serializing_if = "Option::is_none")]
787 #[serde(rename = "endTime")]
788 #[builder(setter(strip_option))]
789 pub end_time: Option<i64>,
790 #[serde(skip_serializing_if = "Option::is_none")]
791 #[builder(setter(strip_option))]
792 pub limit: Option<u32>,
793 #[serde(skip_serializing_if = "Option::is_none")]
794 #[builder(setter(strip_option))]
795 pub cursor: Option<String>,
796}
797
798#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
803#[serde(rename_all = "camelCase")]
804#[builder(default)]
805#[builder(setter(into))]
806pub struct BybitTradeHistoryParams {
807 pub category: BybitProductType,
808 #[serde(skip_serializing_if = "Option::is_none")]
809 #[builder(setter(strip_option))]
810 pub symbol: Option<String>,
811 #[serde(skip_serializing_if = "Option::is_none")]
812 #[builder(setter(strip_option))]
813 pub base_coin: Option<String>,
814 #[serde(skip_serializing_if = "Option::is_none")]
815 #[builder(setter(strip_option))]
816 pub order_id: Option<String>,
817 #[serde(skip_serializing_if = "Option::is_none")]
818 #[builder(setter(strip_option))]
819 pub order_link_id: Option<String>,
820 #[serde(skip_serializing_if = "Option::is_none")]
821 #[builder(setter(strip_option))]
822 pub start_time: Option<i64>,
823 #[serde(skip_serializing_if = "Option::is_none")]
824 #[serde(rename = "endTime")]
825 #[builder(setter(strip_option))]
826 pub end_time: Option<i64>,
827 #[serde(skip_serializing_if = "Option::is_none")]
828 #[builder(setter(strip_option))]
829 pub exec_type: Option<BybitExecType>,
830 #[serde(skip_serializing_if = "Option::is_none")]
831 #[builder(setter(strip_option))]
832 pub limit: Option<u32>,
833 #[serde(skip_serializing_if = "Option::is_none")]
834 #[builder(setter(strip_option))]
835 pub cursor: Option<String>,
836}
837
838#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
857#[serde(rename_all = "PascalCase")]
858#[builder(default)]
859#[builder(setter(into, strip_option))]
860pub struct BybitApiKeyPermissionUpdate {
861 #[serde(skip_serializing_if = "Option::is_none")]
862 pub contract_trade: Option<Vec<String>>,
863 #[serde(skip_serializing_if = "Option::is_none")]
864 pub spot: Option<Vec<String>>,
865 #[serde(skip_serializing_if = "Option::is_none")]
866 pub wallet: Option<Vec<String>>,
867 #[serde(skip_serializing_if = "Option::is_none")]
868 pub options: Option<Vec<String>>,
869 #[serde(skip_serializing_if = "Option::is_none")]
870 pub derivatives: Option<Vec<String>>,
871 #[serde(skip_serializing_if = "Option::is_none")]
872 pub exchange: Option<Vec<String>>,
873 #[serde(skip_serializing_if = "Option::is_none")]
874 pub earn: Option<Vec<String>>,
875 #[serde(skip_serializing_if = "Option::is_none")]
876 pub affiliate: Option<Vec<String>>,
877 #[serde(skip_serializing_if = "Option::is_none")]
878 pub block_trade: Option<Vec<String>>,
879 #[serde(skip_serializing_if = "Option::is_none")]
880 pub copy_trading: Option<Vec<String>>,
881 #[serde(rename = "NFT", skip_serializing_if = "Option::is_none")]
884 pub nft: Option<Vec<String>>,
885 #[serde(rename = "FiatP2P", skip_serializing_if = "Option::is_none")]
887 pub fiat_p2p: Option<Vec<String>>,
888 #[serde(skip_serializing_if = "Option::is_none")]
889 pub fiat_bybit_pay: Option<Vec<String>>,
890 #[serde(skip_serializing_if = "Option::is_none")]
891 pub fiat_bit_pay: Option<Vec<String>>,
892 #[serde(skip_serializing_if = "Option::is_none")]
893 pub fiat_convert_broker: Option<Vec<String>>,
894 #[serde(skip_serializing_if = "Option::is_none")]
895 pub bit_card: Option<Vec<String>>,
896 #[serde(rename = "ByXPost", skip_serializing_if = "Option::is_none")]
898 pub byx_post: Option<Vec<String>>,
899}
900
901#[derive(Debug, Clone, Deserialize, Serialize, Default, Builder)]
909#[serde(rename_all = "camelCase")]
910#[builder(setter(into))]
911pub struct BybitUpdateSubApiParams {
912 #[builder(default)]
913 #[serde(skip_serializing_if = "Option::is_none")]
914 #[builder(setter(strip_option))]
915 pub api_key: Option<SecretString>,
916 #[builder(default)]
919 #[serde(skip_serializing_if = "Option::is_none", with = "opt_bool_as_int")]
920 #[builder(setter(strip_option))]
921 pub read_only: Option<bool>,
922 #[builder(default)]
923 #[serde(skip_serializing_if = "Option::is_none")]
924 #[builder(setter(strip_option))]
925 pub ips: Option<String>,
926 #[builder(default)]
927 #[serde(skip_serializing_if = "Option::is_none")]
928 #[builder(setter(strip_option))]
929 pub permissions: Option<BybitApiKeyPermissionUpdate>,
930}
931
932impl Zeroize for BybitUpdateSubApiParams {
933 fn zeroize(&mut self) {
934 self.api_key.zeroize();
935 }
936}
937
938#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
949#[serde(rename_all = "camelCase")]
950#[builder(default)]
951#[builder(setter(into))]
952pub struct BybitUpdateMasterApiParams {
953 #[serde(skip_serializing_if = "Option::is_none", with = "opt_bool_as_int")]
954 #[builder(setter(strip_option))]
955 pub read_only: Option<bool>,
956 #[serde(skip_serializing_if = "Option::is_none")]
957 #[builder(setter(strip_option))]
958 pub permissions: Option<BybitApiKeyPermissionUpdate>,
959}
960
961#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
973#[serde(rename_all = "camelCase")]
974#[builder(default)]
975#[builder(setter(into))]
976pub struct BybitSubMembersPageParams {
977 #[serde(skip_serializing_if = "Option::is_none")]
978 #[builder(setter(strip_option))]
979 pub page_size: Option<u32>,
980 #[serde(skip_serializing_if = "Option::is_none")]
981 #[builder(setter(strip_option))]
982 pub next_cursor: Option<String>,
983}
984
985#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
994#[serde(rename_all = "camelCase")]
995#[builder(setter(into))]
996pub struct BybitSubApiKeysParams {
997 pub sub_member_id: String,
998 #[serde(skip_serializing_if = "Option::is_none")]
999 #[builder(setter(strip_option), default)]
1000 pub limit: Option<u32>,
1001 #[serde(skip_serializing_if = "Option::is_none")]
1002 #[builder(setter(strip_option), default)]
1003 pub cursor: Option<String>,
1004}
1005
1006#[cfg(test)]
1007mod tests {
1008 use rstest::rstest;
1009 use zeroize::Zeroize;
1010
1011 use super::*;
1012
1013 #[rstest]
1014 fn test_update_sub_api_preserves_wire_value_and_redacts_debug() {
1015 let mut params = BybitUpdateSubApiParamsBuilder::default()
1016 .api_key("sub-api-key-secret".to_string())
1017 .read_only(true)
1018 .build()
1019 .unwrap();
1020
1021 let value = serde_json::to_value(¶ms).unwrap();
1022 let debug = format!("{params:?}");
1023
1024 assert_eq!(value["apiKey"], "sub-api-key-secret");
1025 assert_eq!(value["readOnly"], 1);
1026 assert!(debug.contains(REDACTED));
1027 assert!(!debug.contains("sub-api-key-secret"));
1028
1029 params.zeroize();
1030 assert!(params.api_key.is_none());
1031 }
1032
1033 #[rstest]
1034 fn test_amend_entry_builds_with_only_order_id() {
1035 let entry = BybitBatchAmendOrderEntryBuilder::default()
1036 .symbol("ETHUSDT".to_string())
1037 .order_id("12345".to_string())
1038 .price(Some("1600.0".to_string()))
1039 .build()
1040 .expect("amend entry should build with only order_id");
1041
1042 assert_eq!(entry.order_id.as_deref(), Some("12345"));
1043 assert_eq!(entry.order_link_id, None);
1044 }
1045
1046 #[rstest]
1047 fn test_amend_entry_builds_with_only_order_link_id() {
1048 let entry = BybitBatchAmendOrderEntryBuilder::default()
1049 .symbol("ETHUSDT".to_string())
1050 .order_link_id("link-1".to_string())
1051 .qty(Some("0.02".to_string()))
1052 .build()
1053 .expect("amend entry should build with only order_link_id");
1054
1055 assert_eq!(entry.order_link_id.as_deref(), Some("link-1"));
1056 assert_eq!(entry.order_id, None);
1057 }
1058
1059 #[rstest]
1060 fn test_amend_entry_builds_with_no_identifiers() {
1061 let entry = BybitBatchAmendOrderEntryBuilder::default()
1062 .symbol("ETHUSDT".to_string())
1063 .price(Some("1600.0".to_string()))
1064 .build()
1065 .expect("amend entry optional identifiers default to None");
1066
1067 assert_eq!(entry.order_id, None);
1068 assert_eq!(entry.order_link_id, None);
1069 }
1070
1071 #[rstest]
1072 fn test_cancel_entry_builds_with_only_order_id() {
1073 let entry = BybitBatchCancelOrderEntryBuilder::default()
1074 .symbol("ETHUSDT".to_string())
1075 .order_id("12345".to_string())
1076 .build()
1077 .expect("cancel entry should build with only order_id");
1078
1079 assert_eq!(entry.order_id.as_deref(), Some("12345"));
1080 assert_eq!(entry.order_link_id, None);
1081 }
1082
1083 #[rstest]
1084 fn test_cancel_entry_builds_with_only_order_link_id() {
1085 let entry = BybitBatchCancelOrderEntryBuilder::default()
1086 .symbol("ETHUSDT".to_string())
1087 .order_link_id("link-1".to_string())
1088 .build()
1089 .expect("cancel entry should build with only order_link_id");
1090
1091 assert_eq!(entry.order_link_id.as_deref(), Some("link-1"));
1092 assert_eq!(entry.order_id, None);
1093 }
1094}