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(|cap| cap.as_ccxt_name())
566 .collect()
567 }
568
569 #[inline]
571 pub fn count(&self) -> u32 {
572 self.bits().count_ones()
573 }
574
575 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#[macro_export]
619macro_rules! capabilities {
620 ($cap:ident) => {
622 $crate::capability::Capabilities::$cap
623 };
624 ($cap:ident | $($rest:tt)+) => {
626 $crate::capability::Capabilities::$cap | capabilities!($($rest)+)
627 };
628 ($cap:ident, $($rest:tt)+) => {
630 $crate::capability::Capabilities::$cap | capabilities!($($rest)+)
631 };
632}
633
634#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
658pub struct ExchangeCapabilities {
659 inner: Capabilities,
660}
661
662impl ExchangeCapabilities {
663 pub const fn none() -> Self {
665 Self {
666 inner: Capabilities::empty(),
667 }
668 }
669
670 pub const fn all() -> Self {
683 Self {
684 inner: Capabilities::ALL,
685 }
686 }
687
688 pub const fn public_only() -> Self {
700 Self {
701 inner: Capabilities::PUBLIC_ONLY,
702 }
703 }
704
705 pub const fn from_capabilities(caps: Capabilities) -> Self {
707 Self { inner: caps }
708 }
709
710 pub const fn as_capabilities(&self) -> Capabilities {
712 self.inner
713 }
714
715 pub fn has(&self, capability: &str) -> bool {
734 self.inner.has(capability)
735 }
736
737 pub fn supported_capabilities(&self) -> Vec<&'static str> {
739 self.inner.supported_capabilities()
740 }
741
742 #[inline]
744 pub fn count(&self) -> u32 {
745 self.inner.count()
746 }
747
748 #[inline]
752 pub const fn fetch_markets(&self) -> bool {
753 self.inner.contains(Capabilities::FETCH_MARKETS)
754 }
755
756 #[inline]
758 pub const fn fetch_currencies(&self) -> bool {
759 self.inner.contains(Capabilities::FETCH_CURRENCIES)
760 }
761
762 #[inline]
764 pub const fn fetch_ticker(&self) -> bool {
765 self.inner.contains(Capabilities::FETCH_TICKER)
766 }
767
768 #[inline]
770 pub const fn fetch_tickers(&self) -> bool {
771 self.inner.contains(Capabilities::FETCH_TICKERS)
772 }
773
774 #[inline]
776 pub const fn fetch_order_book(&self) -> bool {
777 self.inner.contains(Capabilities::FETCH_ORDER_BOOK)
778 }
779
780 #[inline]
782 pub const fn fetch_trades(&self) -> bool {
783 self.inner.contains(Capabilities::FETCH_TRADES)
784 }
785
786 #[inline]
788 pub const fn fetch_ohlcv(&self) -> bool {
789 self.inner.contains(Capabilities::FETCH_OHLCV)
790 }
791
792 #[inline]
794 pub const fn fetch_status(&self) -> bool {
795 self.inner.contains(Capabilities::FETCH_STATUS)
796 }
797
798 #[inline]
800 pub const fn fetch_time(&self) -> bool {
801 self.inner.contains(Capabilities::FETCH_TIME)
802 }
803
804 #[inline]
808 pub const fn create_order(&self) -> bool {
809 self.inner.contains(Capabilities::CREATE_ORDER)
810 }
811
812 #[inline]
814 pub const fn create_market_order(&self) -> bool {
815 self.inner.contains(Capabilities::CREATE_MARKET_ORDER)
816 }
817
818 #[inline]
820 pub const fn create_limit_order(&self) -> bool {
821 self.inner.contains(Capabilities::CREATE_LIMIT_ORDER)
822 }
823
824 #[inline]
826 pub const fn cancel_order(&self) -> bool {
827 self.inner.contains(Capabilities::CANCEL_ORDER)
828 }
829
830 #[inline]
832 pub const fn cancel_all_orders(&self) -> bool {
833 self.inner.contains(Capabilities::CANCEL_ALL_ORDERS)
834 }
835
836 #[inline]
838 pub const fn edit_order(&self) -> bool {
839 self.inner.contains(Capabilities::EDIT_ORDER)
840 }
841
842 #[inline]
844 pub const fn fetch_order(&self) -> bool {
845 self.inner.contains(Capabilities::FETCH_ORDER)
846 }
847
848 #[inline]
850 pub const fn fetch_orders(&self) -> bool {
851 self.inner.contains(Capabilities::FETCH_ORDERS)
852 }
853
854 #[inline]
856 pub const fn fetch_open_orders(&self) -> bool {
857 self.inner.contains(Capabilities::FETCH_OPEN_ORDERS)
858 }
859
860 #[inline]
862 pub const fn fetch_closed_orders(&self) -> bool {
863 self.inner.contains(Capabilities::FETCH_CLOSED_ORDERS)
864 }
865
866 #[inline]
868 pub const fn fetch_canceled_orders(&self) -> bool {
869 self.inner.contains(Capabilities::FETCH_CANCELED_ORDERS)
870 }
871
872 #[inline]
876 pub const fn fetch_balance(&self) -> bool {
877 self.inner.contains(Capabilities::FETCH_BALANCE)
878 }
879
880 #[inline]
882 pub const fn fetch_my_trades(&self) -> bool {
883 self.inner.contains(Capabilities::FETCH_MY_TRADES)
884 }
885
886 #[inline]
888 pub const fn fetch_deposits(&self) -> bool {
889 self.inner.contains(Capabilities::FETCH_DEPOSITS)
890 }
891
892 #[inline]
894 pub const fn fetch_withdrawals(&self) -> bool {
895 self.inner.contains(Capabilities::FETCH_WITHDRAWALS)
896 }
897
898 #[inline]
900 pub const fn fetch_transactions(&self) -> bool {
901 self.inner.contains(Capabilities::FETCH_TRANSACTIONS)
902 }
903
904 #[inline]
906 pub const fn fetch_ledger(&self) -> bool {
907 self.inner.contains(Capabilities::FETCH_LEDGER)
908 }
909
910 #[inline]
914 pub const fn fetch_deposit_address(&self) -> bool {
915 self.inner.contains(Capabilities::FETCH_DEPOSIT_ADDRESS)
916 }
917
918 #[inline]
920 pub const fn create_deposit_address(&self) -> bool {
921 self.inner.contains(Capabilities::CREATE_DEPOSIT_ADDRESS)
922 }
923
924 #[inline]
926 pub const fn withdraw(&self) -> bool {
927 self.inner.contains(Capabilities::WITHDRAW)
928 }
929
930 #[inline]
932 pub const fn transfer(&self) -> bool {
933 self.inner.contains(Capabilities::TRANSFER)
934 }
935
936 #[inline]
940 pub const fn fetch_borrow_rate(&self) -> bool {
941 self.inner.contains(Capabilities::FETCH_BORROW_RATE)
942 }
943
944 #[inline]
946 pub const fn fetch_borrow_rates(&self) -> bool {
947 self.inner.contains(Capabilities::FETCH_BORROW_RATES)
948 }
949
950 #[inline]
952 pub const fn fetch_funding_rate(&self) -> bool {
953 self.inner.contains(Capabilities::FETCH_FUNDING_RATE)
954 }
955
956 #[inline]
958 pub const fn fetch_funding_rates(&self) -> bool {
959 self.inner.contains(Capabilities::FETCH_FUNDING_RATES)
960 }
961
962 #[inline]
964 pub const fn fetch_positions(&self) -> bool {
965 self.inner.contains(Capabilities::FETCH_POSITIONS)
966 }
967
968 #[inline]
970 pub const fn set_leverage(&self) -> bool {
971 self.inner.contains(Capabilities::SET_LEVERAGE)
972 }
973
974 #[inline]
976 pub const fn set_margin_mode(&self) -> bool {
977 self.inner.contains(Capabilities::SET_MARGIN_MODE)
978 }
979
980 #[inline]
984 pub const fn websocket(&self) -> bool {
985 self.inner.contains(Capabilities::WEBSOCKET)
986 }
987
988 #[inline]
990 pub const fn watch_ticker(&self) -> bool {
991 self.inner.contains(Capabilities::WATCH_TICKER)
992 }
993
994 #[inline]
996 pub const fn watch_tickers(&self) -> bool {
997 self.inner.contains(Capabilities::WATCH_TICKERS)
998 }
999
1000 #[inline]
1002 pub const fn watch_order_book(&self) -> bool {
1003 self.inner.contains(Capabilities::WATCH_ORDER_BOOK)
1004 }
1005
1006 #[inline]
1008 pub const fn watch_trades(&self) -> bool {
1009 self.inner.contains(Capabilities::WATCH_TRADES)
1010 }
1011
1012 #[inline]
1014 pub const fn watch_ohlcv(&self) -> bool {
1015 self.inner.contains(Capabilities::WATCH_OHLCV)
1016 }
1017
1018 #[inline]
1020 pub const fn watch_balance(&self) -> bool {
1021 self.inner.contains(Capabilities::WATCH_BALANCE)
1022 }
1023
1024 #[inline]
1026 pub const fn watch_orders(&self) -> bool {
1027 self.inner.contains(Capabilities::WATCH_ORDERS)
1028 }
1029
1030 #[inline]
1032 pub const fn watch_my_trades(&self) -> bool {
1033 self.inner.contains(Capabilities::WATCH_MY_TRADES)
1034 }
1035
1036 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#[derive(Debug, Clone, Default)]
1091pub struct ExchangeCapabilitiesBuilder {
1092 inner: Capabilities,
1093}
1094
1095impl ExchangeCapabilitiesBuilder {
1096 pub fn new() -> Self {
1098 Self {
1099 inner: Capabilities::empty(),
1100 }
1101 }
1102
1103 pub fn market_data(mut self) -> Self {
1105 self.inner |= Capabilities::MARKET_DATA;
1106 self
1107 }
1108
1109 pub fn trading(mut self) -> Self {
1111 self.inner |= Capabilities::TRADING;
1112 self
1113 }
1114
1115 pub fn account(mut self) -> Self {
1117 self.inner |= Capabilities::ACCOUNT;
1118 self
1119 }
1120
1121 pub fn funding(mut self) -> Self {
1123 self.inner |= Capabilities::FUNDING;
1124 self
1125 }
1126
1127 pub fn margin(mut self) -> Self {
1129 self.inner |= Capabilities::MARGIN;
1130 self
1131 }
1132
1133 pub fn websocket_all(mut self) -> Self {
1135 self.inner |= Capabilities::WEBSOCKET_ALL;
1136 self
1137 }
1138
1139 pub fn websocket(mut self) -> Self {
1141 self.inner |= Capabilities::WEBSOCKET;
1142 self
1143 }
1144
1145 pub fn rest_all(mut self) -> Self {
1147 self.inner |= Capabilities::REST_ALL;
1148 self
1149 }
1150
1151 pub fn all(mut self) -> Self {
1153 self.inner = Capabilities::ALL;
1154 self
1155 }
1156
1157 pub fn capability(mut self, cap: Capability) -> Self {
1159 self.inner |= Capabilities::from(cap);
1160 self
1161 }
1162
1163 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 pub fn raw(mut self, caps: Capabilities) -> Self {
1173 self.inner |= caps;
1174 self
1175 }
1176
1177 pub fn without_capability(mut self, cap: Capability) -> Self {
1179 self.inner.remove(Capabilities::from(cap));
1180 self
1181 }
1182
1183 pub fn without(mut self, caps: Capabilities) -> Self {
1185 self.inner.remove(caps);
1186 self
1187 }
1188
1189 pub fn build(self) -> ExchangeCapabilities {
1191 ExchangeCapabilities { inner: self.inner }
1192 }
1193}
1194
1195impl ExchangeCapabilities {
1200 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 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 pub const fn full_featured() -> Self {
1236 Self {
1237 inner: Capabilities::ALL,
1238 }
1239 }
1240}
1241
1242#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1278pub enum TraitCategory {
1279 PublicExchange,
1282 MarketData,
1285 Trading,
1288 Account,
1291 Margin,
1294 Funding,
1297 WebSocket,
1300}
1301
1302impl TraitCategory {
1303 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 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 pub const fn capabilities(&self) -> Capabilities {
1331 match self {
1332 Self::PublicExchange => Capabilities::empty(), 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 pub const fn minimum_capabilities(&self) -> Capabilities {
1347 match self {
1348 Self::PublicExchange => Capabilities::empty(),
1349 Self::MarketData => Capabilities::from_bits_truncate(
1351 Capabilities::FETCH_MARKETS.bits() | Capabilities::FETCH_TICKER.bits(),
1352 ),
1353 Self::Trading => Capabilities::from_bits_truncate(
1355 Capabilities::CREATE_ORDER.bits() | Capabilities::CANCEL_ORDER.bits(),
1356 ),
1357 Self::Account => Capabilities::FETCH_BALANCE,
1359 Self::Margin => Capabilities::FETCH_POSITIONS,
1361 Self::Funding => Capabilities::FETCH_DEPOSIT_ADDRESS,
1363 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 pub const fn trait_category(&self) -> TraitCategory {
1388 match self {
1389 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 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 Self::FetchBalance
1415 | Self::FetchMyTrades
1416 | Self::FetchDeposits
1417 | Self::FetchWithdrawals
1418 | Self::FetchTransactions
1419 | Self::FetchLedger => TraitCategory::Account,
1420
1421 Self::FetchDepositAddress
1423 | Self::CreateDepositAddress
1424 | Self::Withdraw
1425 | Self::Transfer => TraitCategory::Funding,
1426
1427 Self::FetchBorrowRate
1429 | Self::FetchBorrowRates
1430 | Self::FetchFundingRate
1431 | Self::FetchFundingRates
1432 | Self::FetchPositions
1433 | Self::SetLeverage
1434 | Self::SetMarginMode => TraitCategory::Margin,
1435
1436 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 #[inline]
1472 pub const fn supports_market_data(&self) -> bool {
1473 self.inner
1474 .contains(TraitCategory::MarketData.minimum_capabilities())
1475 }
1476
1477 #[inline]
1494 pub const fn supports_trading(&self) -> bool {
1495 self.inner
1496 .contains(TraitCategory::Trading.minimum_capabilities())
1497 }
1498
1499 #[inline]
1516 pub const fn supports_account(&self) -> bool {
1517 self.inner
1518 .contains(TraitCategory::Account.minimum_capabilities())
1519 }
1520
1521 #[inline]
1538 pub const fn supports_margin(&self) -> bool {
1539 self.inner
1540 .contains(TraitCategory::Margin.minimum_capabilities())
1541 }
1542
1543 #[inline]
1560 pub const fn supports_funding(&self) -> bool {
1561 self.inner
1562 .contains(TraitCategory::Funding.minimum_capabilities())
1563 }
1564
1565 #[inline]
1581 pub const fn supports_websocket(&self) -> bool {
1582 self.inner
1583 .contains(TraitCategory::WebSocket.minimum_capabilities())
1584 }
1585
1586 #[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 pub const fn supports_trait(&self, category: TraitCategory) -> bool {
1627 match category {
1628 TraitCategory::PublicExchange => true, 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 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 pub const fn capabilities_for_trait(&self, category: TraitCategory) -> Capabilities {
1680 Capabilities::from_bits_truncate(self.inner.bits() & category.capabilities().bits())
1681 }
1682
1683 pub const fn trait_for_capability(capability: Capability) -> TraitCategory {
1698 capability.trait_category()
1699 }
1700}
1701
1702#[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 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 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()); 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 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 assert_eq!(std::mem::size_of::<ExchangeCapabilities>(), 8);
1894 assert_eq!(std::mem::size_of::<Capabilities>(), 8);
1895 }
1896
1897 #[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 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 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 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 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 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 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 let caps = ExchangeCapabilities::builder()
2034 .capability(Capability::FetchMarkets)
2035 .build();
2036 assert!(!caps.supports_market_data());
2037
2038 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 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()); let caps = ExchangeCapabilities::futures_exchange();
2127 assert!(!caps.supports_full_exchange()); }
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); }
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}