1#![allow(missing_docs)]
8use bitflags::bitflags;
32use std::fmt;
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
53#[repr(u8)]
54pub enum Capability {
55 FetchMarkets = 0,
58 FetchCurrencies = 1,
60 FetchTicker = 2,
62 FetchTickers = 3,
64 FetchOrderBook = 4,
66 FetchTrades = 5,
68 FetchOhlcv = 6,
70 FetchStatus = 7,
72 FetchTime = 8,
74
75 CreateOrder = 9,
78 CreateMarketOrder = 10,
80 CreateLimitOrder = 11,
82 CancelOrder = 12,
84 CancelAllOrders = 13,
86 EditOrder = 14,
88 FetchOrder = 15,
90 FetchOrders = 16,
92 FetchOpenOrders = 17,
94 FetchClosedOrders = 18,
96 FetchCanceledOrders = 19,
98
99 FetchBalance = 20,
102 FetchMyTrades = 21,
104 FetchDeposits = 22,
106 FetchWithdrawals = 23,
108 FetchTransactions = 24,
110 FetchLedger = 25,
112
113 FetchDepositAddress = 26,
116 CreateDepositAddress = 27,
118 Withdraw = 28,
120 Transfer = 29,
122
123 FetchBorrowRate = 30,
126 FetchBorrowRates = 31,
128 FetchFundingRate = 32,
130 FetchFundingRates = 33,
132 FetchPositions = 34,
134 SetLeverage = 35,
136 SetMarginMode = 36,
138
139 Websocket = 37,
142 WatchTicker = 38,
144 WatchTickers = 39,
146 WatchOrderBook = 40,
148 WatchTrades = 41,
150 WatchOhlcv = 42,
152 WatchBalance = 43,
154 WatchOrders = 44,
156 WatchMyTrades = 45,
158}
159
160impl Capability {
161 pub const COUNT: usize = 46;
163
164 pub const fn as_ccxt_name(&self) -> &'static str {
175 match self {
176 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 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 Self::FetchBalance => "fetchBalance",
200 Self::FetchMyTrades => "fetchMyTrades",
201 Self::FetchDeposits => "fetchDeposits",
202 Self::FetchWithdrawals => "fetchWithdrawals",
203 Self::FetchTransactions => "fetchTransactions",
204 Self::FetchLedger => "fetchLedger",
205 Self::FetchDepositAddress => "fetchDepositAddress",
207 Self::CreateDepositAddress => "createDepositAddress",
208 Self::Withdraw => "withdraw",
209 Self::Transfer => "transfer",
210 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 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 pub fn from_ccxt_name(name: &str) -> Option<Self> {
242 match name {
243 "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 "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 "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 "fetchDepositAddress" => Some(Self::FetchDepositAddress),
274 "createDepositAddress" => Some(Self::CreateDepositAddress),
275 "withdraw" => Some(Self::Withdraw),
276 "transfer" => Some(Self::Transfer),
277 "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" => 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 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 #[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
364bitflags! {
369 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
397 pub struct Capabilities: u64 {
398 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 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 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 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 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 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 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 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 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 const FUNDING = Self::FETCH_DEPOSIT_ADDRESS.bits()
491 | Self::CREATE_DEPOSIT_ADDRESS.bits()
492 | Self::WITHDRAW.bits()
493 | Self::TRANSFER.bits();
494
495 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 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 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 const PUBLIC_ONLY = Self::MARKET_DATA.bits();
524
525 const ALL = Self::REST_ALL.bits() | Self::WEBSOCKET_ALL.bits();
527 }
528}
529
530impl Capabilities {
531 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 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 #[inline]
571 pub fn count(&self) -> u32 {
572 self.bits().count_ones()
573 }
574
575 #[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#[macro_export]
622macro_rules! capabilities {
623 ($cap:ident) => {
625 $crate::capability::Capabilities::$cap
626 };
627 ($cap:ident | $($rest:tt)+) => {
629 $crate::capability::Capabilities::$cap | capabilities!($($rest)+)
630 };
631 ($cap:ident, $($rest:tt)+) => {
633 $crate::capability::Capabilities::$cap | capabilities!($($rest)+)
634 };
635}
636
637#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
661pub struct ExchangeCapabilities {
662 inner: Capabilities,
663}
664
665impl ExchangeCapabilities {
666 pub const fn none() -> Self {
668 Self {
669 inner: Capabilities::empty(),
670 }
671 }
672
673 pub const fn all() -> Self {
686 Self {
687 inner: Capabilities::ALL,
688 }
689 }
690
691 pub const fn public_only() -> Self {
703 Self {
704 inner: Capabilities::PUBLIC_ONLY,
705 }
706 }
707
708 pub const fn from_capabilities(caps: Capabilities) -> Self {
710 Self { inner: caps }
711 }
712
713 pub const fn as_capabilities(&self) -> Capabilities {
715 self.inner
716 }
717
718 pub fn has(&self, capability: &str) -> bool {
737 self.inner.has(capability)
738 }
739
740 pub fn supported_capabilities(&self) -> Vec<&'static str> {
742 self.inner.supported_capabilities()
743 }
744
745 #[inline]
747 pub fn count(&self) -> u32 {
748 self.inner.count()
749 }
750
751 #[inline]
755 pub const fn fetch_markets(&self) -> bool {
756 self.inner.contains(Capabilities::FETCH_MARKETS)
757 }
758
759 #[inline]
761 pub const fn fetch_currencies(&self) -> bool {
762 self.inner.contains(Capabilities::FETCH_CURRENCIES)
763 }
764
765 #[inline]
767 pub const fn fetch_ticker(&self) -> bool {
768 self.inner.contains(Capabilities::FETCH_TICKER)
769 }
770
771 #[inline]
773 pub const fn fetch_tickers(&self) -> bool {
774 self.inner.contains(Capabilities::FETCH_TICKERS)
775 }
776
777 #[inline]
779 pub const fn fetch_order_book(&self) -> bool {
780 self.inner.contains(Capabilities::FETCH_ORDER_BOOK)
781 }
782
783 #[inline]
785 pub const fn fetch_trades(&self) -> bool {
786 self.inner.contains(Capabilities::FETCH_TRADES)
787 }
788
789 #[inline]
791 pub const fn fetch_ohlcv(&self) -> bool {
792 self.inner.contains(Capabilities::FETCH_OHLCV)
793 }
794
795 #[inline]
797 pub const fn fetch_status(&self) -> bool {
798 self.inner.contains(Capabilities::FETCH_STATUS)
799 }
800
801 #[inline]
803 pub const fn fetch_time(&self) -> bool {
804 self.inner.contains(Capabilities::FETCH_TIME)
805 }
806
807 #[inline]
811 pub const fn create_order(&self) -> bool {
812 self.inner.contains(Capabilities::CREATE_ORDER)
813 }
814
815 #[inline]
817 pub const fn create_market_order(&self) -> bool {
818 self.inner.contains(Capabilities::CREATE_MARKET_ORDER)
819 }
820
821 #[inline]
823 pub const fn create_limit_order(&self) -> bool {
824 self.inner.contains(Capabilities::CREATE_LIMIT_ORDER)
825 }
826
827 #[inline]
829 pub const fn cancel_order(&self) -> bool {
830 self.inner.contains(Capabilities::CANCEL_ORDER)
831 }
832
833 #[inline]
835 pub const fn cancel_all_orders(&self) -> bool {
836 self.inner.contains(Capabilities::CANCEL_ALL_ORDERS)
837 }
838
839 #[inline]
841 pub const fn edit_order(&self) -> bool {
842 self.inner.contains(Capabilities::EDIT_ORDER)
843 }
844
845 #[inline]
847 pub const fn fetch_order(&self) -> bool {
848 self.inner.contains(Capabilities::FETCH_ORDER)
849 }
850
851 #[inline]
853 pub const fn fetch_orders(&self) -> bool {
854 self.inner.contains(Capabilities::FETCH_ORDERS)
855 }
856
857 #[inline]
859 pub const fn fetch_open_orders(&self) -> bool {
860 self.inner.contains(Capabilities::FETCH_OPEN_ORDERS)
861 }
862
863 #[inline]
865 pub const fn fetch_closed_orders(&self) -> bool {
866 self.inner.contains(Capabilities::FETCH_CLOSED_ORDERS)
867 }
868
869 #[inline]
871 pub const fn fetch_canceled_orders(&self) -> bool {
872 self.inner.contains(Capabilities::FETCH_CANCELED_ORDERS)
873 }
874
875 #[inline]
879 pub const fn fetch_balance(&self) -> bool {
880 self.inner.contains(Capabilities::FETCH_BALANCE)
881 }
882
883 #[inline]
885 pub const fn fetch_my_trades(&self) -> bool {
886 self.inner.contains(Capabilities::FETCH_MY_TRADES)
887 }
888
889 #[inline]
891 pub const fn fetch_deposits(&self) -> bool {
892 self.inner.contains(Capabilities::FETCH_DEPOSITS)
893 }
894
895 #[inline]
897 pub const fn fetch_withdrawals(&self) -> bool {
898 self.inner.contains(Capabilities::FETCH_WITHDRAWALS)
899 }
900
901 #[inline]
903 pub const fn fetch_transactions(&self) -> bool {
904 self.inner.contains(Capabilities::FETCH_TRANSACTIONS)
905 }
906
907 #[inline]
909 pub const fn fetch_ledger(&self) -> bool {
910 self.inner.contains(Capabilities::FETCH_LEDGER)
911 }
912
913 #[inline]
917 pub const fn fetch_deposit_address(&self) -> bool {
918 self.inner.contains(Capabilities::FETCH_DEPOSIT_ADDRESS)
919 }
920
921 #[inline]
923 pub const fn create_deposit_address(&self) -> bool {
924 self.inner.contains(Capabilities::CREATE_DEPOSIT_ADDRESS)
925 }
926
927 #[inline]
929 pub const fn withdraw(&self) -> bool {
930 self.inner.contains(Capabilities::WITHDRAW)
931 }
932
933 #[inline]
935 pub const fn transfer(&self) -> bool {
936 self.inner.contains(Capabilities::TRANSFER)
937 }
938
939 #[inline]
943 pub const fn fetch_borrow_rate(&self) -> bool {
944 self.inner.contains(Capabilities::FETCH_BORROW_RATE)
945 }
946
947 #[inline]
949 pub const fn fetch_borrow_rates(&self) -> bool {
950 self.inner.contains(Capabilities::FETCH_BORROW_RATES)
951 }
952
953 #[inline]
955 pub const fn fetch_funding_rate(&self) -> bool {
956 self.inner.contains(Capabilities::FETCH_FUNDING_RATE)
957 }
958
959 #[inline]
961 pub const fn fetch_funding_rates(&self) -> bool {
962 self.inner.contains(Capabilities::FETCH_FUNDING_RATES)
963 }
964
965 #[inline]
967 pub const fn fetch_positions(&self) -> bool {
968 self.inner.contains(Capabilities::FETCH_POSITIONS)
969 }
970
971 #[inline]
973 pub const fn set_leverage(&self) -> bool {
974 self.inner.contains(Capabilities::SET_LEVERAGE)
975 }
976
977 #[inline]
979 pub const fn set_margin_mode(&self) -> bool {
980 self.inner.contains(Capabilities::SET_MARGIN_MODE)
981 }
982
983 #[inline]
987 pub const fn websocket(&self) -> bool {
988 self.inner.contains(Capabilities::WEBSOCKET)
989 }
990
991 #[inline]
993 pub const fn watch_ticker(&self) -> bool {
994 self.inner.contains(Capabilities::WATCH_TICKER)
995 }
996
997 #[inline]
999 pub const fn watch_tickers(&self) -> bool {
1000 self.inner.contains(Capabilities::WATCH_TICKERS)
1001 }
1002
1003 #[inline]
1005 pub const fn watch_order_book(&self) -> bool {
1006 self.inner.contains(Capabilities::WATCH_ORDER_BOOK)
1007 }
1008
1009 #[inline]
1011 pub const fn watch_trades(&self) -> bool {
1012 self.inner.contains(Capabilities::WATCH_TRADES)
1013 }
1014
1015 #[inline]
1017 pub const fn watch_ohlcv(&self) -> bool {
1018 self.inner.contains(Capabilities::WATCH_OHLCV)
1019 }
1020
1021 #[inline]
1023 pub const fn watch_balance(&self) -> bool {
1024 self.inner.contains(Capabilities::WATCH_BALANCE)
1025 }
1026
1027 #[inline]
1029 pub const fn watch_orders(&self) -> bool {
1030 self.inner.contains(Capabilities::WATCH_ORDERS)
1031 }
1032
1033 #[inline]
1035 pub const fn watch_my_trades(&self) -> bool {
1036 self.inner.contains(Capabilities::WATCH_MY_TRADES)
1037 }
1038
1039 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#[derive(Debug, Clone, Default)]
1094pub struct ExchangeCapabilitiesBuilder {
1095 inner: Capabilities,
1096}
1097
1098impl ExchangeCapabilitiesBuilder {
1099 pub fn new() -> Self {
1101 Self {
1102 inner: Capabilities::empty(),
1103 }
1104 }
1105
1106 pub fn market_data(mut self) -> Self {
1108 self.inner |= Capabilities::MARKET_DATA;
1109 self
1110 }
1111
1112 pub fn trading(mut self) -> Self {
1114 self.inner |= Capabilities::TRADING;
1115 self
1116 }
1117
1118 pub fn account(mut self) -> Self {
1120 self.inner |= Capabilities::ACCOUNT;
1121 self
1122 }
1123
1124 pub fn funding(mut self) -> Self {
1126 self.inner |= Capabilities::FUNDING;
1127 self
1128 }
1129
1130 pub fn margin(mut self) -> Self {
1132 self.inner |= Capabilities::MARGIN;
1133 self
1134 }
1135
1136 pub fn websocket_all(mut self) -> Self {
1138 self.inner |= Capabilities::WEBSOCKET_ALL;
1139 self
1140 }
1141
1142 pub fn websocket(mut self) -> Self {
1144 self.inner |= Capabilities::WEBSOCKET;
1145 self
1146 }
1147
1148 pub fn rest_all(mut self) -> Self {
1150 self.inner |= Capabilities::REST_ALL;
1151 self
1152 }
1153
1154 pub fn all(mut self) -> Self {
1156 self.inner = Capabilities::ALL;
1157 self
1158 }
1159
1160 pub fn capability(mut self, cap: Capability) -> Self {
1162 self.inner |= Capabilities::from(cap);
1163 self
1164 }
1165
1166 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 pub fn raw(mut self, caps: Capabilities) -> Self {
1176 self.inner |= caps;
1177 self
1178 }
1179
1180 pub fn without_capability(mut self, cap: Capability) -> Self {
1182 self.inner.remove(Capabilities::from(cap));
1183 self
1184 }
1185
1186 pub fn without(mut self, caps: Capabilities) -> Self {
1188 self.inner.remove(caps);
1189 self
1190 }
1191
1192 pub fn build(self) -> ExchangeCapabilities {
1194 ExchangeCapabilities { inner: self.inner }
1195 }
1196}
1197
1198impl ExchangeCapabilities {
1203 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 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 pub const fn full_featured() -> Self {
1239 Self {
1240 inner: Capabilities::ALL,
1241 }
1242 }
1243}
1244
1245#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1281pub enum TraitCategory {
1282 PublicExchange,
1285 MarketData,
1288 Trading,
1291 Account,
1294 Margin,
1297 Funding,
1300 WebSocket,
1303}
1304
1305impl TraitCategory {
1306 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 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 pub const fn capabilities(&self) -> Capabilities {
1334 match self {
1335 Self::PublicExchange => Capabilities::empty(), 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 pub const fn minimum_capabilities(&self) -> Capabilities {
1350 match self {
1351 Self::PublicExchange => Capabilities::empty(),
1352 Self::MarketData => Capabilities::from_bits_truncate(
1354 Capabilities::FETCH_MARKETS.bits() | Capabilities::FETCH_TICKER.bits(),
1355 ),
1356 Self::Trading => Capabilities::from_bits_truncate(
1358 Capabilities::CREATE_ORDER.bits() | Capabilities::CANCEL_ORDER.bits(),
1359 ),
1360 Self::Account => Capabilities::FETCH_BALANCE,
1362 Self::Margin => Capabilities::FETCH_POSITIONS,
1364 Self::Funding => Capabilities::FETCH_DEPOSIT_ADDRESS,
1366 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 pub const fn trait_category(&self) -> TraitCategory {
1391 match self {
1392 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 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 Self::FetchBalance
1418 | Self::FetchMyTrades
1419 | Self::FetchDeposits
1420 | Self::FetchWithdrawals
1421 | Self::FetchTransactions
1422 | Self::FetchLedger => TraitCategory::Account,
1423
1424 Self::FetchDepositAddress
1426 | Self::CreateDepositAddress
1427 | Self::Withdraw
1428 | Self::Transfer => TraitCategory::Funding,
1429
1430 Self::FetchBorrowRate
1432 | Self::FetchBorrowRates
1433 | Self::FetchFundingRate
1434 | Self::FetchFundingRates
1435 | Self::FetchPositions
1436 | Self::SetLeverage
1437 | Self::SetMarginMode => TraitCategory::Margin,
1438
1439 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 #[inline]
1475 pub const fn supports_market_data(&self) -> bool {
1476 self.inner
1477 .contains(TraitCategory::MarketData.minimum_capabilities())
1478 }
1479
1480 #[inline]
1497 pub const fn supports_trading(&self) -> bool {
1498 self.inner
1499 .contains(TraitCategory::Trading.minimum_capabilities())
1500 }
1501
1502 #[inline]
1519 pub const fn supports_account(&self) -> bool {
1520 self.inner
1521 .contains(TraitCategory::Account.minimum_capabilities())
1522 }
1523
1524 #[inline]
1541 pub const fn supports_margin(&self) -> bool {
1542 self.inner
1543 .contains(TraitCategory::Margin.minimum_capabilities())
1544 }
1545
1546 #[inline]
1563 pub const fn supports_funding(&self) -> bool {
1564 self.inner
1565 .contains(TraitCategory::Funding.minimum_capabilities())
1566 }
1567
1568 #[inline]
1584 pub const fn supports_websocket(&self) -> bool {
1585 self.inner
1586 .contains(TraitCategory::WebSocket.minimum_capabilities())
1587 }
1588
1589 #[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 pub const fn supports_trait(&self, category: TraitCategory) -> bool {
1630 match category {
1631 TraitCategory::PublicExchange => true, 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 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 pub const fn capabilities_for_trait(&self, category: TraitCategory) -> Capabilities {
1683 Capabilities::from_bits_truncate(self.inner.bits() & category.capabilities().bits())
1684 }
1685
1686 pub const fn trait_for_capability(capability: Capability) -> TraitCategory {
1701 capability.trait_category()
1702 }
1703}
1704
1705#[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 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 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()); 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 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 assert_eq!(std::mem::size_of::<ExchangeCapabilities>(), 8);
1897 assert_eq!(std::mem::size_of::<Capabilities>(), 8);
1898 }
1899
1900 #[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 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 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 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 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 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 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 let caps = ExchangeCapabilities::builder()
2037 .capability(Capability::FetchMarkets)
2038 .build();
2039 assert!(!caps.supports_market_data());
2040
2041 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 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()); let caps = ExchangeCapabilities::futures_exchange();
2130 assert!(!caps.supports_full_exchange()); }
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); }
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}