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