ccxt_core/
capability.rs

1//! Exchange Capabilities Module
2//!
3//! This module provides efficient representation and manipulation of exchange capabilities
4//! using bitflags for compact storage (8 bytes instead of 46+ bytes) and type-safe operations.
5//!
6// Allow missing docs for bitflags-generated constants which are self-documenting by name
7#![allow(missing_docs)]
8//!
9//! # Design
10//!
11//! The capability system uses a hybrid approach:
12//! - `Capability` enum: Individual capability identifiers for type-safe API
13//! - `Capabilities` bitflags: Efficient storage and set operations
14//! - `ExchangeCapabilities` struct: High-level API with backward compatibility
15//!
16//! # Example
17//!
18//! ```rust
19//! use ccxt_core::capability::{Capability, Capabilities, ExchangeCapabilities};
20//!
21//! // Using bitflags directly
22//! let caps = Capabilities::MARKET_DATA | Capabilities::TRADING;
23//! assert!(caps.contains(Capabilities::FETCH_TICKER));
24//!
25//! // Using the high-level API
26//! let exchange_caps = ExchangeCapabilities::public_only();
27//! assert!(exchange_caps.has("fetchTicker"));
28//! assert!(!exchange_caps.has("createOrder"));
29//! ```
30
31use bitflags::bitflags;
32use std::fmt;
33
34// ============================================================================
35// Capability Enum
36// ============================================================================
37
38/// Individual capability identifier
39///
40/// This enum provides type-safe capability names that can be converted to/from
41/// bitflags and string representations. It supports all 46 exchange capabilities
42/// organized into logical categories.
43///
44/// # Categories
45///
46/// - **Market Data**: Public API endpoints for market information
47/// - **Trading**: Order management and execution
48/// - **Account**: Balance and trade history
49/// - **Funding**: Deposits, withdrawals, and transfers
50/// - **Margin**: Margin/futures trading features
51/// - **WebSocket**: Real-time data streaming
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
53#[repr(u8)]
54pub enum Capability {
55    // ==================== Market Data (0-8) ====================
56    /// Can fetch market definitions
57    FetchMarkets = 0,
58    /// Can fetch currency definitions
59    FetchCurrencies = 1,
60    /// Can fetch single ticker
61    FetchTicker = 2,
62    /// Can fetch multiple tickers
63    FetchTickers = 3,
64    /// Can fetch order book
65    FetchOrderBook = 4,
66    /// Can fetch public trades
67    FetchTrades = 5,
68    /// Can fetch OHLCV candlestick data
69    FetchOhlcv = 6,
70    /// Can fetch exchange status
71    FetchStatus = 7,
72    /// Can fetch server time
73    FetchTime = 8,
74
75    // ==================== Trading (9-19) ====================
76    /// Can create orders
77    CreateOrder = 9,
78    /// Can create market orders
79    CreateMarketOrder = 10,
80    /// Can create limit orders
81    CreateLimitOrder = 11,
82    /// Can cancel orders
83    CancelOrder = 12,
84    /// Can cancel all orders
85    CancelAllOrders = 13,
86    /// Can edit/modify orders
87    EditOrder = 14,
88    /// Can fetch single order
89    FetchOrder = 15,
90    /// Can fetch all orders
91    FetchOrders = 16,
92    /// Can fetch open orders
93    FetchOpenOrders = 17,
94    /// Can fetch closed orders
95    FetchClosedOrders = 18,
96    /// Can fetch canceled orders
97    FetchCanceledOrders = 19,
98
99    // ==================== Account (20-25) ====================
100    /// Can fetch account balance
101    FetchBalance = 20,
102    /// Can fetch user's trade history
103    FetchMyTrades = 21,
104    /// Can fetch deposit history
105    FetchDeposits = 22,
106    /// Can fetch withdrawal history
107    FetchWithdrawals = 23,
108    /// Can fetch transaction history
109    FetchTransactions = 24,
110    /// Can fetch ledger entries
111    FetchLedger = 25,
112
113    // ==================== Funding (26-29) ====================
114    /// Can fetch deposit address
115    FetchDepositAddress = 26,
116    /// Can create deposit address
117    CreateDepositAddress = 27,
118    /// Can withdraw funds
119    Withdraw = 28,
120    /// Can transfer between accounts
121    Transfer = 29,
122
123    // ==================== Margin Trading (30-36) ====================
124    /// Can fetch borrow rate
125    FetchBorrowRate = 30,
126    /// Can fetch multiple borrow rates
127    FetchBorrowRates = 31,
128    /// Can fetch funding rate
129    FetchFundingRate = 32,
130    /// Can fetch multiple funding rates
131    FetchFundingRates = 33,
132    /// Can fetch positions
133    FetchPositions = 34,
134    /// Can set leverage
135    SetLeverage = 35,
136    /// Can set margin mode
137    SetMarginMode = 36,
138
139    // ==================== WebSocket (37-45) ====================
140    /// WebSocket support available
141    Websocket = 37,
142    /// Can watch ticker updates
143    WatchTicker = 38,
144    /// Can watch multiple ticker updates
145    WatchTickers = 39,
146    /// Can watch order book updates
147    WatchOrderBook = 40,
148    /// Can watch trade updates
149    WatchTrades = 41,
150    /// Can watch OHLCV updates
151    WatchOhlcv = 42,
152    /// Can watch balance updates
153    WatchBalance = 43,
154    /// Can watch order updates
155    WatchOrders = 44,
156    /// Can watch user trade updates
157    WatchMyTrades = 45,
158}
159
160impl Capability {
161    /// Total number of defined capabilities
162    pub const COUNT: usize = 46;
163
164    /// Get the CCXT-style camelCase name for this capability
165    ///
166    /// # Example
167    ///
168    /// ```rust
169    /// use ccxt_core::capability::Capability;
170    ///
171    /// assert_eq!(Capability::FetchTicker.as_ccxt_name(), "fetchTicker");
172    /// assert_eq!(Capability::CreateOrder.as_ccxt_name(), "createOrder");
173    /// ```
174    pub const fn as_ccxt_name(&self) -> &'static str {
175        match self {
176            // Market Data
177            Self::FetchMarkets => "fetchMarkets",
178            Self::FetchCurrencies => "fetchCurrencies",
179            Self::FetchTicker => "fetchTicker",
180            Self::FetchTickers => "fetchTickers",
181            Self::FetchOrderBook => "fetchOrderBook",
182            Self::FetchTrades => "fetchTrades",
183            Self::FetchOhlcv => "fetchOHLCV",
184            Self::FetchStatus => "fetchStatus",
185            Self::FetchTime => "fetchTime",
186            // Trading
187            Self::CreateOrder => "createOrder",
188            Self::CreateMarketOrder => "createMarketOrder",
189            Self::CreateLimitOrder => "createLimitOrder",
190            Self::CancelOrder => "cancelOrder",
191            Self::CancelAllOrders => "cancelAllOrders",
192            Self::EditOrder => "editOrder",
193            Self::FetchOrder => "fetchOrder",
194            Self::FetchOrders => "fetchOrders",
195            Self::FetchOpenOrders => "fetchOpenOrders",
196            Self::FetchClosedOrders => "fetchClosedOrders",
197            Self::FetchCanceledOrders => "fetchCanceledOrders",
198            // Account
199            Self::FetchBalance => "fetchBalance",
200            Self::FetchMyTrades => "fetchMyTrades",
201            Self::FetchDeposits => "fetchDeposits",
202            Self::FetchWithdrawals => "fetchWithdrawals",
203            Self::FetchTransactions => "fetchTransactions",
204            Self::FetchLedger => "fetchLedger",
205            // Funding
206            Self::FetchDepositAddress => "fetchDepositAddress",
207            Self::CreateDepositAddress => "createDepositAddress",
208            Self::Withdraw => "withdraw",
209            Self::Transfer => "transfer",
210            // Margin
211            Self::FetchBorrowRate => "fetchBorrowRate",
212            Self::FetchBorrowRates => "fetchBorrowRates",
213            Self::FetchFundingRate => "fetchFundingRate",
214            Self::FetchFundingRates => "fetchFundingRates",
215            Self::FetchPositions => "fetchPositions",
216            Self::SetLeverage => "setLeverage",
217            Self::SetMarginMode => "setMarginMode",
218            // WebSocket
219            Self::Websocket => "websocket",
220            Self::WatchTicker => "watchTicker",
221            Self::WatchTickers => "watchTickers",
222            Self::WatchOrderBook => "watchOrderBook",
223            Self::WatchTrades => "watchTrades",
224            Self::WatchOhlcv => "watchOHLCV",
225            Self::WatchBalance => "watchBalance",
226            Self::WatchOrders => "watchOrders",
227            Self::WatchMyTrades => "watchMyTrades",
228        }
229    }
230
231    /// Parse a CCXT-style camelCase name into a Capability
232    ///
233    /// # Example
234    ///
235    /// ```rust
236    /// use ccxt_core::capability::Capability;
237    ///
238    /// assert_eq!(Capability::from_ccxt_name("fetchTicker"), Some(Capability::FetchTicker));
239    /// assert_eq!(Capability::from_ccxt_name("unknown"), None);
240    /// ```
241    pub fn from_ccxt_name(name: &str) -> Option<Self> {
242        match name {
243            // Market Data
244            "fetchMarkets" => Some(Self::FetchMarkets),
245            "fetchCurrencies" => Some(Self::FetchCurrencies),
246            "fetchTicker" => Some(Self::FetchTicker),
247            "fetchTickers" => Some(Self::FetchTickers),
248            "fetchOrderBook" => Some(Self::FetchOrderBook),
249            "fetchTrades" => Some(Self::FetchTrades),
250            "fetchOHLCV" => Some(Self::FetchOhlcv),
251            "fetchStatus" => Some(Self::FetchStatus),
252            "fetchTime" => Some(Self::FetchTime),
253            // Trading
254            "createOrder" => Some(Self::CreateOrder),
255            "createMarketOrder" => Some(Self::CreateMarketOrder),
256            "createLimitOrder" => Some(Self::CreateLimitOrder),
257            "cancelOrder" => Some(Self::CancelOrder),
258            "cancelAllOrders" => Some(Self::CancelAllOrders),
259            "editOrder" => Some(Self::EditOrder),
260            "fetchOrder" => Some(Self::FetchOrder),
261            "fetchOrders" => Some(Self::FetchOrders),
262            "fetchOpenOrders" => Some(Self::FetchOpenOrders),
263            "fetchClosedOrders" => Some(Self::FetchClosedOrders),
264            "fetchCanceledOrders" => Some(Self::FetchCanceledOrders),
265            // Account
266            "fetchBalance" => Some(Self::FetchBalance),
267            "fetchMyTrades" => Some(Self::FetchMyTrades),
268            "fetchDeposits" => Some(Self::FetchDeposits),
269            "fetchWithdrawals" => Some(Self::FetchWithdrawals),
270            "fetchTransactions" => Some(Self::FetchTransactions),
271            "fetchLedger" => Some(Self::FetchLedger),
272            // Funding
273            "fetchDepositAddress" => Some(Self::FetchDepositAddress),
274            "createDepositAddress" => Some(Self::CreateDepositAddress),
275            "withdraw" => Some(Self::Withdraw),
276            "transfer" => Some(Self::Transfer),
277            // Margin
278            "fetchBorrowRate" => Some(Self::FetchBorrowRate),
279            "fetchBorrowRates" => Some(Self::FetchBorrowRates),
280            "fetchFundingRate" => Some(Self::FetchFundingRate),
281            "fetchFundingRates" => Some(Self::FetchFundingRates),
282            "fetchPositions" => Some(Self::FetchPositions),
283            "setLeverage" => Some(Self::SetLeverage),
284            "setMarginMode" => Some(Self::SetMarginMode),
285            // WebSocket
286            "websocket" => Some(Self::Websocket),
287            "watchTicker" => Some(Self::WatchTicker),
288            "watchTickers" => Some(Self::WatchTickers),
289            "watchOrderBook" => Some(Self::WatchOrderBook),
290            "watchTrades" => Some(Self::WatchTrades),
291            "watchOHLCV" => Some(Self::WatchOhlcv),
292            "watchBalance" => Some(Self::WatchBalance),
293            "watchOrders" => Some(Self::WatchOrders),
294            "watchMyTrades" => Some(Self::WatchMyTrades),
295            _ => None,
296        }
297    }
298
299    /// Get all capabilities as an array
300    pub const fn all() -> [Self; Self::COUNT] {
301        [
302            Self::FetchMarkets,
303            Self::FetchCurrencies,
304            Self::FetchTicker,
305            Self::FetchTickers,
306            Self::FetchOrderBook,
307            Self::FetchTrades,
308            Self::FetchOhlcv,
309            Self::FetchStatus,
310            Self::FetchTime,
311            Self::CreateOrder,
312            Self::CreateMarketOrder,
313            Self::CreateLimitOrder,
314            Self::CancelOrder,
315            Self::CancelAllOrders,
316            Self::EditOrder,
317            Self::FetchOrder,
318            Self::FetchOrders,
319            Self::FetchOpenOrders,
320            Self::FetchClosedOrders,
321            Self::FetchCanceledOrders,
322            Self::FetchBalance,
323            Self::FetchMyTrades,
324            Self::FetchDeposits,
325            Self::FetchWithdrawals,
326            Self::FetchTransactions,
327            Self::FetchLedger,
328            Self::FetchDepositAddress,
329            Self::CreateDepositAddress,
330            Self::Withdraw,
331            Self::Transfer,
332            Self::FetchBorrowRate,
333            Self::FetchBorrowRates,
334            Self::FetchFundingRate,
335            Self::FetchFundingRates,
336            Self::FetchPositions,
337            Self::SetLeverage,
338            Self::SetMarginMode,
339            Self::Websocket,
340            Self::WatchTicker,
341            Self::WatchTickers,
342            Self::WatchOrderBook,
343            Self::WatchTrades,
344            Self::WatchOhlcv,
345            Self::WatchBalance,
346            Self::WatchOrders,
347            Self::WatchMyTrades,
348        ]
349    }
350
351    /// Convert to bit position for bitflags
352    #[inline]
353    pub const fn bit_position(&self) -> u64 {
354        1u64 << (*self as u8)
355    }
356}
357
358impl fmt::Display for Capability {
359    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360        write!(f, "{}", self.as_ccxt_name())
361    }
362}
363
364// ============================================================================
365// Capabilities Bitflags
366// ============================================================================
367
368bitflags! {
369    /// Efficient bitflags representation of exchange capabilities
370    ///
371    /// Uses 64 bits to store all 46 capabilities, providing:
372    /// - Compact storage (8 bytes vs 46+ bytes for booleans)
373    /// - Fast set operations (union, intersection, difference)
374    /// - Type-safe capability combinations
375    ///
376    /// # Predefined Sets
377    ///
378    /// - `MARKET_DATA`: All public market data capabilities
379    /// - `TRADING`: All trading capabilities
380    /// - `ACCOUNT`: All account-related capabilities
381    /// - `FUNDING`: All funding capabilities
382    /// - `MARGIN`: All margin/futures capabilities
383    /// - `WEBSOCKET`: All WebSocket capabilities
384    /// - `ALL`: All capabilities enabled
385    /// - `NONE`: No capabilities
386    ///
387    /// # Example
388    ///
389    /// ```rust
390    /// use ccxt_core::capability::Capabilities;
391    ///
392    /// let caps = Capabilities::MARKET_DATA | Capabilities::TRADING;
393    /// assert!(caps.contains(Capabilities::FETCH_TICKER));
394    /// assert!(caps.contains(Capabilities::CREATE_ORDER));
395    /// ```
396    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
397    pub struct Capabilities: u64 {
398        // ==================== Market Data (bits 0-8) ====================
399        const FETCH_MARKETS     = 1 << 0;
400        const FETCH_CURRENCIES  = 1 << 1;
401        const FETCH_TICKER      = 1 << 2;
402        const FETCH_TICKERS     = 1 << 3;
403        const FETCH_ORDER_BOOK  = 1 << 4;
404        const FETCH_TRADES      = 1 << 5;
405        const FETCH_OHLCV       = 1 << 6;
406        const FETCH_STATUS      = 1 << 7;
407        const FETCH_TIME        = 1 << 8;
408
409        // ==================== Trading (bits 9-19) ====================
410        const CREATE_ORDER          = 1 << 9;
411        const CREATE_MARKET_ORDER   = 1 << 10;
412        const CREATE_LIMIT_ORDER    = 1 << 11;
413        const CANCEL_ORDER          = 1 << 12;
414        const CANCEL_ALL_ORDERS     = 1 << 13;
415        const EDIT_ORDER            = 1 << 14;
416        const FETCH_ORDER           = 1 << 15;
417        const FETCH_ORDERS          = 1 << 16;
418        const FETCH_OPEN_ORDERS     = 1 << 17;
419        const FETCH_CLOSED_ORDERS   = 1 << 18;
420        const FETCH_CANCELED_ORDERS = 1 << 19;
421
422        // ==================== Account (bits 20-25) ====================
423        const FETCH_BALANCE      = 1 << 20;
424        const FETCH_MY_TRADES    = 1 << 21;
425        const FETCH_DEPOSITS     = 1 << 22;
426        const FETCH_WITHDRAWALS  = 1 << 23;
427        const FETCH_TRANSACTIONS = 1 << 24;
428        const FETCH_LEDGER       = 1 << 25;
429
430        // ==================== Funding (bits 26-29) ====================
431        const FETCH_DEPOSIT_ADDRESS  = 1 << 26;
432        const CREATE_DEPOSIT_ADDRESS = 1 << 27;
433        const WITHDRAW               = 1 << 28;
434        const TRANSFER               = 1 << 29;
435
436        // ==================== Margin Trading (bits 30-36) ====================
437        const FETCH_BORROW_RATE   = 1 << 30;
438        const FETCH_BORROW_RATES  = 1 << 31;
439        const FETCH_FUNDING_RATE  = 1 << 32;
440        const FETCH_FUNDING_RATES = 1 << 33;
441        const FETCH_POSITIONS     = 1 << 34;
442        const SET_LEVERAGE        = 1 << 35;
443        const SET_MARGIN_MODE     = 1 << 36;
444
445        // ==================== WebSocket (bits 37-45) ====================
446        const WEBSOCKET        = 1 << 37;
447        const WATCH_TICKER     = 1 << 38;
448        const WATCH_TICKERS    = 1 << 39;
449        const WATCH_ORDER_BOOK = 1 << 40;
450        const WATCH_TRADES     = 1 << 41;
451        const WATCH_OHLCV      = 1 << 42;
452        const WATCH_BALANCE    = 1 << 43;
453        const WATCH_ORDERS     = 1 << 44;
454        const WATCH_MY_TRADES  = 1 << 45;
455
456        // ==================== Category Presets ====================
457        /// All public market data capabilities
458        const MARKET_DATA = Self::FETCH_MARKETS.bits()
459            | Self::FETCH_CURRENCIES.bits()
460            | Self::FETCH_TICKER.bits()
461            | Self::FETCH_TICKERS.bits()
462            | Self::FETCH_ORDER_BOOK.bits()
463            | Self::FETCH_TRADES.bits()
464            | Self::FETCH_OHLCV.bits()
465            | Self::FETCH_STATUS.bits()
466            | Self::FETCH_TIME.bits();
467
468        /// All trading capabilities
469        const TRADING = Self::CREATE_ORDER.bits()
470            | Self::CREATE_MARKET_ORDER.bits()
471            | Self::CREATE_LIMIT_ORDER.bits()
472            | Self::CANCEL_ORDER.bits()
473            | Self::CANCEL_ALL_ORDERS.bits()
474            | Self::EDIT_ORDER.bits()
475            | Self::FETCH_ORDER.bits()
476            | Self::FETCH_ORDERS.bits()
477            | Self::FETCH_OPEN_ORDERS.bits()
478            | Self::FETCH_CLOSED_ORDERS.bits()
479            | Self::FETCH_CANCELED_ORDERS.bits();
480
481        /// All account-related capabilities
482        const ACCOUNT = Self::FETCH_BALANCE.bits()
483            | Self::FETCH_MY_TRADES.bits()
484            | Self::FETCH_DEPOSITS.bits()
485            | Self::FETCH_WITHDRAWALS.bits()
486            | Self::FETCH_TRANSACTIONS.bits()
487            | Self::FETCH_LEDGER.bits();
488
489        /// All funding capabilities
490        const FUNDING = Self::FETCH_DEPOSIT_ADDRESS.bits()
491            | Self::CREATE_DEPOSIT_ADDRESS.bits()
492            | Self::WITHDRAW.bits()
493            | Self::TRANSFER.bits();
494
495        /// All margin/futures trading capabilities
496        const MARGIN = Self::FETCH_BORROW_RATE.bits()
497            | Self::FETCH_BORROW_RATES.bits()
498            | Self::FETCH_FUNDING_RATE.bits()
499            | Self::FETCH_FUNDING_RATES.bits()
500            | Self::FETCH_POSITIONS.bits()
501            | Self::SET_LEVERAGE.bits()
502            | Self::SET_MARGIN_MODE.bits();
503
504        /// All WebSocket capabilities
505        const WEBSOCKET_ALL = Self::WEBSOCKET.bits()
506            | Self::WATCH_TICKER.bits()
507            | Self::WATCH_TICKERS.bits()
508            | Self::WATCH_ORDER_BOOK.bits()
509            | Self::WATCH_TRADES.bits()
510            | Self::WATCH_OHLCV.bits()
511            | Self::WATCH_BALANCE.bits()
512            | Self::WATCH_ORDERS.bits()
513            | Self::WATCH_MY_TRADES.bits();
514
515        /// All REST API capabilities (no WebSocket)
516        const REST_ALL = Self::MARKET_DATA.bits()
517            | Self::TRADING.bits()
518            | Self::ACCOUNT.bits()
519            | Self::FUNDING.bits()
520            | Self::MARGIN.bits();
521
522        /// Public-only capabilities (no authentication required)
523        const PUBLIC_ONLY = Self::MARKET_DATA.bits();
524
525        /// All capabilities enabled
526        const ALL = Self::REST_ALL.bits() | Self::WEBSOCKET_ALL.bits();
527    }
528}
529
530impl Capabilities {
531    /// Check if a capability is supported by CCXT-style name
532    ///
533    /// # Example
534    ///
535    /// ```rust
536    /// use ccxt_core::capability::Capabilities;
537    ///
538    /// let caps = Capabilities::MARKET_DATA;
539    /// assert!(caps.has("fetchTicker"));
540    /// assert!(!caps.has("createOrder"));
541    /// ```
542    pub fn has(&self, capability: &str) -> bool {
543        if let Some(cap) = Capability::from_ccxt_name(capability) {
544            self.contains(Self::from(cap))
545        } else {
546            false
547        }
548    }
549
550    /// Get a list of all supported capability names
551    ///
552    /// # Example
553    ///
554    /// ```rust
555    /// use ccxt_core::capability::Capabilities;
556    ///
557    /// let caps = Capabilities::PUBLIC_ONLY;
558    /// let names = caps.supported_capabilities();
559    /// assert!(names.contains(&"fetchTicker"));
560    /// ```
561    pub fn supported_capabilities(&self) -> Vec<&'static str> {
562        Capability::all()
563            .iter()
564            .filter(|cap| self.contains(Self::from(**cap)))
565            .map(Capability::as_ccxt_name)
566            .collect()
567    }
568
569    /// Count the number of enabled capabilities
570    #[inline]
571    pub fn count(&self) -> u32 {
572        self.bits().count_ones()
573    }
574
575    /// Create from an iterator of capabilities
576    // Lint: should_implement_trait
577    // Reason: This method has different semantics than FromIterator - it's a convenience constructor
578    #[allow(clippy::should_implement_trait)]
579    pub fn from_iter<I: IntoIterator<Item = Capability>>(iter: I) -> Self {
580        let mut caps = Self::empty();
581        for cap in iter {
582            caps |= Self::from(cap);
583        }
584        caps
585    }
586}
587
588impl From<Capability> for Capabilities {
589    fn from(cap: Capability) -> Self {
590        Self::from_bits_truncate(cap.bit_position())
591    }
592}
593
594impl fmt::Display for Capabilities {
595    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
596        let caps = self.supported_capabilities();
597        write!(f, "[{}]", caps.join(", "))
598    }
599}
600
601// ============================================================================
602// Capabilities Builder Macro
603// ============================================================================
604
605/// Macro for building Capabilities with a concise syntax
606///
607/// # Examples
608///
609/// ```rust
610/// use ccxt_core::{capabilities, capability::Capabilities};
611///
612/// // Using predefined sets
613/// let caps = capabilities!(MARKET_DATA, TRADING);
614///
615/// // Using individual capabilities
616/// let caps = capabilities!(FETCH_TICKER, CREATE_ORDER, WEBSOCKET);
617///
618/// // Combining sets and individual capabilities
619/// let caps = capabilities!(MARKET_DATA | FETCH_BALANCE | WEBSOCKET);
620/// ```
621#[macro_export]
622macro_rules! capabilities {
623    // Single capability or set
624    ($cap:ident) => {
625        $crate::capability::Capabilities::$cap
626    };
627    // Multiple capabilities with |
628    ($cap:ident | $($rest:tt)+) => {
629        $crate::capability::Capabilities::$cap | capabilities!($($rest)+)
630    };
631    // Multiple capabilities with ,
632    ($cap:ident, $($rest:tt)+) => {
633        $crate::capability::Capabilities::$cap | capabilities!($($rest)+)
634    };
635}
636
637// ============================================================================
638// ExchangeCapabilities Struct (Backward Compatible)
639// ============================================================================
640
641/// Exchange capabilities configuration
642///
643/// This struct provides a high-level API for working with exchange capabilities,
644/// maintaining backward compatibility with the original boolean-field design
645/// while using efficient bitflags internally.
646///
647/// # Example
648///
649/// ```rust
650/// use ccxt_core::capability::ExchangeCapabilities;
651///
652/// let caps = ExchangeCapabilities::public_only();
653/// assert!(caps.has("fetchTicker"));
654/// assert!(!caps.has("createOrder"));
655///
656/// let caps = ExchangeCapabilities::all();
657/// assert!(caps.fetch_ticker());
658/// assert!(caps.create_order());
659/// ```
660#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
661pub struct ExchangeCapabilities {
662    inner: Capabilities,
663}
664
665impl ExchangeCapabilities {
666    /// Create with no capabilities enabled
667    pub const fn none() -> Self {
668        Self {
669            inner: Capabilities::empty(),
670        }
671    }
672
673    /// Create capabilities with all features enabled
674    ///
675    /// # Example
676    ///
677    /// ```rust
678    /// use ccxt_core::capability::ExchangeCapabilities;
679    ///
680    /// let caps = ExchangeCapabilities::all();
681    /// assert!(caps.fetch_ticker());
682    /// assert!(caps.create_order());
683    /// assert!(caps.websocket());
684    /// ```
685    pub const fn all() -> Self {
686        Self {
687            inner: Capabilities::ALL,
688        }
689    }
690
691    /// Create capabilities for public API only (no authentication required)
692    ///
693    /// # Example
694    ///
695    /// ```rust
696    /// use ccxt_core::capability::ExchangeCapabilities;
697    ///
698    /// let caps = ExchangeCapabilities::public_only();
699    /// assert!(caps.fetch_ticker());
700    /// assert!(!caps.create_order());
701    /// ```
702    pub const fn public_only() -> Self {
703        Self {
704            inner: Capabilities::PUBLIC_ONLY,
705        }
706    }
707
708    /// Create from raw Capabilities bitflags
709    pub const fn from_capabilities(caps: Capabilities) -> Self {
710        Self { inner: caps }
711    }
712
713    /// Get the underlying Capabilities bitflags
714    pub const fn as_capabilities(&self) -> Capabilities {
715        self.inner
716    }
717
718    /// Check if a capability is supported by name
719    ///
720    /// This method allows checking capabilities using CCXT-style camelCase names.
721    ///
722    /// # Arguments
723    ///
724    /// * `capability` - The capability name in camelCase format
725    ///
726    /// # Example
727    ///
728    /// ```rust
729    /// use ccxt_core::capability::ExchangeCapabilities;
730    ///
731    /// let caps = ExchangeCapabilities::all();
732    /// assert!(caps.has("fetchTicker"));
733    /// assert!(caps.has("createOrder"));
734    /// assert!(!caps.has("unknownCapability"));
735    /// ```
736    pub fn has(&self, capability: &str) -> bool {
737        self.inner.has(capability)
738    }
739
740    /// Get a list of all supported capability names
741    pub fn supported_capabilities(&self) -> Vec<&'static str> {
742        self.inner.supported_capabilities()
743    }
744
745    /// Count the number of enabled capabilities
746    #[inline]
747    pub fn count(&self) -> u32 {
748        self.inner.count()
749    }
750
751    // ==================== Market Data Accessors ====================
752
753    /// Can fetch market definitions
754    #[inline]
755    pub const fn fetch_markets(&self) -> bool {
756        self.inner.contains(Capabilities::FETCH_MARKETS)
757    }
758
759    /// Can fetch currency definitions
760    #[inline]
761    pub const fn fetch_currencies(&self) -> bool {
762        self.inner.contains(Capabilities::FETCH_CURRENCIES)
763    }
764
765    /// Can fetch single ticker
766    #[inline]
767    pub const fn fetch_ticker(&self) -> bool {
768        self.inner.contains(Capabilities::FETCH_TICKER)
769    }
770
771    /// Can fetch multiple tickers
772    #[inline]
773    pub const fn fetch_tickers(&self) -> bool {
774        self.inner.contains(Capabilities::FETCH_TICKERS)
775    }
776
777    /// Can fetch order book
778    #[inline]
779    pub const fn fetch_order_book(&self) -> bool {
780        self.inner.contains(Capabilities::FETCH_ORDER_BOOK)
781    }
782
783    /// Can fetch public trades
784    #[inline]
785    pub const fn fetch_trades(&self) -> bool {
786        self.inner.contains(Capabilities::FETCH_TRADES)
787    }
788
789    /// Can fetch OHLCV candlestick data
790    #[inline]
791    pub const fn fetch_ohlcv(&self) -> bool {
792        self.inner.contains(Capabilities::FETCH_OHLCV)
793    }
794
795    /// Can fetch exchange status
796    #[inline]
797    pub const fn fetch_status(&self) -> bool {
798        self.inner.contains(Capabilities::FETCH_STATUS)
799    }
800
801    /// Can fetch server time
802    #[inline]
803    pub const fn fetch_time(&self) -> bool {
804        self.inner.contains(Capabilities::FETCH_TIME)
805    }
806
807    // ==================== Trading Accessors ====================
808
809    /// Can create orders
810    #[inline]
811    pub const fn create_order(&self) -> bool {
812        self.inner.contains(Capabilities::CREATE_ORDER)
813    }
814
815    /// Can create market orders
816    #[inline]
817    pub const fn create_market_order(&self) -> bool {
818        self.inner.contains(Capabilities::CREATE_MARKET_ORDER)
819    }
820
821    /// Can create limit orders
822    #[inline]
823    pub const fn create_limit_order(&self) -> bool {
824        self.inner.contains(Capabilities::CREATE_LIMIT_ORDER)
825    }
826
827    /// Can cancel orders
828    #[inline]
829    pub const fn cancel_order(&self) -> bool {
830        self.inner.contains(Capabilities::CANCEL_ORDER)
831    }
832
833    /// Can cancel all orders
834    #[inline]
835    pub const fn cancel_all_orders(&self) -> bool {
836        self.inner.contains(Capabilities::CANCEL_ALL_ORDERS)
837    }
838
839    /// Can edit/modify orders
840    #[inline]
841    pub const fn edit_order(&self) -> bool {
842        self.inner.contains(Capabilities::EDIT_ORDER)
843    }
844
845    /// Can fetch single order
846    #[inline]
847    pub const fn fetch_order(&self) -> bool {
848        self.inner.contains(Capabilities::FETCH_ORDER)
849    }
850
851    /// Can fetch all orders
852    #[inline]
853    pub const fn fetch_orders(&self) -> bool {
854        self.inner.contains(Capabilities::FETCH_ORDERS)
855    }
856
857    /// Can fetch open orders
858    #[inline]
859    pub const fn fetch_open_orders(&self) -> bool {
860        self.inner.contains(Capabilities::FETCH_OPEN_ORDERS)
861    }
862
863    /// Can fetch closed orders
864    #[inline]
865    pub const fn fetch_closed_orders(&self) -> bool {
866        self.inner.contains(Capabilities::FETCH_CLOSED_ORDERS)
867    }
868
869    /// Can fetch canceled orders
870    #[inline]
871    pub const fn fetch_canceled_orders(&self) -> bool {
872        self.inner.contains(Capabilities::FETCH_CANCELED_ORDERS)
873    }
874
875    // ==================== Account Accessors ====================
876
877    /// Can fetch account balance
878    #[inline]
879    pub const fn fetch_balance(&self) -> bool {
880        self.inner.contains(Capabilities::FETCH_BALANCE)
881    }
882
883    /// Can fetch user's trade history
884    #[inline]
885    pub const fn fetch_my_trades(&self) -> bool {
886        self.inner.contains(Capabilities::FETCH_MY_TRADES)
887    }
888
889    /// Can fetch deposit history
890    #[inline]
891    pub const fn fetch_deposits(&self) -> bool {
892        self.inner.contains(Capabilities::FETCH_DEPOSITS)
893    }
894
895    /// Can fetch withdrawal history
896    #[inline]
897    pub const fn fetch_withdrawals(&self) -> bool {
898        self.inner.contains(Capabilities::FETCH_WITHDRAWALS)
899    }
900
901    /// Can fetch transaction history
902    #[inline]
903    pub const fn fetch_transactions(&self) -> bool {
904        self.inner.contains(Capabilities::FETCH_TRANSACTIONS)
905    }
906
907    /// Can fetch ledger entries
908    #[inline]
909    pub const fn fetch_ledger(&self) -> bool {
910        self.inner.contains(Capabilities::FETCH_LEDGER)
911    }
912
913    // ==================== Funding Accessors ====================
914
915    /// Can fetch deposit address
916    #[inline]
917    pub const fn fetch_deposit_address(&self) -> bool {
918        self.inner.contains(Capabilities::FETCH_DEPOSIT_ADDRESS)
919    }
920
921    /// Can create deposit address
922    #[inline]
923    pub const fn create_deposit_address(&self) -> bool {
924        self.inner.contains(Capabilities::CREATE_DEPOSIT_ADDRESS)
925    }
926
927    /// Can withdraw funds
928    #[inline]
929    pub const fn withdraw(&self) -> bool {
930        self.inner.contains(Capabilities::WITHDRAW)
931    }
932
933    /// Can transfer between accounts
934    #[inline]
935    pub const fn transfer(&self) -> bool {
936        self.inner.contains(Capabilities::TRANSFER)
937    }
938
939    // ==================== Margin Trading Accessors ====================
940
941    /// Can fetch borrow rate
942    #[inline]
943    pub const fn fetch_borrow_rate(&self) -> bool {
944        self.inner.contains(Capabilities::FETCH_BORROW_RATE)
945    }
946
947    /// Can fetch multiple borrow rates
948    #[inline]
949    pub const fn fetch_borrow_rates(&self) -> bool {
950        self.inner.contains(Capabilities::FETCH_BORROW_RATES)
951    }
952
953    /// Can fetch funding rate
954    #[inline]
955    pub const fn fetch_funding_rate(&self) -> bool {
956        self.inner.contains(Capabilities::FETCH_FUNDING_RATE)
957    }
958
959    /// Can fetch multiple funding rates
960    #[inline]
961    pub const fn fetch_funding_rates(&self) -> bool {
962        self.inner.contains(Capabilities::FETCH_FUNDING_RATES)
963    }
964
965    /// Can fetch positions
966    #[inline]
967    pub const fn fetch_positions(&self) -> bool {
968        self.inner.contains(Capabilities::FETCH_POSITIONS)
969    }
970
971    /// Can set leverage
972    #[inline]
973    pub const fn set_leverage(&self) -> bool {
974        self.inner.contains(Capabilities::SET_LEVERAGE)
975    }
976
977    /// Can set margin mode
978    #[inline]
979    pub const fn set_margin_mode(&self) -> bool {
980        self.inner.contains(Capabilities::SET_MARGIN_MODE)
981    }
982
983    // ==================== WebSocket Accessors ====================
984
985    /// WebSocket support available
986    #[inline]
987    pub const fn websocket(&self) -> bool {
988        self.inner.contains(Capabilities::WEBSOCKET)
989    }
990
991    /// Can watch ticker updates
992    #[inline]
993    pub const fn watch_ticker(&self) -> bool {
994        self.inner.contains(Capabilities::WATCH_TICKER)
995    }
996
997    /// Can watch multiple ticker updates
998    #[inline]
999    pub const fn watch_tickers(&self) -> bool {
1000        self.inner.contains(Capabilities::WATCH_TICKERS)
1001    }
1002
1003    /// Can watch order book updates
1004    #[inline]
1005    pub const fn watch_order_book(&self) -> bool {
1006        self.inner.contains(Capabilities::WATCH_ORDER_BOOK)
1007    }
1008
1009    /// Can watch trade updates
1010    #[inline]
1011    pub const fn watch_trades(&self) -> bool {
1012        self.inner.contains(Capabilities::WATCH_TRADES)
1013    }
1014
1015    /// Can watch OHLCV updates
1016    #[inline]
1017    pub const fn watch_ohlcv(&self) -> bool {
1018        self.inner.contains(Capabilities::WATCH_OHLCV)
1019    }
1020
1021    /// Can watch balance updates
1022    #[inline]
1023    pub const fn watch_balance(&self) -> bool {
1024        self.inner.contains(Capabilities::WATCH_BALANCE)
1025    }
1026
1027    /// Can watch order updates
1028    #[inline]
1029    pub const fn watch_orders(&self) -> bool {
1030        self.inner.contains(Capabilities::WATCH_ORDERS)
1031    }
1032
1033    /// Can watch user trade updates
1034    #[inline]
1035    pub const fn watch_my_trades(&self) -> bool {
1036        self.inner.contains(Capabilities::WATCH_MY_TRADES)
1037    }
1038
1039    // ==================== Builder Method ====================
1040
1041    /// Create a builder for ExchangeCapabilities
1042    ///
1043    /// # Example
1044    ///
1045    /// ```rust
1046    /// use ccxt_core::capability::ExchangeCapabilities;
1047    ///
1048    /// let caps = ExchangeCapabilities::builder()
1049    ///     .market_data()
1050    ///     .trading()
1051    ///     .websocket()
1052    ///     .build();
1053    /// assert!(caps.fetch_ticker());
1054    /// assert!(caps.create_order());
1055    /// assert!(caps.websocket());
1056    /// ```
1057    pub fn builder() -> ExchangeCapabilitiesBuilder {
1058        ExchangeCapabilitiesBuilder::new()
1059    }
1060}
1061
1062impl From<Capabilities> for ExchangeCapabilities {
1063    fn from(caps: Capabilities) -> Self {
1064        Self::from_capabilities(caps)
1065    }
1066}
1067
1068impl fmt::Display for ExchangeCapabilities {
1069    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1070        write!(f, "ExchangeCapabilities({})", self.inner)
1071    }
1072}
1073
1074// ============================================================================
1075// ExchangeCapabilities Builder
1076// ============================================================================
1077
1078/// Builder for ExchangeCapabilities
1079///
1080/// Provides a fluent API for constructing capability sets.
1081///
1082/// # Example
1083///
1084/// ```rust
1085/// use ccxt_core::capability::ExchangeCapabilitiesBuilder;
1086///
1087/// let caps = ExchangeCapabilitiesBuilder::new()
1088///     .market_data()
1089///     .trading()
1090///     .capability(ccxt_core::capability::Capability::Websocket)
1091///     .build();
1092/// ```
1093#[derive(Debug, Clone, Default)]
1094pub struct ExchangeCapabilitiesBuilder {
1095    inner: Capabilities,
1096}
1097
1098impl ExchangeCapabilitiesBuilder {
1099    /// Create a new builder with no capabilities
1100    pub fn new() -> Self {
1101        Self {
1102            inner: Capabilities::empty(),
1103        }
1104    }
1105
1106    /// Add all market data capabilities
1107    pub fn market_data(mut self) -> Self {
1108        self.inner |= Capabilities::MARKET_DATA;
1109        self
1110    }
1111
1112    /// Add all trading capabilities
1113    pub fn trading(mut self) -> Self {
1114        self.inner |= Capabilities::TRADING;
1115        self
1116    }
1117
1118    /// Add all account capabilities
1119    pub fn account(mut self) -> Self {
1120        self.inner |= Capabilities::ACCOUNT;
1121        self
1122    }
1123
1124    /// Add all funding capabilities
1125    pub fn funding(mut self) -> Self {
1126        self.inner |= Capabilities::FUNDING;
1127        self
1128    }
1129
1130    /// Add all margin trading capabilities
1131    pub fn margin(mut self) -> Self {
1132        self.inner |= Capabilities::MARGIN;
1133        self
1134    }
1135
1136    /// Add all WebSocket capabilities
1137    pub fn websocket_all(mut self) -> Self {
1138        self.inner |= Capabilities::WEBSOCKET_ALL;
1139        self
1140    }
1141
1142    /// Add just the WebSocket base capability
1143    pub fn websocket(mut self) -> Self {
1144        self.inner |= Capabilities::WEBSOCKET;
1145        self
1146    }
1147
1148    /// Add all REST API capabilities
1149    pub fn rest_all(mut self) -> Self {
1150        self.inner |= Capabilities::REST_ALL;
1151        self
1152    }
1153
1154    /// Add all capabilities
1155    pub fn all(mut self) -> Self {
1156        self.inner = Capabilities::ALL;
1157        self
1158    }
1159
1160    /// Add a specific capability
1161    pub fn capability(mut self, cap: Capability) -> Self {
1162        self.inner |= Capabilities::from(cap);
1163        self
1164    }
1165
1166    /// Add multiple capabilities
1167    pub fn capabilities<I: IntoIterator<Item = Capability>>(mut self, caps: I) -> Self {
1168        for cap in caps {
1169            self.inner |= Capabilities::from(cap);
1170        }
1171        self
1172    }
1173
1174    /// Add raw Capabilities bitflags
1175    pub fn raw(mut self, caps: Capabilities) -> Self {
1176        self.inner |= caps;
1177        self
1178    }
1179
1180    /// Remove a specific capability
1181    pub fn without_capability(mut self, cap: Capability) -> Self {
1182        self.inner.remove(Capabilities::from(cap));
1183        self
1184    }
1185
1186    /// Remove capabilities
1187    pub fn without(mut self, caps: Capabilities) -> Self {
1188        self.inner.remove(caps);
1189        self
1190    }
1191
1192    /// Build the ExchangeCapabilities
1193    pub fn build(self) -> ExchangeCapabilities {
1194        ExchangeCapabilities { inner: self.inner }
1195    }
1196}
1197
1198// ============================================================================
1199// Presets for Common Exchange Configurations
1200// ============================================================================
1201
1202impl ExchangeCapabilities {
1203    /// Create capabilities for a typical spot exchange
1204    ///
1205    /// Includes: market data, trading, account, and basic WebSocket
1206    pub const fn spot_exchange() -> Self {
1207        Self {
1208            inner: Capabilities::from_bits_truncate(
1209                Capabilities::MARKET_DATA.bits()
1210                    | Capabilities::TRADING.bits()
1211                    | Capabilities::ACCOUNT.bits()
1212                    | Capabilities::WEBSOCKET.bits()
1213                    | Capabilities::WATCH_TICKER.bits()
1214                    | Capabilities::WATCH_ORDER_BOOK.bits()
1215                    | Capabilities::WATCH_TRADES.bits(),
1216            ),
1217        }
1218    }
1219
1220    /// Create capabilities for a typical futures exchange
1221    ///
1222    /// Includes: spot capabilities + margin trading
1223    pub const fn futures_exchange() -> Self {
1224        Self {
1225            inner: Capabilities::from_bits_truncate(
1226                Capabilities::MARKET_DATA.bits()
1227                    | Capabilities::TRADING.bits()
1228                    | Capabilities::ACCOUNT.bits()
1229                    | Capabilities::MARGIN.bits()
1230                    | Capabilities::WEBSOCKET_ALL.bits(),
1231            ),
1232        }
1233    }
1234
1235    /// Create capabilities for a full-featured exchange (like Binance)
1236    ///
1237    /// Includes: all capabilities
1238    pub const fn full_featured() -> Self {
1239        Self {
1240            inner: Capabilities::ALL,
1241        }
1242    }
1243}
1244
1245// ============================================================================
1246// Trait-Capability Mapping
1247// ============================================================================
1248
1249/// Trait category for capability-to-trait mapping.
1250///
1251/// This enum represents the decomposed trait hierarchy used in the exchange
1252/// trait system. Each variant corresponds to a specific trait that exchanges
1253/// can implement.
1254///
1255/// # Trait Hierarchy
1256///
1257/// ```text
1258/// PublicExchange (base trait - metadata, capabilities)
1259///     │
1260///     ├── MarketData (public market data)
1261///     ├── Trading (order management)
1262///     ├── Account (balance, trade history)
1263///     ├── Margin (positions, leverage, funding)
1264///     └── Funding (deposits, withdrawals, transfers)
1265///
1266/// FullExchange = PublicExchange + MarketData + Trading + Account + Margin + Funding
1267/// ```
1268///
1269/// # Capability Mapping
1270///
1271/// | Trait Category | Capabilities |
1272/// |----------------|--------------|
1273/// | `PublicExchange` | Base trait, always required |
1274/// | `MarketData` | FetchMarkets, FetchCurrencies, FetchTicker, FetchTickers, FetchOrderBook, FetchTrades, FetchOhlcv, FetchStatus, FetchTime |
1275/// | `Trading` | CreateOrder, CreateMarketOrder, CreateLimitOrder, CancelOrder, CancelAllOrders, EditOrder, FetchOrder, FetchOrders, FetchOpenOrders, FetchClosedOrders, FetchCanceledOrders |
1276/// | `Account` | FetchBalance, FetchMyTrades, FetchDeposits, FetchWithdrawals, FetchTransactions, FetchLedger |
1277/// | `Margin` | FetchBorrowRate, FetchBorrowRates, FetchFundingRate, FetchFundingRates, FetchPositions, SetLeverage, SetMarginMode |
1278/// | `Funding` | FetchDepositAddress, CreateDepositAddress, Withdraw, Transfer |
1279/// | `WebSocket` | Websocket, WatchTicker, WatchTickers, WatchOrderBook, WatchTrades, WatchOhlcv, WatchBalance, WatchOrders, WatchMyTrades |
1280#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1281pub enum TraitCategory {
1282    /// Base trait providing exchange metadata and capabilities.
1283    /// All exchanges must implement this trait.
1284    PublicExchange,
1285    /// Public market data operations (ticker, orderbook, trades, OHLCV).
1286    /// Corresponds to the `MarketData` trait.
1287    MarketData,
1288    /// Order management operations (create, cancel, fetch orders).
1289    /// Corresponds to the `Trading` trait.
1290    Trading,
1291    /// Account-related operations (balance, trade history).
1292    /// Corresponds to the `Account` trait.
1293    Account,
1294    /// Margin/futures trading operations (positions, leverage, funding).
1295    /// Corresponds to the `Margin` trait.
1296    Margin,
1297    /// Deposit/withdrawal operations.
1298    /// Corresponds to the `Funding` trait.
1299    Funding,
1300    /// WebSocket real-time data streaming.
1301    /// Corresponds to the `WsExchange` trait.
1302    WebSocket,
1303}
1304
1305impl TraitCategory {
1306    /// Get all trait categories.
1307    pub const fn all() -> [Self; 7] {
1308        [
1309            Self::PublicExchange,
1310            Self::MarketData,
1311            Self::Trading,
1312            Self::Account,
1313            Self::Margin,
1314            Self::Funding,
1315            Self::WebSocket,
1316        ]
1317    }
1318
1319    /// Get the display name for this trait category.
1320    pub const fn name(&self) -> &'static str {
1321        match self {
1322            Self::PublicExchange => "PublicExchange",
1323            Self::MarketData => "MarketData",
1324            Self::Trading => "Trading",
1325            Self::Account => "Account",
1326            Self::Margin => "Margin",
1327            Self::Funding => "Funding",
1328            Self::WebSocket => "WebSocket",
1329        }
1330    }
1331
1332    /// Get the capabilities associated with this trait category.
1333    pub const fn capabilities(&self) -> Capabilities {
1334        match self {
1335            Self::PublicExchange => Capabilities::empty(), // Base trait, no specific capabilities
1336            Self::MarketData => Capabilities::MARKET_DATA,
1337            Self::Trading => Capabilities::TRADING,
1338            Self::Account => Capabilities::ACCOUNT,
1339            Self::Margin => Capabilities::MARGIN,
1340            Self::Funding => Capabilities::FUNDING,
1341            Self::WebSocket => Capabilities::WEBSOCKET_ALL,
1342        }
1343    }
1344
1345    /// Get the minimum required capabilities for this trait.
1346    ///
1347    /// Returns the capabilities that MUST be present for an exchange
1348    /// to be considered as implementing this trait.
1349    pub const fn minimum_capabilities(&self) -> Capabilities {
1350        match self {
1351            Self::PublicExchange => Capabilities::empty(),
1352            // MarketData requires at least fetch_markets and fetch_ticker
1353            Self::MarketData => Capabilities::from_bits_truncate(
1354                Capabilities::FETCH_MARKETS.bits() | Capabilities::FETCH_TICKER.bits(),
1355            ),
1356            // Trading requires at least create_order and cancel_order
1357            Self::Trading => Capabilities::from_bits_truncate(
1358                Capabilities::CREATE_ORDER.bits() | Capabilities::CANCEL_ORDER.bits(),
1359            ),
1360            // Account requires at least fetch_balance
1361            Self::Account => Capabilities::FETCH_BALANCE,
1362            // Margin requires at least fetch_positions
1363            Self::Margin => Capabilities::FETCH_POSITIONS,
1364            // Funding requires at least fetch_deposit_address
1365            Self::Funding => Capabilities::FETCH_DEPOSIT_ADDRESS,
1366            // WebSocket requires the base websocket capability
1367            Self::WebSocket => Capabilities::WEBSOCKET,
1368        }
1369    }
1370}
1371
1372impl fmt::Display for TraitCategory {
1373    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1374        write!(f, "{}", self.name())
1375    }
1376}
1377
1378impl Capability {
1379    /// Get the trait category this capability belongs to.
1380    ///
1381    /// # Example
1382    ///
1383    /// ```rust
1384    /// use ccxt_core::capability::{Capability, TraitCategory};
1385    ///
1386    /// assert_eq!(Capability::FetchTicker.trait_category(), TraitCategory::MarketData);
1387    /// assert_eq!(Capability::CreateOrder.trait_category(), TraitCategory::Trading);
1388    /// assert_eq!(Capability::FetchBalance.trait_category(), TraitCategory::Account);
1389    /// ```
1390    pub const fn trait_category(&self) -> TraitCategory {
1391        match self {
1392            // Market Data
1393            Self::FetchMarkets
1394            | Self::FetchCurrencies
1395            | Self::FetchTicker
1396            | Self::FetchTickers
1397            | Self::FetchOrderBook
1398            | Self::FetchTrades
1399            | Self::FetchOhlcv
1400            | Self::FetchStatus
1401            | Self::FetchTime => TraitCategory::MarketData,
1402
1403            // Trading
1404            Self::CreateOrder
1405            | Self::CreateMarketOrder
1406            | Self::CreateLimitOrder
1407            | Self::CancelOrder
1408            | Self::CancelAllOrders
1409            | Self::EditOrder
1410            | Self::FetchOrder
1411            | Self::FetchOrders
1412            | Self::FetchOpenOrders
1413            | Self::FetchClosedOrders
1414            | Self::FetchCanceledOrders => TraitCategory::Trading,
1415
1416            // Account
1417            Self::FetchBalance
1418            | Self::FetchMyTrades
1419            | Self::FetchDeposits
1420            | Self::FetchWithdrawals
1421            | Self::FetchTransactions
1422            | Self::FetchLedger => TraitCategory::Account,
1423
1424            // Funding
1425            Self::FetchDepositAddress
1426            | Self::CreateDepositAddress
1427            | Self::Withdraw
1428            | Self::Transfer => TraitCategory::Funding,
1429
1430            // Margin
1431            Self::FetchBorrowRate
1432            | Self::FetchBorrowRates
1433            | Self::FetchFundingRate
1434            | Self::FetchFundingRates
1435            | Self::FetchPositions
1436            | Self::SetLeverage
1437            | Self::SetMarginMode => TraitCategory::Margin,
1438
1439            // WebSocket
1440            Self::Websocket
1441            | Self::WatchTicker
1442            | Self::WatchTickers
1443            | Self::WatchOrderBook
1444            | Self::WatchTrades
1445            | Self::WatchOhlcv
1446            | Self::WatchBalance
1447            | Self::WatchOrders
1448            | Self::WatchMyTrades => TraitCategory::WebSocket,
1449        }
1450    }
1451}
1452
1453impl ExchangeCapabilities {
1454    // ========================================================================
1455    // Trait Implementation Checks
1456    // ========================================================================
1457
1458    /// Check if the exchange supports the MarketData trait.
1459    ///
1460    /// Returns `true` if the exchange has the minimum capabilities required
1461    /// to implement the `MarketData` trait (fetch_markets and fetch_ticker).
1462    ///
1463    /// # Example
1464    ///
1465    /// ```rust
1466    /// use ccxt_core::capability::ExchangeCapabilities;
1467    ///
1468    /// let caps = ExchangeCapabilities::public_only();
1469    /// assert!(caps.supports_market_data());
1470    ///
1471    /// let caps = ExchangeCapabilities::none();
1472    /// assert!(!caps.supports_market_data());
1473    /// ```
1474    #[inline]
1475    pub const fn supports_market_data(&self) -> bool {
1476        self.inner
1477            .contains(TraitCategory::MarketData.minimum_capabilities())
1478    }
1479
1480    /// Check if the exchange supports the Trading trait.
1481    ///
1482    /// Returns `true` if the exchange has the minimum capabilities required
1483    /// to implement the `Trading` trait (create_order and cancel_order).
1484    ///
1485    /// # Example
1486    ///
1487    /// ```rust
1488    /// use ccxt_core::capability::ExchangeCapabilities;
1489    ///
1490    /// let caps = ExchangeCapabilities::all();
1491    /// assert!(caps.supports_trading());
1492    ///
1493    /// let caps = ExchangeCapabilities::public_only();
1494    /// assert!(!caps.supports_trading());
1495    /// ```
1496    #[inline]
1497    pub const fn supports_trading(&self) -> bool {
1498        self.inner
1499            .contains(TraitCategory::Trading.minimum_capabilities())
1500    }
1501
1502    /// Check if the exchange supports the Account trait.
1503    ///
1504    /// Returns `true` if the exchange has the minimum capabilities required
1505    /// to implement the `Account` trait (fetch_balance).
1506    ///
1507    /// # Example
1508    ///
1509    /// ```rust
1510    /// use ccxt_core::capability::ExchangeCapabilities;
1511    ///
1512    /// let caps = ExchangeCapabilities::all();
1513    /// assert!(caps.supports_account());
1514    ///
1515    /// let caps = ExchangeCapabilities::public_only();
1516    /// assert!(!caps.supports_account());
1517    /// ```
1518    #[inline]
1519    pub const fn supports_account(&self) -> bool {
1520        self.inner
1521            .contains(TraitCategory::Account.minimum_capabilities())
1522    }
1523
1524    /// Check if the exchange supports the Margin trait.
1525    ///
1526    /// Returns `true` if the exchange has the minimum capabilities required
1527    /// to implement the `Margin` trait (fetch_positions).
1528    ///
1529    /// # Example
1530    ///
1531    /// ```rust
1532    /// use ccxt_core::capability::ExchangeCapabilities;
1533    ///
1534    /// let caps = ExchangeCapabilities::futures_exchange();
1535    /// assert!(caps.supports_margin());
1536    ///
1537    /// let caps = ExchangeCapabilities::spot_exchange();
1538    /// assert!(!caps.supports_margin());
1539    /// ```
1540    #[inline]
1541    pub const fn supports_margin(&self) -> bool {
1542        self.inner
1543            .contains(TraitCategory::Margin.minimum_capabilities())
1544    }
1545
1546    /// Check if the exchange supports the Funding trait.
1547    ///
1548    /// Returns `true` if the exchange has the minimum capabilities required
1549    /// to implement the `Funding` trait (fetch_deposit_address).
1550    ///
1551    /// # Example
1552    ///
1553    /// ```rust
1554    /// use ccxt_core::capability::ExchangeCapabilities;
1555    ///
1556    /// let caps = ExchangeCapabilities::all();
1557    /// assert!(caps.supports_funding());
1558    ///
1559    /// let caps = ExchangeCapabilities::public_only();
1560    /// assert!(!caps.supports_funding());
1561    /// ```
1562    #[inline]
1563    pub const fn supports_funding(&self) -> bool {
1564        self.inner
1565            .contains(TraitCategory::Funding.minimum_capabilities())
1566    }
1567
1568    /// Check if the exchange supports WebSocket.
1569    ///
1570    /// Returns `true` if the exchange has the base WebSocket capability.
1571    ///
1572    /// # Example
1573    ///
1574    /// ```rust
1575    /// use ccxt_core::capability::ExchangeCapabilities;
1576    ///
1577    /// let caps = ExchangeCapabilities::all();
1578    /// assert!(caps.supports_websocket());
1579    ///
1580    /// let caps = ExchangeCapabilities::public_only();
1581    /// assert!(!caps.supports_websocket());
1582    /// ```
1583    #[inline]
1584    pub const fn supports_websocket(&self) -> bool {
1585        self.inner
1586            .contains(TraitCategory::WebSocket.minimum_capabilities())
1587    }
1588
1589    /// Check if the exchange supports all traits (FullExchange).
1590    ///
1591    /// Returns `true` if the exchange has the minimum capabilities required
1592    /// to implement all traits: MarketData, Trading, Account, Margin, and Funding.
1593    ///
1594    /// # Example
1595    ///
1596    /// ```rust
1597    /// use ccxt_core::capability::ExchangeCapabilities;
1598    ///
1599    /// let caps = ExchangeCapabilities::all();
1600    /// assert!(caps.supports_full_exchange());
1601    ///
1602    /// let caps = ExchangeCapabilities::spot_exchange();
1603    /// assert!(!caps.supports_full_exchange());
1604    /// ```
1605    #[inline]
1606    pub const fn supports_full_exchange(&self) -> bool {
1607        self.supports_market_data()
1608            && self.supports_trading()
1609            && self.supports_account()
1610            && self.supports_margin()
1611            && self.supports_funding()
1612    }
1613
1614    /// Check if the exchange supports a specific trait category.
1615    ///
1616    /// # Arguments
1617    ///
1618    /// * `category` - The trait category to check
1619    ///
1620    /// # Example
1621    ///
1622    /// ```rust
1623    /// use ccxt_core::capability::{ExchangeCapabilities, TraitCategory};
1624    ///
1625    /// let caps = ExchangeCapabilities::all();
1626    /// assert!(caps.supports_trait(TraitCategory::MarketData));
1627    /// assert!(caps.supports_trait(TraitCategory::Trading));
1628    /// ```
1629    pub const fn supports_trait(&self, category: TraitCategory) -> bool {
1630        match category {
1631            TraitCategory::PublicExchange => true, // Always supported
1632            TraitCategory::MarketData => self.supports_market_data(),
1633            TraitCategory::Trading => self.supports_trading(),
1634            TraitCategory::Account => self.supports_account(),
1635            TraitCategory::Margin => self.supports_margin(),
1636            TraitCategory::Funding => self.supports_funding(),
1637            TraitCategory::WebSocket => self.supports_websocket(),
1638        }
1639    }
1640
1641    /// Get a list of supported trait categories.
1642    ///
1643    /// Returns a vector of trait categories that this exchange supports
1644    /// based on its capabilities.
1645    ///
1646    /// # Example
1647    ///
1648    /// ```rust
1649    /// use ccxt_core::capability::{ExchangeCapabilities, TraitCategory};
1650    ///
1651    /// let caps = ExchangeCapabilities::public_only();
1652    /// let traits = caps.supported_traits();
1653    /// assert!(traits.contains(&TraitCategory::PublicExchange));
1654    /// assert!(traits.contains(&TraitCategory::MarketData));
1655    /// assert!(!traits.contains(&TraitCategory::Trading));
1656    /// ```
1657    pub fn supported_traits(&self) -> Vec<TraitCategory> {
1658        TraitCategory::all()
1659            .iter()
1660            .filter(|cat| self.supports_trait(**cat))
1661            .copied()
1662            .collect()
1663    }
1664
1665    /// Get capabilities for a specific trait category.
1666    ///
1667    /// Returns the capabilities that are enabled for the specified trait category.
1668    ///
1669    /// # Arguments
1670    ///
1671    /// * `category` - The trait category to get capabilities for
1672    ///
1673    /// # Example
1674    ///
1675    /// ```rust
1676    /// use ccxt_core::capability::{ExchangeCapabilities, TraitCategory, Capabilities};
1677    ///
1678    /// let caps = ExchangeCapabilities::all();
1679    /// let market_caps = caps.capabilities_for_trait(TraitCategory::MarketData);
1680    /// assert!(market_caps.contains(Capabilities::FETCH_TICKER));
1681    /// ```
1682    pub const fn capabilities_for_trait(&self, category: TraitCategory) -> Capabilities {
1683        Capabilities::from_bits_truncate(self.inner.bits() & category.capabilities().bits())
1684    }
1685
1686    /// Get the trait category for a specific capability.
1687    ///
1688    /// # Arguments
1689    ///
1690    /// * `capability` - The capability to get the trait category for
1691    ///
1692    /// # Example
1693    ///
1694    /// ```rust
1695    /// use ccxt_core::capability::{ExchangeCapabilities, Capability, TraitCategory};
1696    ///
1697    /// let category = ExchangeCapabilities::trait_for_capability(Capability::FetchTicker);
1698    /// assert_eq!(category, TraitCategory::MarketData);
1699    /// ```
1700    pub const fn trait_for_capability(capability: Capability) -> TraitCategory {
1701        capability.trait_category()
1702    }
1703}
1704
1705// ============================================================================
1706// Unit Tests
1707// ============================================================================
1708
1709#[cfg(test)]
1710mod tests {
1711    use super::*;
1712
1713    #[test]
1714    fn test_capability_count() {
1715        assert_eq!(Capability::COUNT, 46);
1716    }
1717
1718    #[test]
1719    fn test_capability_ccxt_names() {
1720        assert_eq!(Capability::FetchTicker.as_ccxt_name(), "fetchTicker");
1721        assert_eq!(Capability::CreateOrder.as_ccxt_name(), "createOrder");
1722        assert_eq!(Capability::FetchOhlcv.as_ccxt_name(), "fetchOHLCV");
1723        assert_eq!(Capability::WatchOhlcv.as_ccxt_name(), "watchOHLCV");
1724    }
1725
1726    #[test]
1727    fn test_capability_from_ccxt_name() {
1728        assert_eq!(
1729            Capability::from_ccxt_name("fetchTicker"),
1730            Some(Capability::FetchTicker)
1731        );
1732        assert_eq!(
1733            Capability::from_ccxt_name("createOrder"),
1734            Some(Capability::CreateOrder)
1735        );
1736        assert_eq!(Capability::from_ccxt_name("unknown"), None);
1737    }
1738
1739    #[test]
1740    fn test_capabilities_bitflags() {
1741        let caps = Capabilities::FETCH_TICKER | Capabilities::CREATE_ORDER;
1742        assert!(caps.contains(Capabilities::FETCH_TICKER));
1743        assert!(caps.contains(Capabilities::CREATE_ORDER));
1744        assert!(!caps.contains(Capabilities::WEBSOCKET));
1745    }
1746
1747    #[test]
1748    fn test_capabilities_presets() {
1749        // Market data should include all fetch* for public data
1750        assert!(Capabilities::MARKET_DATA.contains(Capabilities::FETCH_TICKER));
1751        assert!(Capabilities::MARKET_DATA.contains(Capabilities::FETCH_ORDER_BOOK));
1752        assert!(!Capabilities::MARKET_DATA.contains(Capabilities::CREATE_ORDER));
1753
1754        // Trading should include order operations
1755        assert!(Capabilities::TRADING.contains(Capabilities::CREATE_ORDER));
1756        assert!(Capabilities::TRADING.contains(Capabilities::CANCEL_ORDER));
1757        assert!(!Capabilities::TRADING.contains(Capabilities::FETCH_TICKER));
1758    }
1759
1760    #[test]
1761    fn test_capabilities_has() {
1762        let caps = Capabilities::MARKET_DATA;
1763        assert!(caps.has("fetchTicker"));
1764        assert!(caps.has("fetchOrderBook"));
1765        assert!(!caps.has("createOrder"));
1766        assert!(!caps.has("unknownCapability"));
1767    }
1768
1769    #[test]
1770    fn test_capabilities_count() {
1771        assert_eq!(Capabilities::empty().count(), 0);
1772        assert_eq!(Capabilities::FETCH_TICKER.count(), 1);
1773        assert_eq!(
1774            (Capabilities::FETCH_TICKER | Capabilities::CREATE_ORDER).count(),
1775            2
1776        );
1777        assert_eq!(Capabilities::MARKET_DATA.count(), 9);
1778    }
1779
1780    #[test]
1781    fn test_capabilities_from_iter() {
1782        let caps = Capabilities::from_iter([
1783            Capability::FetchTicker,
1784            Capability::CreateOrder,
1785            Capability::Websocket,
1786        ]);
1787        assert!(caps.contains(Capabilities::FETCH_TICKER));
1788        assert!(caps.contains(Capabilities::CREATE_ORDER));
1789        assert!(caps.contains(Capabilities::WEBSOCKET));
1790        assert_eq!(caps.count(), 3);
1791    }
1792
1793    #[test]
1794    fn test_exchange_capabilities_all() {
1795        let caps = ExchangeCapabilities::all();
1796        assert!(caps.fetch_ticker());
1797        assert!(caps.create_order());
1798        assert!(caps.websocket());
1799        assert!(caps.fetch_positions());
1800    }
1801
1802    #[test]
1803    fn test_exchange_capabilities_public_only() {
1804        let caps = ExchangeCapabilities::public_only();
1805        assert!(caps.fetch_ticker());
1806        assert!(caps.fetch_order_book());
1807        assert!(!caps.create_order());
1808        assert!(!caps.fetch_balance());
1809    }
1810
1811    #[test]
1812    fn test_exchange_capabilities_has() {
1813        let caps = ExchangeCapabilities::all();
1814        assert!(caps.has("fetchTicker"));
1815        assert!(caps.has("createOrder"));
1816        assert!(!caps.has("unknownCapability"));
1817    }
1818
1819    #[test]
1820    fn test_exchange_capabilities_builder() {
1821        let caps = ExchangeCapabilities::builder()
1822            .market_data()
1823            .trading()
1824            .build();
1825
1826        assert!(caps.fetch_ticker());
1827        assert!(caps.create_order());
1828        assert!(!caps.websocket());
1829    }
1830
1831    #[test]
1832    fn test_exchange_capabilities_builder_with_capability() {
1833        let caps = ExchangeCapabilities::builder()
1834            .capability(Capability::FetchTicker)
1835            .capability(Capability::Websocket)
1836            .build();
1837
1838        assert!(caps.fetch_ticker());
1839        assert!(caps.websocket());
1840        assert!(!caps.create_order());
1841    }
1842
1843    #[test]
1844    fn test_exchange_capabilities_builder_without() {
1845        let caps = ExchangeCapabilities::builder()
1846            .all()
1847            .without_capability(Capability::Websocket)
1848            .build();
1849
1850        assert!(caps.fetch_ticker());
1851        assert!(caps.create_order());
1852        assert!(!caps.websocket());
1853    }
1854
1855    #[test]
1856    fn test_exchange_capabilities_presets() {
1857        let spot = ExchangeCapabilities::spot_exchange();
1858        assert!(spot.fetch_ticker());
1859        assert!(spot.create_order());
1860        assert!(spot.websocket());
1861        assert!(!spot.fetch_positions()); // No margin trading
1862
1863        let futures = ExchangeCapabilities::futures_exchange();
1864        assert!(futures.fetch_ticker());
1865        assert!(futures.create_order());
1866        assert!(futures.fetch_positions());
1867        assert!(futures.set_leverage());
1868    }
1869
1870    #[test]
1871    fn test_capabilities_macro() {
1872        let caps = capabilities!(MARKET_DATA);
1873        assert!(caps.contains(Capabilities::FETCH_TICKER));
1874
1875        let caps = capabilities!(FETCH_TICKER | CREATE_ORDER);
1876        assert!(caps.contains(Capabilities::FETCH_TICKER));
1877        assert!(caps.contains(Capabilities::CREATE_ORDER));
1878
1879        let caps = capabilities!(MARKET_DATA, TRADING);
1880        assert!(caps.contains(Capabilities::FETCH_TICKER));
1881        assert!(caps.contains(Capabilities::CREATE_ORDER));
1882    }
1883
1884    #[test]
1885    fn test_capability_bit_positions() {
1886        // Verify bit positions match enum values
1887        assert_eq!(Capability::FetchMarkets.bit_position(), 1 << 0);
1888        assert_eq!(Capability::FetchTicker.bit_position(), 1 << 2);
1889        assert_eq!(Capability::CreateOrder.bit_position(), 1 << 9);
1890        assert_eq!(Capability::Websocket.bit_position(), 1 << 37);
1891    }
1892
1893    #[test]
1894    fn test_memory_efficiency() {
1895        // ExchangeCapabilities should be 8 bytes (u64)
1896        assert_eq!(std::mem::size_of::<ExchangeCapabilities>(), 8);
1897        assert_eq!(std::mem::size_of::<Capabilities>(), 8);
1898    }
1899
1900    // ========================================================================
1901    // Trait-Capability Mapping Tests
1902    // ========================================================================
1903
1904    #[test]
1905    fn test_trait_category_all() {
1906        let categories = TraitCategory::all();
1907        assert_eq!(categories.len(), 7);
1908        assert!(categories.contains(&TraitCategory::PublicExchange));
1909        assert!(categories.contains(&TraitCategory::MarketData));
1910        assert!(categories.contains(&TraitCategory::Trading));
1911        assert!(categories.contains(&TraitCategory::Account));
1912        assert!(categories.contains(&TraitCategory::Margin));
1913        assert!(categories.contains(&TraitCategory::Funding));
1914        assert!(categories.contains(&TraitCategory::WebSocket));
1915    }
1916
1917    #[test]
1918    fn test_trait_category_names() {
1919        assert_eq!(TraitCategory::PublicExchange.name(), "PublicExchange");
1920        assert_eq!(TraitCategory::MarketData.name(), "MarketData");
1921        assert_eq!(TraitCategory::Trading.name(), "Trading");
1922        assert_eq!(TraitCategory::Account.name(), "Account");
1923        assert_eq!(TraitCategory::Margin.name(), "Margin");
1924        assert_eq!(TraitCategory::Funding.name(), "Funding");
1925        assert_eq!(TraitCategory::WebSocket.name(), "WebSocket");
1926    }
1927
1928    #[test]
1929    fn test_trait_category_capabilities() {
1930        assert_eq!(
1931            TraitCategory::PublicExchange.capabilities(),
1932            Capabilities::empty()
1933        );
1934        assert_eq!(
1935            TraitCategory::MarketData.capabilities(),
1936            Capabilities::MARKET_DATA
1937        );
1938        assert_eq!(TraitCategory::Trading.capabilities(), Capabilities::TRADING);
1939        assert_eq!(TraitCategory::Account.capabilities(), Capabilities::ACCOUNT);
1940        assert_eq!(TraitCategory::Margin.capabilities(), Capabilities::MARGIN);
1941        assert_eq!(TraitCategory::Funding.capabilities(), Capabilities::FUNDING);
1942        assert_eq!(
1943            TraitCategory::WebSocket.capabilities(),
1944            Capabilities::WEBSOCKET_ALL
1945        );
1946    }
1947
1948    #[test]
1949    fn test_capability_trait_category() {
1950        // Market Data
1951        assert_eq!(
1952            Capability::FetchTicker.trait_category(),
1953            TraitCategory::MarketData
1954        );
1955        assert_eq!(
1956            Capability::FetchMarkets.trait_category(),
1957            TraitCategory::MarketData
1958        );
1959        assert_eq!(
1960            Capability::FetchOhlcv.trait_category(),
1961            TraitCategory::MarketData
1962        );
1963
1964        // Trading
1965        assert_eq!(
1966            Capability::CreateOrder.trait_category(),
1967            TraitCategory::Trading
1968        );
1969        assert_eq!(
1970            Capability::CancelOrder.trait_category(),
1971            TraitCategory::Trading
1972        );
1973        assert_eq!(
1974            Capability::FetchOpenOrders.trait_category(),
1975            TraitCategory::Trading
1976        );
1977
1978        // Account
1979        assert_eq!(
1980            Capability::FetchBalance.trait_category(),
1981            TraitCategory::Account
1982        );
1983        assert_eq!(
1984            Capability::FetchMyTrades.trait_category(),
1985            TraitCategory::Account
1986        );
1987
1988        // Margin
1989        assert_eq!(
1990            Capability::FetchPositions.trait_category(),
1991            TraitCategory::Margin
1992        );
1993        assert_eq!(
1994            Capability::SetLeverage.trait_category(),
1995            TraitCategory::Margin
1996        );
1997        assert_eq!(
1998            Capability::FetchFundingRate.trait_category(),
1999            TraitCategory::Margin
2000        );
2001
2002        // Funding
2003        assert_eq!(
2004            Capability::FetchDepositAddress.trait_category(),
2005            TraitCategory::Funding
2006        );
2007        assert_eq!(
2008            Capability::Withdraw.trait_category(),
2009            TraitCategory::Funding
2010        );
2011        assert_eq!(
2012            Capability::Transfer.trait_category(),
2013            TraitCategory::Funding
2014        );
2015
2016        // WebSocket
2017        assert_eq!(
2018            Capability::Websocket.trait_category(),
2019            TraitCategory::WebSocket
2020        );
2021        assert_eq!(
2022            Capability::WatchTicker.trait_category(),
2023            TraitCategory::WebSocket
2024        );
2025    }
2026
2027    #[test]
2028    fn test_supports_market_data() {
2029        let caps = ExchangeCapabilities::public_only();
2030        assert!(caps.supports_market_data());
2031
2032        let caps = ExchangeCapabilities::none();
2033        assert!(!caps.supports_market_data());
2034
2035        // Only fetch_markets is not enough
2036        let caps = ExchangeCapabilities::builder()
2037            .capability(Capability::FetchMarkets)
2038            .build();
2039        assert!(!caps.supports_market_data());
2040
2041        // Both fetch_markets and fetch_ticker are required
2042        let caps = ExchangeCapabilities::builder()
2043            .capability(Capability::FetchMarkets)
2044            .capability(Capability::FetchTicker)
2045            .build();
2046        assert!(caps.supports_market_data());
2047    }
2048
2049    #[test]
2050    fn test_supports_trading() {
2051        let caps = ExchangeCapabilities::all();
2052        assert!(caps.supports_trading());
2053
2054        let caps = ExchangeCapabilities::public_only();
2055        assert!(!caps.supports_trading());
2056
2057        // Both create_order and cancel_order are required
2058        let caps = ExchangeCapabilities::builder()
2059            .capability(Capability::CreateOrder)
2060            .capability(Capability::CancelOrder)
2061            .build();
2062        assert!(caps.supports_trading());
2063    }
2064
2065    #[test]
2066    fn test_supports_account() {
2067        let caps = ExchangeCapabilities::all();
2068        assert!(caps.supports_account());
2069
2070        let caps = ExchangeCapabilities::public_only();
2071        assert!(!caps.supports_account());
2072
2073        let caps = ExchangeCapabilities::builder()
2074            .capability(Capability::FetchBalance)
2075            .build();
2076        assert!(caps.supports_account());
2077    }
2078
2079    #[test]
2080    fn test_supports_margin() {
2081        let caps = ExchangeCapabilities::futures_exchange();
2082        assert!(caps.supports_margin());
2083
2084        let caps = ExchangeCapabilities::spot_exchange();
2085        assert!(!caps.supports_margin());
2086
2087        let caps = ExchangeCapabilities::builder()
2088            .capability(Capability::FetchPositions)
2089            .build();
2090        assert!(caps.supports_margin());
2091    }
2092
2093    #[test]
2094    fn test_supports_funding() {
2095        let caps = ExchangeCapabilities::all();
2096        assert!(caps.supports_funding());
2097
2098        let caps = ExchangeCapabilities::public_only();
2099        assert!(!caps.supports_funding());
2100
2101        let caps = ExchangeCapabilities::builder()
2102            .capability(Capability::FetchDepositAddress)
2103            .build();
2104        assert!(caps.supports_funding());
2105    }
2106
2107    #[test]
2108    fn test_supports_websocket() {
2109        let caps = ExchangeCapabilities::all();
2110        assert!(caps.supports_websocket());
2111
2112        let caps = ExchangeCapabilities::public_only();
2113        assert!(!caps.supports_websocket());
2114
2115        let caps = ExchangeCapabilities::builder()
2116            .capability(Capability::Websocket)
2117            .build();
2118        assert!(caps.supports_websocket());
2119    }
2120
2121    #[test]
2122    fn test_supports_full_exchange() {
2123        let caps = ExchangeCapabilities::all();
2124        assert!(caps.supports_full_exchange());
2125
2126        let caps = ExchangeCapabilities::spot_exchange();
2127        assert!(!caps.supports_full_exchange()); // Missing margin and funding
2128
2129        let caps = ExchangeCapabilities::futures_exchange();
2130        assert!(!caps.supports_full_exchange()); // Missing funding
2131    }
2132
2133    #[test]
2134    fn test_supports_trait() {
2135        let caps = ExchangeCapabilities::all();
2136        assert!(caps.supports_trait(TraitCategory::PublicExchange));
2137        assert!(caps.supports_trait(TraitCategory::MarketData));
2138        assert!(caps.supports_trait(TraitCategory::Trading));
2139        assert!(caps.supports_trait(TraitCategory::Account));
2140        assert!(caps.supports_trait(TraitCategory::Margin));
2141        assert!(caps.supports_trait(TraitCategory::Funding));
2142        assert!(caps.supports_trait(TraitCategory::WebSocket));
2143
2144        let caps = ExchangeCapabilities::public_only();
2145        assert!(caps.supports_trait(TraitCategory::PublicExchange));
2146        assert!(caps.supports_trait(TraitCategory::MarketData));
2147        assert!(!caps.supports_trait(TraitCategory::Trading));
2148        assert!(!caps.supports_trait(TraitCategory::Account));
2149        assert!(!caps.supports_trait(TraitCategory::Margin));
2150        assert!(!caps.supports_trait(TraitCategory::Funding));
2151        assert!(!caps.supports_trait(TraitCategory::WebSocket));
2152    }
2153
2154    #[test]
2155    fn test_supported_traits() {
2156        let caps = ExchangeCapabilities::public_only();
2157        let traits = caps.supported_traits();
2158        assert!(traits.contains(&TraitCategory::PublicExchange));
2159        assert!(traits.contains(&TraitCategory::MarketData));
2160        assert!(!traits.contains(&TraitCategory::Trading));
2161
2162        let caps = ExchangeCapabilities::all();
2163        let traits = caps.supported_traits();
2164        assert_eq!(traits.len(), 7); // All traits supported
2165    }
2166
2167    #[test]
2168    fn test_capabilities_for_trait() {
2169        let caps = ExchangeCapabilities::all();
2170
2171        let market_caps = caps.capabilities_for_trait(TraitCategory::MarketData);
2172        assert!(market_caps.contains(Capabilities::FETCH_TICKER));
2173        assert!(market_caps.contains(Capabilities::FETCH_ORDER_BOOK));
2174        assert!(!market_caps.contains(Capabilities::CREATE_ORDER));
2175
2176        let trading_caps = caps.capabilities_for_trait(TraitCategory::Trading);
2177        assert!(trading_caps.contains(Capabilities::CREATE_ORDER));
2178        assert!(trading_caps.contains(Capabilities::CANCEL_ORDER));
2179        assert!(!trading_caps.contains(Capabilities::FETCH_TICKER));
2180    }
2181
2182    #[test]
2183    fn test_trait_for_capability() {
2184        assert_eq!(
2185            ExchangeCapabilities::trait_for_capability(Capability::FetchTicker),
2186            TraitCategory::MarketData
2187        );
2188        assert_eq!(
2189            ExchangeCapabilities::trait_for_capability(Capability::CreateOrder),
2190            TraitCategory::Trading
2191        );
2192        assert_eq!(
2193            ExchangeCapabilities::trait_for_capability(Capability::FetchBalance),
2194            TraitCategory::Account
2195        );
2196    }
2197
2198    #[test]
2199    fn test_trait_category_display() {
2200        assert_eq!(format!("{}", TraitCategory::MarketData), "MarketData");
2201        assert_eq!(format!("{}", TraitCategory::Trading), "Trading");
2202    }
2203}