nautilus_bybit/common/
enums.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Enumerations that model Bybit string/int enums across HTTP and WebSocket payloads.
17
18use std::fmt::{Display, Formatter};
19
20use nautilus_model::enums::{AggressorSide, OrderSide, TriggerType};
21use serde::{Deserialize, Serialize};
22use serde_repr::{Deserialize_repr, Serialize_repr};
23use strum::{AsRefStr, EnumIter, EnumString};
24
25/// Unified margin account status values.
26#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize_repr, Deserialize_repr)]
27#[repr(i32)]
28pub enum BybitUnifiedMarginStatus {
29    /// Classic account.
30    ClassicAccount = 1,
31    /// Unified trading account 1.0.
32    UnifiedTradingAccount10 = 3,
33    /// Unified trading account 1.0 pro.
34    UnifiedTradingAccount10Pro = 4,
35    /// Unified trading account 2.0.
36    UnifiedTradingAccount20 = 5,
37    /// Unified trading account 2.0 pro.
38    UnifiedTradingAccount20Pro = 6,
39}
40
41/// Margin mode used by Bybit when switching risk profiles.
42#[derive(
43    Clone,
44    Copy,
45    Debug,
46    strum::Display,
47    Eq,
48    PartialEq,
49    Hash,
50    AsRefStr,
51    EnumIter,
52    EnumString,
53    Serialize,
54    Deserialize,
55)]
56#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
57#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
58#[cfg_attr(
59    feature = "python",
60    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.bybit")
61)]
62pub enum BybitMarginMode {
63    IsolatedMargin,
64    RegularMargin,
65    PortfolioMargin,
66}
67
68/// Position mode as returned by the v5 API.
69#[derive(
70    Clone,
71    Copy,
72    Debug,
73    strum::Display,
74    Eq,
75    PartialEq,
76    Hash,
77    AsRefStr,
78    EnumIter,
79    EnumString,
80    Serialize_repr,
81    Deserialize_repr,
82)]
83#[repr(i32)]
84#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
85#[cfg_attr(
86    feature = "python",
87    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.bybit")
88)]
89pub enum BybitPositionMode {
90    /// Merged single position mode.
91    MergedSingle = 0,
92    /// Dual-side hedged position mode.
93    BothSides = 3,
94}
95
96/// Position index values used for hedge mode payloads.
97#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize_repr, Deserialize_repr)]
98#[repr(i32)]
99pub enum BybitPositionIdx {
100    /// One-way mode position identifier.
101    OneWay = 0,
102    /// Buy side of a hedge-mode position.
103    BuyHedge = 1,
104    /// Sell side of a hedge-mode position.
105    SellHedge = 2,
106}
107
108/// Account type enumeration.
109#[derive(
110    Copy,
111    Clone,
112    Debug,
113    strum::Display,
114    PartialEq,
115    Eq,
116    Hash,
117    AsRefStr,
118    EnumIter,
119    EnumString,
120    Serialize,
121    Deserialize,
122)]
123#[serde(rename_all = "UPPERCASE")]
124#[cfg_attr(
125    feature = "python",
126    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.bybit")
127)]
128pub enum BybitAccountType {
129    Unified,
130}
131
132/// Environments supported by the Bybit API stack.
133#[derive(
134    Copy,
135    Clone,
136    Debug,
137    strum::Display,
138    PartialEq,
139    Eq,
140    Hash,
141    AsRefStr,
142    EnumIter,
143    EnumString,
144    Serialize,
145    Deserialize,
146)]
147#[serde(rename_all = "lowercase")]
148#[cfg_attr(
149    feature = "python",
150    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.bybit")
151)]
152pub enum BybitEnvironment {
153    /// Live trading environment.
154    Mainnet,
155    /// Demo (paper trading) environment.
156    Demo,
157    /// Testnet environment for spot/derivatives.
158    Testnet,
159}
160
161/// Product categories supported by the v5 API.
162#[derive(
163    Copy,
164    Clone,
165    Debug,
166    strum::Display,
167    Default,
168    PartialEq,
169    Eq,
170    Hash,
171    AsRefStr,
172    EnumIter,
173    EnumString,
174    Serialize,
175    Deserialize,
176)]
177#[serde(rename_all = "lowercase")]
178#[cfg_attr(
179    feature = "python",
180    pyo3::pyclass(eq, eq_int, module = "nautilus_trader.core.nautilus_pyo3.bybit")
181)]
182pub enum BybitProductType {
183    #[default]
184    Spot,
185    Linear,
186    Inverse,
187    Option,
188}
189
190/// Spot margin trading enablement states.
191#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
192pub enum BybitMarginTrading {
193    #[serde(rename = "none")]
194    None,
195    #[serde(rename = "utaOnly")]
196    UtaOnly,
197    #[serde(rename = "both")]
198    Both,
199    #[serde(other)]
200    Other,
201}
202
203/// Innovation market flag for spot instruments.
204#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
205pub enum BybitInnovationFlag {
206    #[serde(rename = "0")]
207    Standard,
208    #[serde(rename = "1")]
209    Innovation,
210    #[serde(other)]
211    Other,
212}
213
214/// Instrument lifecycle status values.
215#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
216#[serde(rename_all = "PascalCase")]
217pub enum BybitInstrumentStatus {
218    Trading,
219    Settled,
220    Delivering,
221    ListedOnly,
222    PendingListing,
223    PreTrading,
224    Closed,
225    Suspended,
226    #[serde(other)]
227    Other,
228}
229
230impl BybitProductType {
231    /// Returns the canonical lowercase identifier used for REST/WS routes.
232    #[must_use]
233    pub const fn as_str(self) -> &'static str {
234        match self {
235            Self::Spot => "spot",
236            Self::Linear => "linear",
237            Self::Inverse => "inverse",
238            Self::Option => "option",
239        }
240    }
241
242    /// Returns the uppercase suffix used in instrument identifiers (e.g. `-LINEAR`).
243    #[must_use]
244    pub const fn suffix(self) -> &'static str {
245        match self {
246            Self::Spot => "-SPOT",
247            Self::Linear => "-LINEAR",
248            Self::Inverse => "-INVERSE",
249            Self::Option => "-OPTION",
250        }
251    }
252
253    /// Returns `true` if the product is a spot instrument.
254    #[must_use]
255    pub fn is_spot(self) -> bool {
256        matches!(self, Self::Spot)
257    }
258
259    /// Returns `true` if the product is a linear contract.
260    #[must_use]
261    pub fn is_linear(self) -> bool {
262        matches!(self, Self::Linear)
263    }
264
265    /// Returns `true` if the product is an inverse contract.
266    #[must_use]
267    pub fn is_inverse(self) -> bool {
268        matches!(self, Self::Inverse)
269    }
270
271    /// Returns `true` if the product is an option contract.
272    #[must_use]
273    pub fn is_option(self) -> bool {
274        matches!(self, Self::Option)
275    }
276}
277
278/// Contract type enumeration for linear and inverse derivatives.
279#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
280#[serde(rename_all = "PascalCase")]
281pub enum BybitContractType {
282    LinearPerpetual,
283    LinearFutures,
284    InversePerpetual,
285    InverseFutures,
286}
287
288/// Option flavour values.
289#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
290#[serde(rename_all = "PascalCase")]
291pub enum BybitOptionType {
292    Call,
293    Put,
294}
295
296/// Position side as represented in REST/WebSocket payloads.
297#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
298pub enum BybitPositionSide {
299    #[serde(rename = "")]
300    Flat,
301    #[serde(rename = "Buy")]
302    Buy,
303    #[serde(rename = "Sell")]
304    Sell,
305}
306
307/// WebSocket order request operations.
308#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
309pub enum BybitWsOrderRequestOp {
310    #[serde(rename = "order.create")]
311    Create,
312    #[serde(rename = "order.amend")]
313    Amend,
314    #[serde(rename = "order.cancel")]
315    Cancel,
316    #[serde(rename = "order.create-batch")]
317    CreateBatch,
318    #[serde(rename = "order.amend-batch")]
319    AmendBatch,
320    #[serde(rename = "order.cancel-batch")]
321    CancelBatch,
322}
323
324/// Available kline intervals.
325#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
326pub enum BybitKlineInterval {
327    #[serde(rename = "1")]
328    Minute1,
329    #[serde(rename = "3")]
330    Minute3,
331    #[serde(rename = "5")]
332    Minute5,
333    #[serde(rename = "15")]
334    Minute15,
335    #[serde(rename = "30")]
336    Minute30,
337    #[serde(rename = "60")]
338    Hour1,
339    #[serde(rename = "120")]
340    Hour2,
341    #[serde(rename = "240")]
342    Hour4,
343    #[serde(rename = "360")]
344    Hour6,
345    #[serde(rename = "720")]
346    Hour12,
347    #[serde(rename = "D")]
348    Day1,
349    #[serde(rename = "W")]
350    Week1,
351    #[serde(rename = "M")]
352    Month1,
353}
354
355impl Display for BybitKlineInterval {
356    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
357        let s = match self {
358            Self::Minute1 => "1",
359            Self::Minute3 => "3",
360            Self::Minute5 => "5",
361            Self::Minute15 => "15",
362            Self::Minute30 => "30",
363            Self::Hour1 => "60",
364            Self::Hour2 => "120",
365            Self::Hour4 => "240",
366            Self::Hour6 => "360",
367            Self::Hour12 => "720",
368            Self::Day1 => "D",
369            Self::Week1 => "W",
370            Self::Month1 => "M",
371        };
372        write!(f, "{s}")
373    }
374}
375
376/// Order status values returned by Bybit.
377#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
378pub enum BybitOrderStatus {
379    #[serde(rename = "Created")]
380    Created,
381    #[serde(rename = "New")]
382    New,
383    #[serde(rename = "Rejected")]
384    Rejected,
385    #[serde(rename = "PartiallyFilled")]
386    PartiallyFilled,
387    #[serde(rename = "PartiallyFilledCanceled")]
388    PartiallyFilledCanceled,
389    #[serde(rename = "Filled")]
390    Filled,
391    #[serde(rename = "Cancelled")]
392    Canceled,
393    #[serde(rename = "Untriggered")]
394    Untriggered,
395    #[serde(rename = "Triggered")]
396    Triggered,
397    #[serde(rename = "Deactivated")]
398    Deactivated,
399}
400
401/// Order side enumeration.
402#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
403pub enum BybitOrderSide {
404    #[serde(rename = "")]
405    Unknown,
406    #[serde(rename = "Buy")]
407    Buy,
408    #[serde(rename = "Sell")]
409    Sell,
410}
411
412impl From<BybitOrderSide> for AggressorSide {
413    fn from(value: BybitOrderSide) -> Self {
414        match value {
415            BybitOrderSide::Buy => Self::Buyer,
416            BybitOrderSide::Sell => Self::Seller,
417            BybitOrderSide::Unknown => Self::NoAggressor,
418        }
419    }
420}
421
422impl From<BybitOrderSide> for OrderSide {
423    fn from(value: BybitOrderSide) -> Self {
424        match value {
425            BybitOrderSide::Buy => Self::Buy,
426            BybitOrderSide::Sell => Self::Sell,
427            BybitOrderSide::Unknown => Self::NoOrderSide,
428        }
429    }
430}
431
432impl From<BybitTriggerType> for TriggerType {
433    fn from(value: BybitTriggerType) -> Self {
434        match value {
435            BybitTriggerType::None => Self::Default,
436            BybitTriggerType::LastPrice => Self::LastPrice,
437            BybitTriggerType::IndexPrice => Self::IndexPrice,
438            BybitTriggerType::MarkPrice => Self::MarkPrice,
439        }
440    }
441}
442
443/// Order cancel reason values as returned by Bybit.
444#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
445#[serde(rename_all = "PascalCase")]
446pub enum BybitCancelType {
447    CancelByUser,
448    CancelByReduceOnly,
449    CancelByPrepareLackOfMargin,
450    CancelByPrepareOrderFilter,
451    CancelByPrepareOrderMarginCheckFailed,
452    CancelByPrepareOrderCommission,
453    CancelByPrepareOrderRms,
454    CancelByPrepareOrderOther,
455    CancelByRiskLimit,
456    CancelOnDisconnect,
457    CancelByStopOrdersExceeded,
458    CancelByPzMarketClose,
459    CancelByMarginCheckFailed,
460    CancelByPzTakeover,
461    CancelByAdmin,
462    CancelByTpSlTsClear,
463    CancelByAmendNotModified,
464    CancelByPzCancel,
465    CancelByCrossSelfMatch,
466    CancelBySelfMatchPrevention,
467    #[serde(other)]
468    Other,
469}
470
471/// Order creation origin values.
472#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
473#[serde(rename_all = "PascalCase")]
474pub enum BybitCreateType {
475    CreateByUser,
476    CreateByClosing,
477    CreateByTakeProfit,
478    CreateByStopLoss,
479    CreateByTrailingStop,
480    CreateByStopOrder,
481    CreateByPartialTakeProfit,
482    CreateByPartialStopLoss,
483    CreateByAdl,
484    CreateByLiquidate,
485    CreateByTakeover,
486    CreateByTpsl,
487    #[serde(other)]
488    Other,
489}
490
491/// Venue order type enumeration.
492#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
493pub enum BybitOrderType {
494    #[serde(rename = "Market")]
495    Market,
496    #[serde(rename = "Limit")]
497    Limit,
498    #[serde(rename = "UNKNOWN")]
499    Unknown,
500}
501
502/// Stop order type classification.
503#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
504pub enum BybitStopOrderType {
505    #[serde(rename = "")]
506    None,
507    #[serde(rename = "UNKNOWN")]
508    Unknown,
509    #[serde(rename = "TakeProfit")]
510    TakeProfit,
511    #[serde(rename = "StopLoss")]
512    StopLoss,
513    #[serde(rename = "TrailingStop")]
514    TrailingStop,
515    #[serde(rename = "Stop")]
516    Stop,
517    #[serde(rename = "PartialTakeProfit")]
518    PartialTakeProfit,
519    #[serde(rename = "PartialStopLoss")]
520    PartialStopLoss,
521    #[serde(rename = "tpslOrder")]
522    TpslOrder,
523    #[serde(rename = "OcoOrder")]
524    OcoOrder,
525    #[serde(rename = "MmRateClose")]
526    MmRateClose,
527    #[serde(rename = "BidirectionalTpslOrder")]
528    BidirectionalTpslOrder,
529}
530
531/// Trigger type configuration.
532#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
533pub enum BybitTriggerType {
534    #[serde(rename = "")]
535    None,
536    #[serde(rename = "LastPrice")]
537    LastPrice,
538    #[serde(rename = "IndexPrice")]
539    IndexPrice,
540    #[serde(rename = "MarkPrice")]
541    MarkPrice,
542}
543
544/// Trigger direction integers used by the API.
545#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize_repr, Deserialize_repr)]
546#[repr(i32)]
547pub enum BybitTriggerDirection {
548    None = 0,
549    RisesTo = 1,
550    FallsTo = 2,
551}
552
553/// Take-profit/stop-loss mode for derivatives orders.
554#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
555#[serde(rename_all = "PascalCase")]
556pub enum BybitTpSlMode {
557    Full,
558    Partial,
559    #[serde(other)]
560    Unknown,
561}
562
563/// Time-in-force enumeration.
564#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
565pub enum BybitTimeInForce {
566    #[serde(rename = "GTC")]
567    Gtc,
568    #[serde(rename = "IOC")]
569    Ioc,
570    #[serde(rename = "FOK")]
571    Fok,
572    #[serde(rename = "PostOnly")]
573    PostOnly,
574}
575
576/// Execution type values used in execution reports.
577#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
578pub enum BybitExecType {
579    #[serde(rename = "Trade")]
580    Trade,
581    #[serde(rename = "AdlTrade")]
582    AdlTrade,
583    #[serde(rename = "Funding")]
584    Funding,
585    #[serde(rename = "BustTrade")]
586    BustTrade,
587    #[serde(rename = "Delivery")]
588    Delivery,
589    #[serde(rename = "Settle")]
590    Settle,
591    #[serde(rename = "BlockTrade")]
592    BlockTrade,
593    #[serde(rename = "MovePosition")]
594    MovePosition,
595    #[serde(rename = "UNKNOWN")]
596    Unknown,
597}
598
599/// Transaction types for wallet funding records.
600#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
601pub enum BybitTransactionType {
602    #[serde(rename = "TRANSFER_IN")]
603    TransferIn,
604    #[serde(rename = "TRANSFER_OUT")]
605    TransferOut,
606    #[serde(rename = "TRADE")]
607    Trade,
608    #[serde(rename = "SETTLEMENT")]
609    Settlement,
610    #[serde(rename = "DELIVERY")]
611    Delivery,
612    #[serde(rename = "LIQUIDATION")]
613    Liquidation,
614    #[serde(rename = "AIRDRP")]
615    Airdrop,
616}
617
618/// Endpoint classifications used by the Bybit API.
619#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
620#[serde(rename_all = "UPPERCASE")]
621pub enum BybitEndpointType {
622    None,
623    Asset,
624    Market,
625    Account,
626    Trade,
627    Position,
628    User,
629}