nautilus_binance/common/
enums.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 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//! Binance enumeration types for product types and environments.
17
18use serde::{Deserialize, Serialize};
19
20/// Binance product type identifier.
21///
22/// Each product type corresponds to a different Binance API domain and
23/// has distinct trading rules and instrument specifications.
24#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
25#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
26#[cfg_attr(
27    feature = "python",
28    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.binance", eq)
29)]
30pub enum BinanceProductType {
31    /// Spot trading (api.binance.com).
32    #[default]
33    Spot,
34    /// Spot Margin trading (uses Spot API with margin endpoints).
35    Margin,
36    /// USD-M Futures - linear perpetuals and delivery futures (fapi.binance.com).
37    UsdM,
38    /// COIN-M Futures - inverse perpetuals and delivery futures (dapi.binance.com).
39    CoinM,
40    /// European Options (eapi.binance.com).
41    Options,
42}
43
44impl BinanceProductType {
45    /// Returns the string representation used in API requests.
46    #[must_use]
47    pub const fn as_str(self) -> &'static str {
48        match self {
49            Self::Spot => "SPOT",
50            Self::Margin => "MARGIN",
51            Self::UsdM => "USD_M",
52            Self::CoinM => "COIN_M",
53            Self::Options => "OPTIONS",
54        }
55    }
56
57    /// Returns the instrument ID suffix for this product type.
58    #[must_use]
59    pub const fn suffix(self) -> &'static str {
60        match self {
61            Self::Spot => "-SPOT",
62            Self::Margin => "-MARGIN",
63            Self::UsdM => "-LINEAR",
64            Self::CoinM => "-INVERSE",
65            Self::Options => "-OPTION",
66        }
67    }
68
69    /// Returns true if this is a spot product (Spot or Margin).
70    #[must_use]
71    pub const fn is_spot(self) -> bool {
72        matches!(self, Self::Spot | Self::Margin)
73    }
74
75    /// Returns true if this is a futures product (USD-M or COIN-M).
76    #[must_use]
77    pub const fn is_futures(self) -> bool {
78        matches!(self, Self::UsdM | Self::CoinM)
79    }
80
81    /// Returns true if this is a linear product (Spot, Margin, or USD-M).
82    #[must_use]
83    pub const fn is_linear(self) -> bool {
84        matches!(self, Self::Spot | Self::Margin | Self::UsdM)
85    }
86
87    /// Returns true if this is an inverse product (COIN-M).
88    #[must_use]
89    pub const fn is_inverse(self) -> bool {
90        matches!(self, Self::CoinM)
91    }
92
93    /// Returns true if this is an options product.
94    #[must_use]
95    pub const fn is_options(self) -> bool {
96        matches!(self, Self::Options)
97    }
98}
99
100impl std::fmt::Display for BinanceProductType {
101    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102        write!(f, "{}", self.as_str())
103    }
104}
105
106/// Binance environment type.
107#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
108#[cfg_attr(
109    feature = "python",
110    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.binance", eq)
111)]
112pub enum BinanceEnvironment {
113    /// Production/mainnet environment.
114    #[default]
115    Mainnet,
116    /// Testnet environment.
117    Testnet,
118}
119
120impl BinanceEnvironment {
121    /// Returns true if this is the testnet environment.
122    #[must_use]
123    pub const fn is_testnet(self) -> bool {
124        matches!(self, Self::Testnet)
125    }
126}
127
128/// Order side for Binance orders and trades.
129#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
130#[serde(rename_all = "UPPERCASE")]
131pub enum BinanceSide {
132    /// Buy side.
133    Buy,
134    /// Sell side.
135    Sell,
136}
137
138/// Position side for dual-side position mode.
139#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
140#[serde(rename_all = "UPPERCASE")]
141pub enum BinancePositionSide {
142    /// Single position mode (both).
143    Both,
144    /// Long position.
145    Long,
146    /// Short position.
147    Short,
148    /// Unknown or undocumented value.
149    #[serde(other)]
150    Unknown,
151}
152
153/// Margin type applied to a position.
154#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
155#[serde(rename_all = "lowercase")]
156pub enum BinanceMarginType {
157    /// Cross margin.
158    Cross,
159    /// Isolated margin.
160    Isolated,
161    /// Unknown or undocumented value.
162    #[serde(other)]
163    Unknown,
164}
165
166/// Working type for trigger price evaluation.
167#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
168#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
169pub enum BinanceWorkingType {
170    /// Use the contract price.
171    ContractPrice,
172    /// Use the mark price.
173    MarkPrice,
174    /// Unknown or undocumented value.
175    #[serde(other)]
176    Unknown,
177}
178
179/// Order status lifecycle values.
180#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
181#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
182pub enum BinanceOrderStatus {
183    /// Order accepted and working.
184    New,
185    /// Partially filled.
186    PartiallyFilled,
187    /// Fully filled.
188    Filled,
189    /// Canceled by user or system.
190    Canceled,
191    /// Pending cancel (not commonly used).
192    PendingCancel,
193    /// Rejected by exchange.
194    Rejected,
195    /// Expired.
196    Expired,
197    /// Expired in match (IOC/FOK not executed).
198    ExpiredInMatch,
199    /// Unknown or undocumented value.
200    #[serde(other)]
201    Unknown,
202}
203
204/// Futures order type enumeration.
205#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
206#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
207pub enum BinanceFuturesOrderType {
208    /// Limit order.
209    Limit,
210    /// Market order.
211    Market,
212    /// Stop (stop-limit) order.
213    Stop,
214    /// Stop market order.
215    StopMarket,
216    /// Take profit (limit) order.
217    TakeProfit,
218    /// Take profit market order.
219    TakeProfitMarket,
220    /// Trailing stop market order.
221    TrailingStopMarket,
222    /// Liquidation order created by exchange.
223    Liquidation,
224    /// Auto-deleveraging order created by exchange.
225    Adl,
226    /// Unknown or undocumented value.
227    #[serde(other)]
228    Unknown,
229}
230
231/// Time in force options.
232#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
233#[serde(rename_all = "UPPERCASE")]
234pub enum BinanceTimeInForce {
235    /// Good till canceled.
236    Gtc,
237    /// Immediate or cancel.
238    Ioc,
239    /// Fill or kill.
240    Fok,
241    /// Good till crossing (post-only).
242    Gtx,
243    /// Good till date.
244    Gtd,
245    /// Unknown or undocumented value.
246    #[serde(other)]
247    Unknown,
248}
249
250/// Income type for account income history.
251#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
252#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
253pub enum BinanceIncomeType {
254    /// Internal transfers.
255    Transfer,
256    /// Welcome bonus.
257    WelcomeBonus,
258    /// Realized profit and loss.
259    RealizedPnl,
260    /// Funding fee payments/receipts.
261    FundingFee,
262    /// Trading commission.
263    Commission,
264    /// Insurance clear.
265    InsuranceClear,
266    /// Referral kickback.
267    ReferralKickback,
268    /// Unknown or undocumented value.
269    #[serde(other)]
270    Unknown,
271}
272
273/// Price match mode for futures maker orders.
274#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
275#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
276pub enum BinancePriceMatch {
277    /// Match opposing side (default).
278    Opponent,
279    /// Match opposing side with 5 tick offset.
280    Opponent5,
281    /// Match opposing side with 10 tick offset.
282    Opponent10,
283    /// Match opposing side with 20 tick offset.
284    Opponent20,
285    /// Join current queue on same side.
286    Queue,
287    /// Join queue with 5 tick offset.
288    Queue5,
289    /// Join queue with 10 tick offset.
290    Queue10,
291    /// Join queue with 20 tick offset.
292    Queue20,
293    /// Unknown or undocumented value.
294    #[serde(other)]
295    Unknown,
296}
297
298/// Self-trade prevention mode.
299#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
300#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
301pub enum BinanceSelfTradePreventionMode {
302    /// Expire maker orders on self-trade.
303    ExpireMaker,
304    /// Expire taker orders on self-trade.
305    ExpireTaker,
306    /// Expire both sides on self-trade.
307    ExpireBoth,
308    /// Unknown or undocumented value.
309    #[serde(other)]
310    Unknown,
311}
312
313/// Trading status for symbols.
314#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
315#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
316pub enum BinanceTradingStatus {
317    /// Trading is active.
318    Trading,
319    /// Pending activation.
320    PendingTrading,
321    /// Pre-trading session.
322    PreTrading,
323    /// Post-trading session.
324    PostTrading,
325    /// End of day.
326    EndOfDay,
327    /// Trading halted.
328    Halt,
329    /// Auction match.
330    AuctionMatch,
331    /// Break period.
332    Break,
333    /// Unknown or undocumented value.
334    #[serde(other)]
335    Unknown,
336}
337
338/// Contract status for coin-margined futures.
339#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
340#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
341pub enum BinanceContractStatus {
342    /// Trading is active.
343    Trading,
344    /// Pending trading.
345    PendingTrading,
346    /// Pre-delivering.
347    PreDelivering,
348    /// Delivering.
349    Delivering,
350    /// Delivered.
351    Delivered,
352    /// Pre-delist.
353    PreDelisting,
354    /// Delisting in progress.
355    Delisting,
356    /// Contract down.
357    Down,
358    /// Unknown or undocumented value.
359    #[serde(other)]
360    Unknown,
361}
362
363/// WebSocket stream event types.
364///
365/// These are the "e" field values in WebSocket JSON messages.
366#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
367#[serde(rename_all = "camelCase")]
368pub enum BinanceWsEventType {
369    /// Aggregate trade event.
370    AggTrade,
371    /// Individual trade event.
372    Trade,
373    /// Book ticker (best bid/ask) event.
374    BookTicker,
375    /// Depth update (order book delta) event.
376    DepthUpdate,
377    /// Mark price update event.
378    MarkPriceUpdate,
379    /// Kline/candlestick event.
380    Kline,
381    /// Forced liquidation order event.
382    ForceOrder,
383    /// 24-hour rolling ticker event.
384    #[serde(rename = "24hrTicker")]
385    Ticker24Hr,
386    /// 24-hour rolling mini ticker event.
387    #[serde(rename = "24hrMiniTicker")]
388    MiniTicker24Hr,
389    /// Unknown or undocumented event type.
390    #[serde(other)]
391    Unknown,
392}
393
394impl BinanceWsEventType {
395    /// Returns the wire format string for this event type.
396    #[must_use]
397    pub const fn as_str(self) -> &'static str {
398        match self {
399            Self::AggTrade => "aggTrade",
400            Self::Trade => "trade",
401            Self::BookTicker => "bookTicker",
402            Self::DepthUpdate => "depthUpdate",
403            Self::MarkPriceUpdate => "markPriceUpdate",
404            Self::Kline => "kline",
405            Self::ForceOrder => "forceOrder",
406            Self::Ticker24Hr => "24hrTicker",
407            Self::MiniTicker24Hr => "24hrMiniTicker",
408            Self::Unknown => "unknown",
409        }
410    }
411}
412
413impl std::fmt::Display for BinanceWsEventType {
414    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
415        write!(f, "{}", self.as_str())
416    }
417}
418
419/// WebSocket request method (operation type).
420///
421/// Used for subscription requests on both Spot and Futures WebSocket APIs.
422#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
423#[serde(rename_all = "UPPERCASE")]
424pub enum BinanceWsMethod {
425    /// Subscribe to streams.
426    Subscribe,
427    /// Unsubscribe from streams.
428    Unsubscribe,
429}
430
431/// Filter type identifiers returned in exchange info.
432#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
433#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
434pub enum BinanceFilterType {
435    /// Price filter.
436    PriceFilter,
437    /// Percent price filter.
438    PercentPrice,
439    /// Lot size filter.
440    LotSize,
441    /// Market lot size filter.
442    MarketLotSize,
443    /// Notional filter (spot).
444    Notional,
445    /// Min notional filter (futures).
446    MinNotional,
447    /// Maximum number of orders filter.
448    MaxNumOrders,
449    /// Maximum number of algo orders filter.
450    MaxNumAlgoOrders,
451    /// Unknown or undocumented value.
452    #[serde(other)]
453    Unknown,
454}
455
456impl std::fmt::Display for BinanceEnvironment {
457    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
458        match self {
459            Self::Mainnet => write!(f, "Mainnet"),
460            Self::Testnet => write!(f, "Testnet"),
461        }
462    }
463}
464
465#[cfg(test)]
466mod tests {
467    use rstest::rstest;
468
469    use super::*;
470
471    #[rstest]
472    fn test_product_type_as_str() {
473        assert_eq!(BinanceProductType::Spot.as_str(), "SPOT");
474        assert_eq!(BinanceProductType::Margin.as_str(), "MARGIN");
475        assert_eq!(BinanceProductType::UsdM.as_str(), "USD_M");
476        assert_eq!(BinanceProductType::CoinM.as_str(), "COIN_M");
477        assert_eq!(BinanceProductType::Options.as_str(), "OPTIONS");
478    }
479
480    #[rstest]
481    fn test_product_type_suffix() {
482        assert_eq!(BinanceProductType::Spot.suffix(), "-SPOT");
483        assert_eq!(BinanceProductType::Margin.suffix(), "-MARGIN");
484        assert_eq!(BinanceProductType::UsdM.suffix(), "-LINEAR");
485        assert_eq!(BinanceProductType::CoinM.suffix(), "-INVERSE");
486        assert_eq!(BinanceProductType::Options.suffix(), "-OPTION");
487    }
488
489    #[rstest]
490    fn test_product_type_predicates() {
491        assert!(BinanceProductType::Spot.is_spot());
492        assert!(BinanceProductType::Margin.is_spot());
493        assert!(!BinanceProductType::UsdM.is_spot());
494
495        assert!(BinanceProductType::UsdM.is_futures());
496        assert!(BinanceProductType::CoinM.is_futures());
497        assert!(!BinanceProductType::Spot.is_futures());
498
499        assert!(BinanceProductType::CoinM.is_inverse());
500        assert!(!BinanceProductType::UsdM.is_inverse());
501
502        assert!(BinanceProductType::Options.is_options());
503        assert!(!BinanceProductType::Spot.is_options());
504    }
505}