Skip to main content

bybit_api/models/
common.rs

1//! Common types used across the Bybit API.
2
3use serde::{Deserialize, Serialize};
4
5/// A string newtype that hides its contents from `Debug` formatting.
6///
7/// Use for API secrets, passwords, and other credentials that must never
8/// appear in logs. Serializes/deserializes transparently as a plain string
9/// so the wire format is unchanged.
10///
11/// Call [`Self::expose_secret`] to access the underlying value when you
12/// genuinely need it (e.g. to authenticate a request).
13#[derive(Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(transparent)]
15pub struct RedactedString(String);
16
17impl RedactedString {
18    /// Wrap a string. Prefer [`From<String>`] / [`From<&str>`] in code.
19    pub fn new(s: impl Into<String>) -> Self {
20        Self(s.into())
21    }
22
23    /// Access the underlying secret. Use sparingly; never log the return
24    /// value of this method.
25    pub fn expose_secret(&self) -> &str {
26        &self.0
27    }
28}
29
30impl std::fmt::Debug for RedactedString {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        // Note: do NOT include length or any prefix/suffix of the secret;
33        // doing so can leak entropy in low-entropy secrets.
34        f.write_str("RedactedString(***)")
35    }
36}
37
38impl From<String> for RedactedString {
39    fn from(s: String) -> Self {
40        Self(s)
41    }
42}
43
44impl From<&str> for RedactedString {
45    fn from(s: &str) -> Self {
46        Self(s.to_owned())
47    }
48}
49
50
51/// Product category.
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
53#[serde(rename_all = "lowercase")]
54pub enum Category {
55    /// Spot trading
56    Spot,
57    /// Linear perpetual (USDT margined)
58    Linear,
59    /// Inverse perpetual/futures
60    Inverse,
61    /// Options
62    Option,
63}
64
65impl std::fmt::Display for Category {
66    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67        match self {
68            Self::Spot => write!(f, "spot"),
69            Self::Linear => write!(f, "linear"),
70            Self::Inverse => write!(f, "inverse"),
71            Self::Option => write!(f, "option"),
72        }
73    }
74}
75
76/// Order side.
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
78pub enum Side {
79    /// Buy order
80    Buy,
81    /// Sell order
82    Sell,
83}
84
85impl std::fmt::Display for Side {
86    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87        match self {
88            Self::Buy => write!(f, "Buy"),
89            Self::Sell => write!(f, "Sell"),
90        }
91    }
92}
93
94/// Order type.
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
96pub enum OrderType {
97    /// Market order
98    Market,
99    /// Limit order
100    Limit,
101}
102
103/// Time in force.
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
105pub enum TimeInForce {
106    /// Good till cancelled
107    GTC,
108    /// Immediate or cancel
109    IOC,
110    /// Fill or kill
111    FOK,
112    /// Post only
113    PostOnly,
114}
115
116/// Order status.
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
118pub enum OrderStatus {
119    /// Order created
120    Created,
121    /// Order is new (not filled)
122    New,
123    /// Order is rejected
124    Rejected,
125    /// Order is partially filled
126    PartiallyFilled,
127    /// Order is partially filled and cancelled
128    PartiallyFilledCanceled,
129    /// Order is fully filled
130    Filled,
131    /// Order is cancelled
132    Cancelled,
133    /// Order is untriggered
134    Untriggered,
135    /// Order is triggered
136    Triggered,
137    /// Order is deactivated
138    Deactivated,
139    /// Order is active (conditional)
140    Active,
141}
142
143/// Position side.
144#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
145pub enum PositionIdx {
146    /// One-way mode
147    #[serde(rename = "0")]
148    OneWay = 0,
149    /// Hedge mode - buy side
150    #[serde(rename = "1")]
151    HedgeBuy = 1,
152    /// Hedge mode - sell side
153    #[serde(rename = "2")]
154    HedgeSell = 2,
155}
156
157/// Account type.
158#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
159pub enum AccountType {
160    /// Contract account
161    CONTRACT,
162    /// Unified account
163    UNIFIED,
164    /// Spot account
165    SPOT,
166    /// Investment account
167    INVESTMENT,
168    /// Option account
169    OPTION,
170    /// Fund account
171    FUND,
172}
173
174impl std::fmt::Display for AccountType {
175    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176        match self {
177            Self::CONTRACT => write!(f, "CONTRACT"),
178            Self::UNIFIED => write!(f, "UNIFIED"),
179            Self::SPOT => write!(f, "SPOT"),
180            Self::INVESTMENT => write!(f, "INVESTMENT"),
181            Self::OPTION => write!(f, "OPTION"),
182            Self::FUND => write!(f, "FUND"),
183        }
184    }
185}
186
187/// Kline interval.
188#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
189pub enum Interval {
190    /// 1 minute
191    #[serde(rename = "1")]
192    M1,
193    /// 3 minutes
194    #[serde(rename = "3")]
195    M3,
196    /// 5 minutes
197    #[serde(rename = "5")]
198    M5,
199    /// 15 minutes
200    #[serde(rename = "15")]
201    M15,
202    /// 30 minutes
203    #[serde(rename = "30")]
204    M30,
205    /// 1 hour
206    #[serde(rename = "60")]
207    H1,
208    /// 2 hours
209    #[serde(rename = "120")]
210    H2,
211    /// 4 hours
212    #[serde(rename = "240")]
213    H4,
214    /// 6 hours
215    #[serde(rename = "360")]
216    H6,
217    /// 12 hours
218    #[serde(rename = "720")]
219    H12,
220    /// 1 day
221    #[serde(rename = "D")]
222    D1,
223    /// 1 week
224    #[serde(rename = "W")]
225    W1,
226    /// 1 month
227    #[serde(rename = "M")]
228    M1Month,
229}
230
231impl std::fmt::Display for Interval {
232    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233        match self {
234            Self::M1 => write!(f, "1"),
235            Self::M3 => write!(f, "3"),
236            Self::M5 => write!(f, "5"),
237            Self::M15 => write!(f, "15"),
238            Self::M30 => write!(f, "30"),
239            Self::H1 => write!(f, "60"),
240            Self::H2 => write!(f, "120"),
241            Self::H4 => write!(f, "240"),
242            Self::H6 => write!(f, "360"),
243            Self::H12 => write!(f, "720"),
244            Self::D1 => write!(f, "D"),
245            Self::W1 => write!(f, "W"),
246            Self::M1Month => write!(f, "M"),
247        }
248    }
249}
250
251/// Trigger price type.
252#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
253pub enum TriggerBy {
254    /// Last price
255    LastPrice,
256    /// Index price
257    IndexPrice,
258    /// Mark price
259    MarkPrice,
260}
261
262/// Position mode.
263#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
264pub enum PositionMode {
265    /// Merged single position (one-way)
266    #[serde(rename = "0")]
267    MergedSingle = 0,
268    /// Both sides (hedge mode)
269    #[serde(rename = "3")]
270    BothSides = 3,
271}
272
273/// Margin mode.
274///
275/// Wire protocol values follow Bybit V5 `/v5/account/set-margin-mode`:
276/// - `ISOLATED_MARGIN`
277/// - `REGULAR_MARGIN` (mapped from [`Self::CROSS`])
278/// - `PORTFOLIO_MARGIN` (mapped from [`Self::PORTFOLIO`])
279#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
280pub enum MarginMode {
281    /// Cross margin (wire value: `REGULAR_MARGIN`)
282    #[serde(rename = "REGULAR_MARGIN")]
283    CROSS,
284    /// Isolated margin (wire value: `ISOLATED_MARGIN`)
285    #[serde(rename = "ISOLATED_MARGIN")]
286    ISOLATED,
287    /// Portfolio margin (wire value: `PORTFOLIO_MARGIN`)
288    #[serde(rename = "PORTFOLIO_MARGIN")]
289    PORTFOLIO,
290}
291
292impl std::fmt::Display for MarginMode {
293    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
294        match self {
295            Self::CROSS => write!(f, "REGULAR_MARGIN"),
296            Self::ISOLATED => write!(f, "ISOLATED_MARGIN"),
297            Self::PORTFOLIO => write!(f, "PORTFOLIO_MARGIN"),
298        }
299    }
300}
301
302/// TP/SL mode.
303#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
304pub enum TpSlMode {
305    /// Full position TP/SL
306    Full,
307    /// Partial position TP/SL
308    Partial,
309}