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(|cap| cap.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    pub fn from_iter<I: IntoIterator<Item = Capability>>(iter: I) -> Self {
577        let mut caps = Self::empty();
578        for cap in iter {
579            caps |= Self::from(cap);
580        }
581        caps
582    }
583}
584
585impl From<Capability> for Capabilities {
586    fn from(cap: Capability) -> Self {
587        Self::from_bits_truncate(cap.bit_position())
588    }
589}
590
591impl fmt::Display for Capabilities {
592    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
593        let caps = self.supported_capabilities();
594        write!(f, "[{}]", caps.join(", "))
595    }
596}
597
598// ============================================================================
599// Capabilities Builder Macro
600// ============================================================================
601
602/// Macro for building Capabilities with a concise syntax
603///
604/// # Examples
605///
606/// ```rust
607/// use ccxt_core::{capabilities, capability::Capabilities};
608///
609/// // Using predefined sets
610/// let caps = capabilities!(MARKET_DATA, TRADING);
611///
612/// // Using individual capabilities
613/// let caps = capabilities!(FETCH_TICKER, CREATE_ORDER, WEBSOCKET);
614///
615/// // Combining sets and individual capabilities
616/// let caps = capabilities!(MARKET_DATA | FETCH_BALANCE | WEBSOCKET);
617/// ```
618#[macro_export]
619macro_rules! capabilities {
620    // Single capability or set
621    ($cap:ident) => {
622        $crate::capability::Capabilities::$cap
623    };
624    // Multiple capabilities with |
625    ($cap:ident | $($rest:tt)+) => {
626        $crate::capability::Capabilities::$cap | capabilities!($($rest)+)
627    };
628    // Multiple capabilities with ,
629    ($cap:ident, $($rest:tt)+) => {
630        $crate::capability::Capabilities::$cap | capabilities!($($rest)+)
631    };
632}
633
634// ============================================================================
635// ExchangeCapabilities Struct (Backward Compatible)
636// ============================================================================
637
638/// Exchange capabilities configuration
639///
640/// This struct provides a high-level API for working with exchange capabilities,
641/// maintaining backward compatibility with the original boolean-field design
642/// while using efficient bitflags internally.
643///
644/// # Example
645///
646/// ```rust
647/// use ccxt_core::capability::ExchangeCapabilities;
648///
649/// let caps = ExchangeCapabilities::public_only();
650/// assert!(caps.has("fetchTicker"));
651/// assert!(!caps.has("createOrder"));
652///
653/// let caps = ExchangeCapabilities::all();
654/// assert!(caps.fetch_ticker());
655/// assert!(caps.create_order());
656/// ```
657#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
658pub struct ExchangeCapabilities {
659    inner: Capabilities,
660}
661
662impl ExchangeCapabilities {
663    /// Create with no capabilities enabled
664    pub const fn none() -> Self {
665        Self {
666            inner: Capabilities::empty(),
667        }
668    }
669
670    /// Create capabilities with all features enabled
671    ///
672    /// # Example
673    ///
674    /// ```rust
675    /// use ccxt_core::capability::ExchangeCapabilities;
676    ///
677    /// let caps = ExchangeCapabilities::all();
678    /// assert!(caps.fetch_ticker());
679    /// assert!(caps.create_order());
680    /// assert!(caps.websocket());
681    /// ```
682    pub const fn all() -> Self {
683        Self {
684            inner: Capabilities::ALL,
685        }
686    }
687
688    /// Create capabilities for public API only (no authentication required)
689    ///
690    /// # Example
691    ///
692    /// ```rust
693    /// use ccxt_core::capability::ExchangeCapabilities;
694    ///
695    /// let caps = ExchangeCapabilities::public_only();
696    /// assert!(caps.fetch_ticker());
697    /// assert!(!caps.create_order());
698    /// ```
699    pub const fn public_only() -> Self {
700        Self {
701            inner: Capabilities::PUBLIC_ONLY,
702        }
703    }
704
705    /// Create from raw Capabilities bitflags
706    pub const fn from_capabilities(caps: Capabilities) -> Self {
707        Self { inner: caps }
708    }
709
710    /// Get the underlying Capabilities bitflags
711    pub const fn as_capabilities(&self) -> Capabilities {
712        self.inner
713    }
714
715    /// Check if a capability is supported by name
716    ///
717    /// This method allows checking capabilities using CCXT-style camelCase names.
718    ///
719    /// # Arguments
720    ///
721    /// * `capability` - The capability name in camelCase format
722    ///
723    /// # Example
724    ///
725    /// ```rust
726    /// use ccxt_core::capability::ExchangeCapabilities;
727    ///
728    /// let caps = ExchangeCapabilities::all();
729    /// assert!(caps.has("fetchTicker"));
730    /// assert!(caps.has("createOrder"));
731    /// assert!(!caps.has("unknownCapability"));
732    /// ```
733    pub fn has(&self, capability: &str) -> bool {
734        self.inner.has(capability)
735    }
736
737    /// Get a list of all supported capability names
738    pub fn supported_capabilities(&self) -> Vec<&'static str> {
739        self.inner.supported_capabilities()
740    }
741
742    /// Count the number of enabled capabilities
743    #[inline]
744    pub fn count(&self) -> u32 {
745        self.inner.count()
746    }
747
748    // ==================== Market Data Accessors ====================
749
750    /// Can fetch market definitions
751    #[inline]
752    pub const fn fetch_markets(&self) -> bool {
753        self.inner.contains(Capabilities::FETCH_MARKETS)
754    }
755
756    /// Can fetch currency definitions
757    #[inline]
758    pub const fn fetch_currencies(&self) -> bool {
759        self.inner.contains(Capabilities::FETCH_CURRENCIES)
760    }
761
762    /// Can fetch single ticker
763    #[inline]
764    pub const fn fetch_ticker(&self) -> bool {
765        self.inner.contains(Capabilities::FETCH_TICKER)
766    }
767
768    /// Can fetch multiple tickers
769    #[inline]
770    pub const fn fetch_tickers(&self) -> bool {
771        self.inner.contains(Capabilities::FETCH_TICKERS)
772    }
773
774    /// Can fetch order book
775    #[inline]
776    pub const fn fetch_order_book(&self) -> bool {
777        self.inner.contains(Capabilities::FETCH_ORDER_BOOK)
778    }
779
780    /// Can fetch public trades
781    #[inline]
782    pub const fn fetch_trades(&self) -> bool {
783        self.inner.contains(Capabilities::FETCH_TRADES)
784    }
785
786    /// Can fetch OHLCV candlestick data
787    #[inline]
788    pub const fn fetch_ohlcv(&self) -> bool {
789        self.inner.contains(Capabilities::FETCH_OHLCV)
790    }
791
792    /// Can fetch exchange status
793    #[inline]
794    pub const fn fetch_status(&self) -> bool {
795        self.inner.contains(Capabilities::FETCH_STATUS)
796    }
797
798    /// Can fetch server time
799    #[inline]
800    pub const fn fetch_time(&self) -> bool {
801        self.inner.contains(Capabilities::FETCH_TIME)
802    }
803
804    // ==================== Trading Accessors ====================
805
806    /// Can create orders
807    #[inline]
808    pub const fn create_order(&self) -> bool {
809        self.inner.contains(Capabilities::CREATE_ORDER)
810    }
811
812    /// Can create market orders
813    #[inline]
814    pub const fn create_market_order(&self) -> bool {
815        self.inner.contains(Capabilities::CREATE_MARKET_ORDER)
816    }
817
818    /// Can create limit orders
819    #[inline]
820    pub const fn create_limit_order(&self) -> bool {
821        self.inner.contains(Capabilities::CREATE_LIMIT_ORDER)
822    }
823
824    /// Can cancel orders
825    #[inline]
826    pub const fn cancel_order(&self) -> bool {
827        self.inner.contains(Capabilities::CANCEL_ORDER)
828    }
829
830    /// Can cancel all orders
831    #[inline]
832    pub const fn cancel_all_orders(&self) -> bool {
833        self.inner.contains(Capabilities::CANCEL_ALL_ORDERS)
834    }
835
836    /// Can edit/modify orders
837    #[inline]
838    pub const fn edit_order(&self) -> bool {
839        self.inner.contains(Capabilities::EDIT_ORDER)
840    }
841
842    /// Can fetch single order
843    #[inline]
844    pub const fn fetch_order(&self) -> bool {
845        self.inner.contains(Capabilities::FETCH_ORDER)
846    }
847
848    /// Can fetch all orders
849    #[inline]
850    pub const fn fetch_orders(&self) -> bool {
851        self.inner.contains(Capabilities::FETCH_ORDERS)
852    }
853
854    /// Can fetch open orders
855    #[inline]
856    pub const fn fetch_open_orders(&self) -> bool {
857        self.inner.contains(Capabilities::FETCH_OPEN_ORDERS)
858    }
859
860    /// Can fetch closed orders
861    #[inline]
862    pub const fn fetch_closed_orders(&self) -> bool {
863        self.inner.contains(Capabilities::FETCH_CLOSED_ORDERS)
864    }
865
866    /// Can fetch canceled orders
867    #[inline]
868    pub const fn fetch_canceled_orders(&self) -> bool {
869        self.inner.contains(Capabilities::FETCH_CANCELED_ORDERS)
870    }
871
872    // ==================== Account Accessors ====================
873
874    /// Can fetch account balance
875    #[inline]
876    pub const fn fetch_balance(&self) -> bool {
877        self.inner.contains(Capabilities::FETCH_BALANCE)
878    }
879
880    /// Can fetch user's trade history
881    #[inline]
882    pub const fn fetch_my_trades(&self) -> bool {
883        self.inner.contains(Capabilities::FETCH_MY_TRADES)
884    }
885
886    /// Can fetch deposit history
887    #[inline]
888    pub const fn fetch_deposits(&self) -> bool {
889        self.inner.contains(Capabilities::FETCH_DEPOSITS)
890    }
891
892    /// Can fetch withdrawal history
893    #[inline]
894    pub const fn fetch_withdrawals(&self) -> bool {
895        self.inner.contains(Capabilities::FETCH_WITHDRAWALS)
896    }
897
898    /// Can fetch transaction history
899    #[inline]
900    pub const fn fetch_transactions(&self) -> bool {
901        self.inner.contains(Capabilities::FETCH_TRANSACTIONS)
902    }
903
904    /// Can fetch ledger entries
905    #[inline]
906    pub const fn fetch_ledger(&self) -> bool {
907        self.inner.contains(Capabilities::FETCH_LEDGER)
908    }
909
910    // ==================== Funding Accessors ====================
911
912    /// Can fetch deposit address
913    #[inline]
914    pub const fn fetch_deposit_address(&self) -> bool {
915        self.inner.contains(Capabilities::FETCH_DEPOSIT_ADDRESS)
916    }
917
918    /// Can create deposit address
919    #[inline]
920    pub const fn create_deposit_address(&self) -> bool {
921        self.inner.contains(Capabilities::CREATE_DEPOSIT_ADDRESS)
922    }
923
924    /// Can withdraw funds
925    #[inline]
926    pub const fn withdraw(&self) -> bool {
927        self.inner.contains(Capabilities::WITHDRAW)
928    }
929
930    /// Can transfer between accounts
931    #[inline]
932    pub const fn transfer(&self) -> bool {
933        self.inner.contains(Capabilities::TRANSFER)
934    }
935
936    // ==================== Margin Trading Accessors ====================
937
938    /// Can fetch borrow rate
939    #[inline]
940    pub const fn fetch_borrow_rate(&self) -> bool {
941        self.inner.contains(Capabilities::FETCH_BORROW_RATE)
942    }
943
944    /// Can fetch multiple borrow rates
945    #[inline]
946    pub const fn fetch_borrow_rates(&self) -> bool {
947        self.inner.contains(Capabilities::FETCH_BORROW_RATES)
948    }
949
950    /// Can fetch funding rate
951    #[inline]
952    pub const fn fetch_funding_rate(&self) -> bool {
953        self.inner.contains(Capabilities::FETCH_FUNDING_RATE)
954    }
955
956    /// Can fetch multiple funding rates
957    #[inline]
958    pub const fn fetch_funding_rates(&self) -> bool {
959        self.inner.contains(Capabilities::FETCH_FUNDING_RATES)
960    }
961
962    /// Can fetch positions
963    #[inline]
964    pub const fn fetch_positions(&self) -> bool {
965        self.inner.contains(Capabilities::FETCH_POSITIONS)
966    }
967
968    /// Can set leverage
969    #[inline]
970    pub const fn set_leverage(&self) -> bool {
971        self.inner.contains(Capabilities::SET_LEVERAGE)
972    }
973
974    /// Can set margin mode
975    #[inline]
976    pub const fn set_margin_mode(&self) -> bool {
977        self.inner.contains(Capabilities::SET_MARGIN_MODE)
978    }
979
980    // ==================== WebSocket Accessors ====================
981
982    /// WebSocket support available
983    #[inline]
984    pub const fn websocket(&self) -> bool {
985        self.inner.contains(Capabilities::WEBSOCKET)
986    }
987
988    /// Can watch ticker updates
989    #[inline]
990    pub const fn watch_ticker(&self) -> bool {
991        self.inner.contains(Capabilities::WATCH_TICKER)
992    }
993
994    /// Can watch multiple ticker updates
995    #[inline]
996    pub const fn watch_tickers(&self) -> bool {
997        self.inner.contains(Capabilities::WATCH_TICKERS)
998    }
999
1000    /// Can watch order book updates
1001    #[inline]
1002    pub const fn watch_order_book(&self) -> bool {
1003        self.inner.contains(Capabilities::WATCH_ORDER_BOOK)
1004    }
1005
1006    /// Can watch trade updates
1007    #[inline]
1008    pub const fn watch_trades(&self) -> bool {
1009        self.inner.contains(Capabilities::WATCH_TRADES)
1010    }
1011
1012    /// Can watch OHLCV updates
1013    #[inline]
1014    pub const fn watch_ohlcv(&self) -> bool {
1015        self.inner.contains(Capabilities::WATCH_OHLCV)
1016    }
1017
1018    /// Can watch balance updates
1019    #[inline]
1020    pub const fn watch_balance(&self) -> bool {
1021        self.inner.contains(Capabilities::WATCH_BALANCE)
1022    }
1023
1024    /// Can watch order updates
1025    #[inline]
1026    pub const fn watch_orders(&self) -> bool {
1027        self.inner.contains(Capabilities::WATCH_ORDERS)
1028    }
1029
1030    /// Can watch user trade updates
1031    #[inline]
1032    pub const fn watch_my_trades(&self) -> bool {
1033        self.inner.contains(Capabilities::WATCH_MY_TRADES)
1034    }
1035
1036    // ==================== Builder Method ====================
1037
1038    /// Create a builder for ExchangeCapabilities
1039    ///
1040    /// # Example
1041    ///
1042    /// ```rust
1043    /// use ccxt_core::capability::ExchangeCapabilities;
1044    ///
1045    /// let caps = ExchangeCapabilities::builder()
1046    ///     .market_data()
1047    ///     .trading()
1048    ///     .websocket()
1049    ///     .build();
1050    /// assert!(caps.fetch_ticker());
1051    /// assert!(caps.create_order());
1052    /// assert!(caps.websocket());
1053    /// ```
1054    pub fn builder() -> ExchangeCapabilitiesBuilder {
1055        ExchangeCapabilitiesBuilder::new()
1056    }
1057}
1058
1059impl From<Capabilities> for ExchangeCapabilities {
1060    fn from(caps: Capabilities) -> Self {
1061        Self::from_capabilities(caps)
1062    }
1063}
1064
1065impl fmt::Display for ExchangeCapabilities {
1066    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1067        write!(f, "ExchangeCapabilities({})", self.inner)
1068    }
1069}
1070
1071// ============================================================================
1072// ExchangeCapabilities Builder
1073// ============================================================================
1074
1075/// Builder for ExchangeCapabilities
1076///
1077/// Provides a fluent API for constructing capability sets.
1078///
1079/// # Example
1080///
1081/// ```rust
1082/// use ccxt_core::capability::ExchangeCapabilitiesBuilder;
1083///
1084/// let caps = ExchangeCapabilitiesBuilder::new()
1085///     .market_data()
1086///     .trading()
1087///     .capability(ccxt_core::capability::Capability::Websocket)
1088///     .build();
1089/// ```
1090#[derive(Debug, Clone, Default)]
1091pub struct ExchangeCapabilitiesBuilder {
1092    inner: Capabilities,
1093}
1094
1095impl ExchangeCapabilitiesBuilder {
1096    /// Create a new builder with no capabilities
1097    pub fn new() -> Self {
1098        Self {
1099            inner: Capabilities::empty(),
1100        }
1101    }
1102
1103    /// Add all market data capabilities
1104    pub fn market_data(mut self) -> Self {
1105        self.inner |= Capabilities::MARKET_DATA;
1106        self
1107    }
1108
1109    /// Add all trading capabilities
1110    pub fn trading(mut self) -> Self {
1111        self.inner |= Capabilities::TRADING;
1112        self
1113    }
1114
1115    /// Add all account capabilities
1116    pub fn account(mut self) -> Self {
1117        self.inner |= Capabilities::ACCOUNT;
1118        self
1119    }
1120
1121    /// Add all funding capabilities
1122    pub fn funding(mut self) -> Self {
1123        self.inner |= Capabilities::FUNDING;
1124        self
1125    }
1126
1127    /// Add all margin trading capabilities
1128    pub fn margin(mut self) -> Self {
1129        self.inner |= Capabilities::MARGIN;
1130        self
1131    }
1132
1133    /// Add all WebSocket capabilities
1134    pub fn websocket_all(mut self) -> Self {
1135        self.inner |= Capabilities::WEBSOCKET_ALL;
1136        self
1137    }
1138
1139    /// Add just the WebSocket base capability
1140    pub fn websocket(mut self) -> Self {
1141        self.inner |= Capabilities::WEBSOCKET;
1142        self
1143    }
1144
1145    /// Add all REST API capabilities
1146    pub fn rest_all(mut self) -> Self {
1147        self.inner |= Capabilities::REST_ALL;
1148        self
1149    }
1150
1151    /// Add all capabilities
1152    pub fn all(mut self) -> Self {
1153        self.inner = Capabilities::ALL;
1154        self
1155    }
1156
1157    /// Add a specific capability
1158    pub fn capability(mut self, cap: Capability) -> Self {
1159        self.inner |= Capabilities::from(cap);
1160        self
1161    }
1162
1163    /// Add multiple capabilities
1164    pub fn capabilities<I: IntoIterator<Item = Capability>>(mut self, caps: I) -> Self {
1165        for cap in caps {
1166            self.inner |= Capabilities::from(cap);
1167        }
1168        self
1169    }
1170
1171    /// Add raw Capabilities bitflags
1172    pub fn raw(mut self, caps: Capabilities) -> Self {
1173        self.inner |= caps;
1174        self
1175    }
1176
1177    /// Remove a specific capability
1178    pub fn without_capability(mut self, cap: Capability) -> Self {
1179        self.inner.remove(Capabilities::from(cap));
1180        self
1181    }
1182
1183    /// Remove capabilities
1184    pub fn without(mut self, caps: Capabilities) -> Self {
1185        self.inner.remove(caps);
1186        self
1187    }
1188
1189    /// Build the ExchangeCapabilities
1190    pub fn build(self) -> ExchangeCapabilities {
1191        ExchangeCapabilities { inner: self.inner }
1192    }
1193}
1194
1195// ============================================================================
1196// Presets for Common Exchange Configurations
1197// ============================================================================
1198
1199impl ExchangeCapabilities {
1200    /// Create capabilities for a typical spot exchange
1201    ///
1202    /// Includes: market data, trading, account, and basic WebSocket
1203    pub const fn spot_exchange() -> Self {
1204        Self {
1205            inner: Capabilities::from_bits_truncate(
1206                Capabilities::MARKET_DATA.bits()
1207                    | Capabilities::TRADING.bits()
1208                    | Capabilities::ACCOUNT.bits()
1209                    | Capabilities::WEBSOCKET.bits()
1210                    | Capabilities::WATCH_TICKER.bits()
1211                    | Capabilities::WATCH_ORDER_BOOK.bits()
1212                    | Capabilities::WATCH_TRADES.bits(),
1213            ),
1214        }
1215    }
1216
1217    /// Create capabilities for a typical futures exchange
1218    ///
1219    /// Includes: spot capabilities + margin trading
1220    pub const fn futures_exchange() -> Self {
1221        Self {
1222            inner: Capabilities::from_bits_truncate(
1223                Capabilities::MARKET_DATA.bits()
1224                    | Capabilities::TRADING.bits()
1225                    | Capabilities::ACCOUNT.bits()
1226                    | Capabilities::MARGIN.bits()
1227                    | Capabilities::WEBSOCKET_ALL.bits(),
1228            ),
1229        }
1230    }
1231
1232    /// Create capabilities for a full-featured exchange (like Binance)
1233    ///
1234    /// Includes: all capabilities
1235    pub const fn full_featured() -> Self {
1236        Self {
1237            inner: Capabilities::ALL,
1238        }
1239    }
1240}
1241
1242// ============================================================================
1243// Trait-Capability Mapping
1244// ============================================================================
1245
1246/// Trait category for capability-to-trait mapping.
1247///
1248/// This enum represents the decomposed trait hierarchy used in the exchange
1249/// trait system. Each variant corresponds to a specific trait that exchanges
1250/// can implement.
1251///
1252/// # Trait Hierarchy
1253///
1254/// ```text
1255/// PublicExchange (base trait - metadata, capabilities)
1256///     │
1257///     ├── MarketData (public market data)
1258///     ├── Trading (order management)
1259///     ├── Account (balance, trade history)
1260///     ├── Margin (positions, leverage, funding)
1261///     └── Funding (deposits, withdrawals, transfers)
1262///
1263/// FullExchange = PublicExchange + MarketData + Trading + Account + Margin + Funding
1264/// ```
1265///
1266/// # Capability Mapping
1267///
1268/// | Trait Category | Capabilities |
1269/// |----------------|--------------|
1270/// | `PublicExchange` | Base trait, always required |
1271/// | `MarketData` | FetchMarkets, FetchCurrencies, FetchTicker, FetchTickers, FetchOrderBook, FetchTrades, FetchOhlcv, FetchStatus, FetchTime |
1272/// | `Trading` | CreateOrder, CreateMarketOrder, CreateLimitOrder, CancelOrder, CancelAllOrders, EditOrder, FetchOrder, FetchOrders, FetchOpenOrders, FetchClosedOrders, FetchCanceledOrders |
1273/// | `Account` | FetchBalance, FetchMyTrades, FetchDeposits, FetchWithdrawals, FetchTransactions, FetchLedger |
1274/// | `Margin` | FetchBorrowRate, FetchBorrowRates, FetchFundingRate, FetchFundingRates, FetchPositions, SetLeverage, SetMarginMode |
1275/// | `Funding` | FetchDepositAddress, CreateDepositAddress, Withdraw, Transfer |
1276/// | `WebSocket` | Websocket, WatchTicker, WatchTickers, WatchOrderBook, WatchTrades, WatchOhlcv, WatchBalance, WatchOrders, WatchMyTrades |
1277#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1278pub enum TraitCategory {
1279    /// Base trait providing exchange metadata and capabilities.
1280    /// All exchanges must implement this trait.
1281    PublicExchange,
1282    /// Public market data operations (ticker, orderbook, trades, OHLCV).
1283    /// Corresponds to the `MarketData` trait.
1284    MarketData,
1285    /// Order management operations (create, cancel, fetch orders).
1286    /// Corresponds to the `Trading` trait.
1287    Trading,
1288    /// Account-related operations (balance, trade history).
1289    /// Corresponds to the `Account` trait.
1290    Account,
1291    /// Margin/futures trading operations (positions, leverage, funding).
1292    /// Corresponds to the `Margin` trait.
1293    Margin,
1294    /// Deposit/withdrawal operations.
1295    /// Corresponds to the `Funding` trait.
1296    Funding,
1297    /// WebSocket real-time data streaming.
1298    /// Corresponds to the `WsExchange` trait.
1299    WebSocket,
1300}
1301
1302impl TraitCategory {
1303    /// Get all trait categories.
1304    pub const fn all() -> [Self; 7] {
1305        [
1306            Self::PublicExchange,
1307            Self::MarketData,
1308            Self::Trading,
1309            Self::Account,
1310            Self::Margin,
1311            Self::Funding,
1312            Self::WebSocket,
1313        ]
1314    }
1315
1316    /// Get the display name for this trait category.
1317    pub const fn name(&self) -> &'static str {
1318        match self {
1319            Self::PublicExchange => "PublicExchange",
1320            Self::MarketData => "MarketData",
1321            Self::Trading => "Trading",
1322            Self::Account => "Account",
1323            Self::Margin => "Margin",
1324            Self::Funding => "Funding",
1325            Self::WebSocket => "WebSocket",
1326        }
1327    }
1328
1329    /// Get the capabilities associated with this trait category.
1330    pub const fn capabilities(&self) -> Capabilities {
1331        match self {
1332            Self::PublicExchange => Capabilities::empty(), // Base trait, no specific capabilities
1333            Self::MarketData => Capabilities::MARKET_DATA,
1334            Self::Trading => Capabilities::TRADING,
1335            Self::Account => Capabilities::ACCOUNT,
1336            Self::Margin => Capabilities::MARGIN,
1337            Self::Funding => Capabilities::FUNDING,
1338            Self::WebSocket => Capabilities::WEBSOCKET_ALL,
1339        }
1340    }
1341
1342    /// Get the minimum required capabilities for this trait.
1343    ///
1344    /// Returns the capabilities that MUST be present for an exchange
1345    /// to be considered as implementing this trait.
1346    pub const fn minimum_capabilities(&self) -> Capabilities {
1347        match self {
1348            Self::PublicExchange => Capabilities::empty(),
1349            // MarketData requires at least fetch_markets and fetch_ticker
1350            Self::MarketData => Capabilities::from_bits_truncate(
1351                Capabilities::FETCH_MARKETS.bits() | Capabilities::FETCH_TICKER.bits(),
1352            ),
1353            // Trading requires at least create_order and cancel_order
1354            Self::Trading => Capabilities::from_bits_truncate(
1355                Capabilities::CREATE_ORDER.bits() | Capabilities::CANCEL_ORDER.bits(),
1356            ),
1357            // Account requires at least fetch_balance
1358            Self::Account => Capabilities::FETCH_BALANCE,
1359            // Margin requires at least fetch_positions
1360            Self::Margin => Capabilities::FETCH_POSITIONS,
1361            // Funding requires at least fetch_deposit_address
1362            Self::Funding => Capabilities::FETCH_DEPOSIT_ADDRESS,
1363            // WebSocket requires the base websocket capability
1364            Self::WebSocket => Capabilities::WEBSOCKET,
1365        }
1366    }
1367}
1368
1369impl fmt::Display for TraitCategory {
1370    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1371        write!(f, "{}", self.name())
1372    }
1373}
1374
1375impl Capability {
1376    /// Get the trait category this capability belongs to.
1377    ///
1378    /// # Example
1379    ///
1380    /// ```rust
1381    /// use ccxt_core::capability::{Capability, TraitCategory};
1382    ///
1383    /// assert_eq!(Capability::FetchTicker.trait_category(), TraitCategory::MarketData);
1384    /// assert_eq!(Capability::CreateOrder.trait_category(), TraitCategory::Trading);
1385    /// assert_eq!(Capability::FetchBalance.trait_category(), TraitCategory::Account);
1386    /// ```
1387    pub const fn trait_category(&self) -> TraitCategory {
1388        match self {
1389            // Market Data
1390            Self::FetchMarkets
1391            | Self::FetchCurrencies
1392            | Self::FetchTicker
1393            | Self::FetchTickers
1394            | Self::FetchOrderBook
1395            | Self::FetchTrades
1396            | Self::FetchOhlcv
1397            | Self::FetchStatus
1398            | Self::FetchTime => TraitCategory::MarketData,
1399
1400            // Trading
1401            Self::CreateOrder
1402            | Self::CreateMarketOrder
1403            | Self::CreateLimitOrder
1404            | Self::CancelOrder
1405            | Self::CancelAllOrders
1406            | Self::EditOrder
1407            | Self::FetchOrder
1408            | Self::FetchOrders
1409            | Self::FetchOpenOrders
1410            | Self::FetchClosedOrders
1411            | Self::FetchCanceledOrders => TraitCategory::Trading,
1412
1413            // Account
1414            Self::FetchBalance
1415            | Self::FetchMyTrades
1416            | Self::FetchDeposits
1417            | Self::FetchWithdrawals
1418            | Self::FetchTransactions
1419            | Self::FetchLedger => TraitCategory::Account,
1420
1421            // Funding
1422            Self::FetchDepositAddress
1423            | Self::CreateDepositAddress
1424            | Self::Withdraw
1425            | Self::Transfer => TraitCategory::Funding,
1426
1427            // Margin
1428            Self::FetchBorrowRate
1429            | Self::FetchBorrowRates
1430            | Self::FetchFundingRate
1431            | Self::FetchFundingRates
1432            | Self::FetchPositions
1433            | Self::SetLeverage
1434            | Self::SetMarginMode => TraitCategory::Margin,
1435
1436            // WebSocket
1437            Self::Websocket
1438            | Self::WatchTicker
1439            | Self::WatchTickers
1440            | Self::WatchOrderBook
1441            | Self::WatchTrades
1442            | Self::WatchOhlcv
1443            | Self::WatchBalance
1444            | Self::WatchOrders
1445            | Self::WatchMyTrades => TraitCategory::WebSocket,
1446        }
1447    }
1448}
1449
1450impl ExchangeCapabilities {
1451    // ========================================================================
1452    // Trait Implementation Checks
1453    // ========================================================================
1454
1455    /// Check if the exchange supports the MarketData trait.
1456    ///
1457    /// Returns `true` if the exchange has the minimum capabilities required
1458    /// to implement the `MarketData` trait (fetch_markets and fetch_ticker).
1459    ///
1460    /// # Example
1461    ///
1462    /// ```rust
1463    /// use ccxt_core::capability::ExchangeCapabilities;
1464    ///
1465    /// let caps = ExchangeCapabilities::public_only();
1466    /// assert!(caps.supports_market_data());
1467    ///
1468    /// let caps = ExchangeCapabilities::none();
1469    /// assert!(!caps.supports_market_data());
1470    /// ```
1471    #[inline]
1472    pub const fn supports_market_data(&self) -> bool {
1473        self.inner
1474            .contains(TraitCategory::MarketData.minimum_capabilities())
1475    }
1476
1477    /// Check if the exchange supports the Trading trait.
1478    ///
1479    /// Returns `true` if the exchange has the minimum capabilities required
1480    /// to implement the `Trading` trait (create_order and cancel_order).
1481    ///
1482    /// # Example
1483    ///
1484    /// ```rust
1485    /// use ccxt_core::capability::ExchangeCapabilities;
1486    ///
1487    /// let caps = ExchangeCapabilities::all();
1488    /// assert!(caps.supports_trading());
1489    ///
1490    /// let caps = ExchangeCapabilities::public_only();
1491    /// assert!(!caps.supports_trading());
1492    /// ```
1493    #[inline]
1494    pub const fn supports_trading(&self) -> bool {
1495        self.inner
1496            .contains(TraitCategory::Trading.minimum_capabilities())
1497    }
1498
1499    /// Check if the exchange supports the Account trait.
1500    ///
1501    /// Returns `true` if the exchange has the minimum capabilities required
1502    /// to implement the `Account` trait (fetch_balance).
1503    ///
1504    /// # Example
1505    ///
1506    /// ```rust
1507    /// use ccxt_core::capability::ExchangeCapabilities;
1508    ///
1509    /// let caps = ExchangeCapabilities::all();
1510    /// assert!(caps.supports_account());
1511    ///
1512    /// let caps = ExchangeCapabilities::public_only();
1513    /// assert!(!caps.supports_account());
1514    /// ```
1515    #[inline]
1516    pub const fn supports_account(&self) -> bool {
1517        self.inner
1518            .contains(TraitCategory::Account.minimum_capabilities())
1519    }
1520
1521    /// Check if the exchange supports the Margin trait.
1522    ///
1523    /// Returns `true` if the exchange has the minimum capabilities required
1524    /// to implement the `Margin` trait (fetch_positions).
1525    ///
1526    /// # Example
1527    ///
1528    /// ```rust
1529    /// use ccxt_core::capability::ExchangeCapabilities;
1530    ///
1531    /// let caps = ExchangeCapabilities::futures_exchange();
1532    /// assert!(caps.supports_margin());
1533    ///
1534    /// let caps = ExchangeCapabilities::spot_exchange();
1535    /// assert!(!caps.supports_margin());
1536    /// ```
1537    #[inline]
1538    pub const fn supports_margin(&self) -> bool {
1539        self.inner
1540            .contains(TraitCategory::Margin.minimum_capabilities())
1541    }
1542
1543    /// Check if the exchange supports the Funding trait.
1544    ///
1545    /// Returns `true` if the exchange has the minimum capabilities required
1546    /// to implement the `Funding` trait (fetch_deposit_address).
1547    ///
1548    /// # Example
1549    ///
1550    /// ```rust
1551    /// use ccxt_core::capability::ExchangeCapabilities;
1552    ///
1553    /// let caps = ExchangeCapabilities::all();
1554    /// assert!(caps.supports_funding());
1555    ///
1556    /// let caps = ExchangeCapabilities::public_only();
1557    /// assert!(!caps.supports_funding());
1558    /// ```
1559    #[inline]
1560    pub const fn supports_funding(&self) -> bool {
1561        self.inner
1562            .contains(TraitCategory::Funding.minimum_capabilities())
1563    }
1564
1565    /// Check if the exchange supports WebSocket.
1566    ///
1567    /// Returns `true` if the exchange has the base WebSocket capability.
1568    ///
1569    /// # Example
1570    ///
1571    /// ```rust
1572    /// use ccxt_core::capability::ExchangeCapabilities;
1573    ///
1574    /// let caps = ExchangeCapabilities::all();
1575    /// assert!(caps.supports_websocket());
1576    ///
1577    /// let caps = ExchangeCapabilities::public_only();
1578    /// assert!(!caps.supports_websocket());
1579    /// ```
1580    #[inline]
1581    pub const fn supports_websocket(&self) -> bool {
1582        self.inner
1583            .contains(TraitCategory::WebSocket.minimum_capabilities())
1584    }
1585
1586    /// Check if the exchange supports all traits (FullExchange).
1587    ///
1588    /// Returns `true` if the exchange has the minimum capabilities required
1589    /// to implement all traits: MarketData, Trading, Account, Margin, and Funding.
1590    ///
1591    /// # Example
1592    ///
1593    /// ```rust
1594    /// use ccxt_core::capability::ExchangeCapabilities;
1595    ///
1596    /// let caps = ExchangeCapabilities::all();
1597    /// assert!(caps.supports_full_exchange());
1598    ///
1599    /// let caps = ExchangeCapabilities::spot_exchange();
1600    /// assert!(!caps.supports_full_exchange());
1601    /// ```
1602    #[inline]
1603    pub const fn supports_full_exchange(&self) -> bool {
1604        self.supports_market_data()
1605            && self.supports_trading()
1606            && self.supports_account()
1607            && self.supports_margin()
1608            && self.supports_funding()
1609    }
1610
1611    /// Check if the exchange supports a specific trait category.
1612    ///
1613    /// # Arguments
1614    ///
1615    /// * `category` - The trait category to check
1616    ///
1617    /// # Example
1618    ///
1619    /// ```rust
1620    /// use ccxt_core::capability::{ExchangeCapabilities, TraitCategory};
1621    ///
1622    /// let caps = ExchangeCapabilities::all();
1623    /// assert!(caps.supports_trait(TraitCategory::MarketData));
1624    /// assert!(caps.supports_trait(TraitCategory::Trading));
1625    /// ```
1626    pub const fn supports_trait(&self, category: TraitCategory) -> bool {
1627        match category {
1628            TraitCategory::PublicExchange => true, // Always supported
1629            TraitCategory::MarketData => self.supports_market_data(),
1630            TraitCategory::Trading => self.supports_trading(),
1631            TraitCategory::Account => self.supports_account(),
1632            TraitCategory::Margin => self.supports_margin(),
1633            TraitCategory::Funding => self.supports_funding(),
1634            TraitCategory::WebSocket => self.supports_websocket(),
1635        }
1636    }
1637
1638    /// Get a list of supported trait categories.
1639    ///
1640    /// Returns a vector of trait categories that this exchange supports
1641    /// based on its capabilities.
1642    ///
1643    /// # Example
1644    ///
1645    /// ```rust
1646    /// use ccxt_core::capability::{ExchangeCapabilities, TraitCategory};
1647    ///
1648    /// let caps = ExchangeCapabilities::public_only();
1649    /// let traits = caps.supported_traits();
1650    /// assert!(traits.contains(&TraitCategory::PublicExchange));
1651    /// assert!(traits.contains(&TraitCategory::MarketData));
1652    /// assert!(!traits.contains(&TraitCategory::Trading));
1653    /// ```
1654    pub fn supported_traits(&self) -> Vec<TraitCategory> {
1655        TraitCategory::all()
1656            .iter()
1657            .filter(|cat| self.supports_trait(**cat))
1658            .copied()
1659            .collect()
1660    }
1661
1662    /// Get capabilities for a specific trait category.
1663    ///
1664    /// Returns the capabilities that are enabled for the specified trait category.
1665    ///
1666    /// # Arguments
1667    ///
1668    /// * `category` - The trait category to get capabilities for
1669    ///
1670    /// # Example
1671    ///
1672    /// ```rust
1673    /// use ccxt_core::capability::{ExchangeCapabilities, TraitCategory, Capabilities};
1674    ///
1675    /// let caps = ExchangeCapabilities::all();
1676    /// let market_caps = caps.capabilities_for_trait(TraitCategory::MarketData);
1677    /// assert!(market_caps.contains(Capabilities::FETCH_TICKER));
1678    /// ```
1679    pub const fn capabilities_for_trait(&self, category: TraitCategory) -> Capabilities {
1680        Capabilities::from_bits_truncate(self.inner.bits() & category.capabilities().bits())
1681    }
1682
1683    /// Get the trait category for a specific capability.
1684    ///
1685    /// # Arguments
1686    ///
1687    /// * `capability` - The capability to get the trait category for
1688    ///
1689    /// # Example
1690    ///
1691    /// ```rust
1692    /// use ccxt_core::capability::{ExchangeCapabilities, Capability, TraitCategory};
1693    ///
1694    /// let category = ExchangeCapabilities::trait_for_capability(Capability::FetchTicker);
1695    /// assert_eq!(category, TraitCategory::MarketData);
1696    /// ```
1697    pub const fn trait_for_capability(capability: Capability) -> TraitCategory {
1698        capability.trait_category()
1699    }
1700}
1701
1702// ============================================================================
1703// Unit Tests
1704// ============================================================================
1705
1706#[cfg(test)]
1707mod tests {
1708    use super::*;
1709
1710    #[test]
1711    fn test_capability_count() {
1712        assert_eq!(Capability::COUNT, 46);
1713    }
1714
1715    #[test]
1716    fn test_capability_ccxt_names() {
1717        assert_eq!(Capability::FetchTicker.as_ccxt_name(), "fetchTicker");
1718        assert_eq!(Capability::CreateOrder.as_ccxt_name(), "createOrder");
1719        assert_eq!(Capability::FetchOhlcv.as_ccxt_name(), "fetchOHLCV");
1720        assert_eq!(Capability::WatchOhlcv.as_ccxt_name(), "watchOHLCV");
1721    }
1722
1723    #[test]
1724    fn test_capability_from_ccxt_name() {
1725        assert_eq!(
1726            Capability::from_ccxt_name("fetchTicker"),
1727            Some(Capability::FetchTicker)
1728        );
1729        assert_eq!(
1730            Capability::from_ccxt_name("createOrder"),
1731            Some(Capability::CreateOrder)
1732        );
1733        assert_eq!(Capability::from_ccxt_name("unknown"), None);
1734    }
1735
1736    #[test]
1737    fn test_capabilities_bitflags() {
1738        let caps = Capabilities::FETCH_TICKER | Capabilities::CREATE_ORDER;
1739        assert!(caps.contains(Capabilities::FETCH_TICKER));
1740        assert!(caps.contains(Capabilities::CREATE_ORDER));
1741        assert!(!caps.contains(Capabilities::WEBSOCKET));
1742    }
1743
1744    #[test]
1745    fn test_capabilities_presets() {
1746        // Market data should include all fetch* for public data
1747        assert!(Capabilities::MARKET_DATA.contains(Capabilities::FETCH_TICKER));
1748        assert!(Capabilities::MARKET_DATA.contains(Capabilities::FETCH_ORDER_BOOK));
1749        assert!(!Capabilities::MARKET_DATA.contains(Capabilities::CREATE_ORDER));
1750
1751        // Trading should include order operations
1752        assert!(Capabilities::TRADING.contains(Capabilities::CREATE_ORDER));
1753        assert!(Capabilities::TRADING.contains(Capabilities::CANCEL_ORDER));
1754        assert!(!Capabilities::TRADING.contains(Capabilities::FETCH_TICKER));
1755    }
1756
1757    #[test]
1758    fn test_capabilities_has() {
1759        let caps = Capabilities::MARKET_DATA;
1760        assert!(caps.has("fetchTicker"));
1761        assert!(caps.has("fetchOrderBook"));
1762        assert!(!caps.has("createOrder"));
1763        assert!(!caps.has("unknownCapability"));
1764    }
1765
1766    #[test]
1767    fn test_capabilities_count() {
1768        assert_eq!(Capabilities::empty().count(), 0);
1769        assert_eq!(Capabilities::FETCH_TICKER.count(), 1);
1770        assert_eq!(
1771            (Capabilities::FETCH_TICKER | Capabilities::CREATE_ORDER).count(),
1772            2
1773        );
1774        assert_eq!(Capabilities::MARKET_DATA.count(), 9);
1775    }
1776
1777    #[test]
1778    fn test_capabilities_from_iter() {
1779        let caps = Capabilities::from_iter([
1780            Capability::FetchTicker,
1781            Capability::CreateOrder,
1782            Capability::Websocket,
1783        ]);
1784        assert!(caps.contains(Capabilities::FETCH_TICKER));
1785        assert!(caps.contains(Capabilities::CREATE_ORDER));
1786        assert!(caps.contains(Capabilities::WEBSOCKET));
1787        assert_eq!(caps.count(), 3);
1788    }
1789
1790    #[test]
1791    fn test_exchange_capabilities_all() {
1792        let caps = ExchangeCapabilities::all();
1793        assert!(caps.fetch_ticker());
1794        assert!(caps.create_order());
1795        assert!(caps.websocket());
1796        assert!(caps.fetch_positions());
1797    }
1798
1799    #[test]
1800    fn test_exchange_capabilities_public_only() {
1801        let caps = ExchangeCapabilities::public_only();
1802        assert!(caps.fetch_ticker());
1803        assert!(caps.fetch_order_book());
1804        assert!(!caps.create_order());
1805        assert!(!caps.fetch_balance());
1806    }
1807
1808    #[test]
1809    fn test_exchange_capabilities_has() {
1810        let caps = ExchangeCapabilities::all();
1811        assert!(caps.has("fetchTicker"));
1812        assert!(caps.has("createOrder"));
1813        assert!(!caps.has("unknownCapability"));
1814    }
1815
1816    #[test]
1817    fn test_exchange_capabilities_builder() {
1818        let caps = ExchangeCapabilities::builder()
1819            .market_data()
1820            .trading()
1821            .build();
1822
1823        assert!(caps.fetch_ticker());
1824        assert!(caps.create_order());
1825        assert!(!caps.websocket());
1826    }
1827
1828    #[test]
1829    fn test_exchange_capabilities_builder_with_capability() {
1830        let caps = ExchangeCapabilities::builder()
1831            .capability(Capability::FetchTicker)
1832            .capability(Capability::Websocket)
1833            .build();
1834
1835        assert!(caps.fetch_ticker());
1836        assert!(caps.websocket());
1837        assert!(!caps.create_order());
1838    }
1839
1840    #[test]
1841    fn test_exchange_capabilities_builder_without() {
1842        let caps = ExchangeCapabilities::builder()
1843            .all()
1844            .without_capability(Capability::Websocket)
1845            .build();
1846
1847        assert!(caps.fetch_ticker());
1848        assert!(caps.create_order());
1849        assert!(!caps.websocket());
1850    }
1851
1852    #[test]
1853    fn test_exchange_capabilities_presets() {
1854        let spot = ExchangeCapabilities::spot_exchange();
1855        assert!(spot.fetch_ticker());
1856        assert!(spot.create_order());
1857        assert!(spot.websocket());
1858        assert!(!spot.fetch_positions()); // No margin trading
1859
1860        let futures = ExchangeCapabilities::futures_exchange();
1861        assert!(futures.fetch_ticker());
1862        assert!(futures.create_order());
1863        assert!(futures.fetch_positions());
1864        assert!(futures.set_leverage());
1865    }
1866
1867    #[test]
1868    fn test_capabilities_macro() {
1869        let caps = capabilities!(MARKET_DATA);
1870        assert!(caps.contains(Capabilities::FETCH_TICKER));
1871
1872        let caps = capabilities!(FETCH_TICKER | CREATE_ORDER);
1873        assert!(caps.contains(Capabilities::FETCH_TICKER));
1874        assert!(caps.contains(Capabilities::CREATE_ORDER));
1875
1876        let caps = capabilities!(MARKET_DATA, TRADING);
1877        assert!(caps.contains(Capabilities::FETCH_TICKER));
1878        assert!(caps.contains(Capabilities::CREATE_ORDER));
1879    }
1880
1881    #[test]
1882    fn test_capability_bit_positions() {
1883        // Verify bit positions match enum values
1884        assert_eq!(Capability::FetchMarkets.bit_position(), 1 << 0);
1885        assert_eq!(Capability::FetchTicker.bit_position(), 1 << 2);
1886        assert_eq!(Capability::CreateOrder.bit_position(), 1 << 9);
1887        assert_eq!(Capability::Websocket.bit_position(), 1 << 37);
1888    }
1889
1890    #[test]
1891    fn test_memory_efficiency() {
1892        // ExchangeCapabilities should be 8 bytes (u64)
1893        assert_eq!(std::mem::size_of::<ExchangeCapabilities>(), 8);
1894        assert_eq!(std::mem::size_of::<Capabilities>(), 8);
1895    }
1896
1897    // ========================================================================
1898    // Trait-Capability Mapping Tests
1899    // ========================================================================
1900
1901    #[test]
1902    fn test_trait_category_all() {
1903        let categories = TraitCategory::all();
1904        assert_eq!(categories.len(), 7);
1905        assert!(categories.contains(&TraitCategory::PublicExchange));
1906        assert!(categories.contains(&TraitCategory::MarketData));
1907        assert!(categories.contains(&TraitCategory::Trading));
1908        assert!(categories.contains(&TraitCategory::Account));
1909        assert!(categories.contains(&TraitCategory::Margin));
1910        assert!(categories.contains(&TraitCategory::Funding));
1911        assert!(categories.contains(&TraitCategory::WebSocket));
1912    }
1913
1914    #[test]
1915    fn test_trait_category_names() {
1916        assert_eq!(TraitCategory::PublicExchange.name(), "PublicExchange");
1917        assert_eq!(TraitCategory::MarketData.name(), "MarketData");
1918        assert_eq!(TraitCategory::Trading.name(), "Trading");
1919        assert_eq!(TraitCategory::Account.name(), "Account");
1920        assert_eq!(TraitCategory::Margin.name(), "Margin");
1921        assert_eq!(TraitCategory::Funding.name(), "Funding");
1922        assert_eq!(TraitCategory::WebSocket.name(), "WebSocket");
1923    }
1924
1925    #[test]
1926    fn test_trait_category_capabilities() {
1927        assert_eq!(
1928            TraitCategory::PublicExchange.capabilities(),
1929            Capabilities::empty()
1930        );
1931        assert_eq!(
1932            TraitCategory::MarketData.capabilities(),
1933            Capabilities::MARKET_DATA
1934        );
1935        assert_eq!(TraitCategory::Trading.capabilities(), Capabilities::TRADING);
1936        assert_eq!(TraitCategory::Account.capabilities(), Capabilities::ACCOUNT);
1937        assert_eq!(TraitCategory::Margin.capabilities(), Capabilities::MARGIN);
1938        assert_eq!(TraitCategory::Funding.capabilities(), Capabilities::FUNDING);
1939        assert_eq!(
1940            TraitCategory::WebSocket.capabilities(),
1941            Capabilities::WEBSOCKET_ALL
1942        );
1943    }
1944
1945    #[test]
1946    fn test_capability_trait_category() {
1947        // Market Data
1948        assert_eq!(
1949            Capability::FetchTicker.trait_category(),
1950            TraitCategory::MarketData
1951        );
1952        assert_eq!(
1953            Capability::FetchMarkets.trait_category(),
1954            TraitCategory::MarketData
1955        );
1956        assert_eq!(
1957            Capability::FetchOhlcv.trait_category(),
1958            TraitCategory::MarketData
1959        );
1960
1961        // Trading
1962        assert_eq!(
1963            Capability::CreateOrder.trait_category(),
1964            TraitCategory::Trading
1965        );
1966        assert_eq!(
1967            Capability::CancelOrder.trait_category(),
1968            TraitCategory::Trading
1969        );
1970        assert_eq!(
1971            Capability::FetchOpenOrders.trait_category(),
1972            TraitCategory::Trading
1973        );
1974
1975        // Account
1976        assert_eq!(
1977            Capability::FetchBalance.trait_category(),
1978            TraitCategory::Account
1979        );
1980        assert_eq!(
1981            Capability::FetchMyTrades.trait_category(),
1982            TraitCategory::Account
1983        );
1984
1985        // Margin
1986        assert_eq!(
1987            Capability::FetchPositions.trait_category(),
1988            TraitCategory::Margin
1989        );
1990        assert_eq!(
1991            Capability::SetLeverage.trait_category(),
1992            TraitCategory::Margin
1993        );
1994        assert_eq!(
1995            Capability::FetchFundingRate.trait_category(),
1996            TraitCategory::Margin
1997        );
1998
1999        // Funding
2000        assert_eq!(
2001            Capability::FetchDepositAddress.trait_category(),
2002            TraitCategory::Funding
2003        );
2004        assert_eq!(
2005            Capability::Withdraw.trait_category(),
2006            TraitCategory::Funding
2007        );
2008        assert_eq!(
2009            Capability::Transfer.trait_category(),
2010            TraitCategory::Funding
2011        );
2012
2013        // WebSocket
2014        assert_eq!(
2015            Capability::Websocket.trait_category(),
2016            TraitCategory::WebSocket
2017        );
2018        assert_eq!(
2019            Capability::WatchTicker.trait_category(),
2020            TraitCategory::WebSocket
2021        );
2022    }
2023
2024    #[test]
2025    fn test_supports_market_data() {
2026        let caps = ExchangeCapabilities::public_only();
2027        assert!(caps.supports_market_data());
2028
2029        let caps = ExchangeCapabilities::none();
2030        assert!(!caps.supports_market_data());
2031
2032        // Only fetch_markets is not enough
2033        let caps = ExchangeCapabilities::builder()
2034            .capability(Capability::FetchMarkets)
2035            .build();
2036        assert!(!caps.supports_market_data());
2037
2038        // Both fetch_markets and fetch_ticker are required
2039        let caps = ExchangeCapabilities::builder()
2040            .capability(Capability::FetchMarkets)
2041            .capability(Capability::FetchTicker)
2042            .build();
2043        assert!(caps.supports_market_data());
2044    }
2045
2046    #[test]
2047    fn test_supports_trading() {
2048        let caps = ExchangeCapabilities::all();
2049        assert!(caps.supports_trading());
2050
2051        let caps = ExchangeCapabilities::public_only();
2052        assert!(!caps.supports_trading());
2053
2054        // Both create_order and cancel_order are required
2055        let caps = ExchangeCapabilities::builder()
2056            .capability(Capability::CreateOrder)
2057            .capability(Capability::CancelOrder)
2058            .build();
2059        assert!(caps.supports_trading());
2060    }
2061
2062    #[test]
2063    fn test_supports_account() {
2064        let caps = ExchangeCapabilities::all();
2065        assert!(caps.supports_account());
2066
2067        let caps = ExchangeCapabilities::public_only();
2068        assert!(!caps.supports_account());
2069
2070        let caps = ExchangeCapabilities::builder()
2071            .capability(Capability::FetchBalance)
2072            .build();
2073        assert!(caps.supports_account());
2074    }
2075
2076    #[test]
2077    fn test_supports_margin() {
2078        let caps = ExchangeCapabilities::futures_exchange();
2079        assert!(caps.supports_margin());
2080
2081        let caps = ExchangeCapabilities::spot_exchange();
2082        assert!(!caps.supports_margin());
2083
2084        let caps = ExchangeCapabilities::builder()
2085            .capability(Capability::FetchPositions)
2086            .build();
2087        assert!(caps.supports_margin());
2088    }
2089
2090    #[test]
2091    fn test_supports_funding() {
2092        let caps = ExchangeCapabilities::all();
2093        assert!(caps.supports_funding());
2094
2095        let caps = ExchangeCapabilities::public_only();
2096        assert!(!caps.supports_funding());
2097
2098        let caps = ExchangeCapabilities::builder()
2099            .capability(Capability::FetchDepositAddress)
2100            .build();
2101        assert!(caps.supports_funding());
2102    }
2103
2104    #[test]
2105    fn test_supports_websocket() {
2106        let caps = ExchangeCapabilities::all();
2107        assert!(caps.supports_websocket());
2108
2109        let caps = ExchangeCapabilities::public_only();
2110        assert!(!caps.supports_websocket());
2111
2112        let caps = ExchangeCapabilities::builder()
2113            .capability(Capability::Websocket)
2114            .build();
2115        assert!(caps.supports_websocket());
2116    }
2117
2118    #[test]
2119    fn test_supports_full_exchange() {
2120        let caps = ExchangeCapabilities::all();
2121        assert!(caps.supports_full_exchange());
2122
2123        let caps = ExchangeCapabilities::spot_exchange();
2124        assert!(!caps.supports_full_exchange()); // Missing margin and funding
2125
2126        let caps = ExchangeCapabilities::futures_exchange();
2127        assert!(!caps.supports_full_exchange()); // Missing funding
2128    }
2129
2130    #[test]
2131    fn test_supports_trait() {
2132        let caps = ExchangeCapabilities::all();
2133        assert!(caps.supports_trait(TraitCategory::PublicExchange));
2134        assert!(caps.supports_trait(TraitCategory::MarketData));
2135        assert!(caps.supports_trait(TraitCategory::Trading));
2136        assert!(caps.supports_trait(TraitCategory::Account));
2137        assert!(caps.supports_trait(TraitCategory::Margin));
2138        assert!(caps.supports_trait(TraitCategory::Funding));
2139        assert!(caps.supports_trait(TraitCategory::WebSocket));
2140
2141        let caps = ExchangeCapabilities::public_only();
2142        assert!(caps.supports_trait(TraitCategory::PublicExchange));
2143        assert!(caps.supports_trait(TraitCategory::MarketData));
2144        assert!(!caps.supports_trait(TraitCategory::Trading));
2145        assert!(!caps.supports_trait(TraitCategory::Account));
2146        assert!(!caps.supports_trait(TraitCategory::Margin));
2147        assert!(!caps.supports_trait(TraitCategory::Funding));
2148        assert!(!caps.supports_trait(TraitCategory::WebSocket));
2149    }
2150
2151    #[test]
2152    fn test_supported_traits() {
2153        let caps = ExchangeCapabilities::public_only();
2154        let traits = caps.supported_traits();
2155        assert!(traits.contains(&TraitCategory::PublicExchange));
2156        assert!(traits.contains(&TraitCategory::MarketData));
2157        assert!(!traits.contains(&TraitCategory::Trading));
2158
2159        let caps = ExchangeCapabilities::all();
2160        let traits = caps.supported_traits();
2161        assert_eq!(traits.len(), 7); // All traits supported
2162    }
2163
2164    #[test]
2165    fn test_capabilities_for_trait() {
2166        let caps = ExchangeCapabilities::all();
2167
2168        let market_caps = caps.capabilities_for_trait(TraitCategory::MarketData);
2169        assert!(market_caps.contains(Capabilities::FETCH_TICKER));
2170        assert!(market_caps.contains(Capabilities::FETCH_ORDER_BOOK));
2171        assert!(!market_caps.contains(Capabilities::CREATE_ORDER));
2172
2173        let trading_caps = caps.capabilities_for_trait(TraitCategory::Trading);
2174        assert!(trading_caps.contains(Capabilities::CREATE_ORDER));
2175        assert!(trading_caps.contains(Capabilities::CANCEL_ORDER));
2176        assert!(!trading_caps.contains(Capabilities::FETCH_TICKER));
2177    }
2178
2179    #[test]
2180    fn test_trait_for_capability() {
2181        assert_eq!(
2182            ExchangeCapabilities::trait_for_capability(Capability::FetchTicker),
2183            TraitCategory::MarketData
2184        );
2185        assert_eq!(
2186            ExchangeCapabilities::trait_for_capability(Capability::CreateOrder),
2187            TraitCategory::Trading
2188        );
2189        assert_eq!(
2190            ExchangeCapabilities::trait_for_capability(Capability::FetchBalance),
2191            TraitCategory::Account
2192        );
2193    }
2194
2195    #[test]
2196    fn test_trait_category_display() {
2197        assert_eq!(format!("{}", TraitCategory::MarketData), "MarketData");
2198        assert_eq!(format!("{}", TraitCategory::Trading), "Trading");
2199    }
2200}