ccxt_core/capability/
exchange_caps.rs1use std::fmt;
4
5use super::{Capabilities, Capability};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
27pub struct ExchangeCapabilities {
28 inner: Capabilities,
29}
30
31impl ExchangeCapabilities {
32 pub const fn none() -> Self {
34 Self {
35 inner: Capabilities::empty(),
36 }
37 }
38
39 pub const fn all() -> Self {
41 Self {
42 inner: Capabilities::ALL,
43 }
44 }
45
46 pub const fn public_only() -> Self {
48 Self {
49 inner: Capabilities::PUBLIC_ONLY,
50 }
51 }
52
53 pub const fn from_capabilities(caps: Capabilities) -> Self {
55 Self { inner: caps }
56 }
57
58 pub const fn as_capabilities(&self) -> Capabilities {
60 self.inner
61 }
62
63 pub fn has(&self, capability: &str) -> bool {
65 self.inner.has(capability)
66 }
67
68 pub fn supported_capabilities(&self) -> Vec<&'static str> {
70 self.inner.supported_capabilities()
71 }
72
73 #[inline]
75 pub fn count(&self) -> u32 {
76 self.inner.count()
77 }
78
79 #[inline]
82 pub const fn fetch_markets(&self) -> bool {
83 self.inner.contains(Capabilities::FETCH_MARKETS)
84 }
85
86 #[inline]
87 pub const fn fetch_currencies(&self) -> bool {
88 self.inner.contains(Capabilities::FETCH_CURRENCIES)
89 }
90
91 #[inline]
92 pub const fn fetch_ticker(&self) -> bool {
93 self.inner.contains(Capabilities::FETCH_TICKER)
94 }
95
96 #[inline]
97 pub const fn fetch_tickers(&self) -> bool {
98 self.inner.contains(Capabilities::FETCH_TICKERS)
99 }
100
101 #[inline]
102 pub const fn fetch_order_book(&self) -> bool {
103 self.inner.contains(Capabilities::FETCH_ORDER_BOOK)
104 }
105
106 #[inline]
107 pub const fn fetch_trades(&self) -> bool {
108 self.inner.contains(Capabilities::FETCH_TRADES)
109 }
110
111 #[inline]
112 pub const fn fetch_ohlcv(&self) -> bool {
113 self.inner.contains(Capabilities::FETCH_OHLCV)
114 }
115
116 #[inline]
117 pub const fn fetch_status(&self) -> bool {
118 self.inner.contains(Capabilities::FETCH_STATUS)
119 }
120
121 #[inline]
122 pub const fn fetch_time(&self) -> bool {
123 self.inner.contains(Capabilities::FETCH_TIME)
124 }
125
126 #[inline]
129 pub const fn create_order(&self) -> bool {
130 self.inner.contains(Capabilities::CREATE_ORDER)
131 }
132
133 #[inline]
134 pub const fn create_market_order(&self) -> bool {
135 self.inner.contains(Capabilities::CREATE_MARKET_ORDER)
136 }
137
138 #[inline]
139 pub const fn create_limit_order(&self) -> bool {
140 self.inner.contains(Capabilities::CREATE_LIMIT_ORDER)
141 }
142
143 #[inline]
144 pub const fn cancel_order(&self) -> bool {
145 self.inner.contains(Capabilities::CANCEL_ORDER)
146 }
147
148 #[inline]
149 pub const fn cancel_all_orders(&self) -> bool {
150 self.inner.contains(Capabilities::CANCEL_ALL_ORDERS)
151 }
152
153 #[inline]
154 pub const fn edit_order(&self) -> bool {
155 self.inner.contains(Capabilities::EDIT_ORDER)
156 }
157
158 #[inline]
159 pub const fn fetch_order(&self) -> bool {
160 self.inner.contains(Capabilities::FETCH_ORDER)
161 }
162
163 #[inline]
164 pub const fn fetch_orders(&self) -> bool {
165 self.inner.contains(Capabilities::FETCH_ORDERS)
166 }
167
168 #[inline]
169 pub const fn fetch_open_orders(&self) -> bool {
170 self.inner.contains(Capabilities::FETCH_OPEN_ORDERS)
171 }
172
173 #[inline]
174 pub const fn fetch_closed_orders(&self) -> bool {
175 self.inner.contains(Capabilities::FETCH_CLOSED_ORDERS)
176 }
177
178 #[inline]
179 pub const fn fetch_canceled_orders(&self) -> bool {
180 self.inner.contains(Capabilities::FETCH_CANCELED_ORDERS)
181 }
182
183 #[inline]
186 pub const fn fetch_balance(&self) -> bool {
187 self.inner.contains(Capabilities::FETCH_BALANCE)
188 }
189
190 #[inline]
191 pub const fn fetch_my_trades(&self) -> bool {
192 self.inner.contains(Capabilities::FETCH_MY_TRADES)
193 }
194
195 #[inline]
196 pub const fn fetch_deposits(&self) -> bool {
197 self.inner.contains(Capabilities::FETCH_DEPOSITS)
198 }
199
200 #[inline]
201 pub const fn fetch_withdrawals(&self) -> bool {
202 self.inner.contains(Capabilities::FETCH_WITHDRAWALS)
203 }
204
205 #[inline]
206 pub const fn fetch_transactions(&self) -> bool {
207 self.inner.contains(Capabilities::FETCH_TRANSACTIONS)
208 }
209
210 #[inline]
211 pub const fn fetch_ledger(&self) -> bool {
212 self.inner.contains(Capabilities::FETCH_LEDGER)
213 }
214
215 #[inline]
218 pub const fn fetch_deposit_address(&self) -> bool {
219 self.inner.contains(Capabilities::FETCH_DEPOSIT_ADDRESS)
220 }
221
222 #[inline]
223 pub const fn create_deposit_address(&self) -> bool {
224 self.inner.contains(Capabilities::CREATE_DEPOSIT_ADDRESS)
225 }
226
227 #[inline]
228 pub const fn withdraw(&self) -> bool {
229 self.inner.contains(Capabilities::WITHDRAW)
230 }
231
232 #[inline]
233 pub const fn transfer(&self) -> bool {
234 self.inner.contains(Capabilities::TRANSFER)
235 }
236
237 #[inline]
240 pub const fn fetch_borrow_rate(&self) -> bool {
241 self.inner.contains(Capabilities::FETCH_BORROW_RATE)
242 }
243
244 #[inline]
245 pub const fn fetch_borrow_rates(&self) -> bool {
246 self.inner.contains(Capabilities::FETCH_BORROW_RATES)
247 }
248
249 #[inline]
250 pub const fn fetch_funding_rate(&self) -> bool {
251 self.inner.contains(Capabilities::FETCH_FUNDING_RATE)
252 }
253
254 #[inline]
255 pub const fn fetch_funding_rates(&self) -> bool {
256 self.inner.contains(Capabilities::FETCH_FUNDING_RATES)
257 }
258
259 #[inline]
260 pub const fn fetch_positions(&self) -> bool {
261 self.inner.contains(Capabilities::FETCH_POSITIONS)
262 }
263
264 #[inline]
265 pub const fn set_leverage(&self) -> bool {
266 self.inner.contains(Capabilities::SET_LEVERAGE)
267 }
268
269 #[inline]
270 pub const fn set_margin_mode(&self) -> bool {
271 self.inner.contains(Capabilities::SET_MARGIN_MODE)
272 }
273
274 #[inline]
277 pub const fn websocket(&self) -> bool {
278 self.inner.contains(Capabilities::WEBSOCKET)
279 }
280
281 #[inline]
282 pub const fn watch_ticker(&self) -> bool {
283 self.inner.contains(Capabilities::WATCH_TICKER)
284 }
285
286 #[inline]
287 pub const fn watch_tickers(&self) -> bool {
288 self.inner.contains(Capabilities::WATCH_TICKERS)
289 }
290
291 #[inline]
292 pub const fn watch_order_book(&self) -> bool {
293 self.inner.contains(Capabilities::WATCH_ORDER_BOOK)
294 }
295
296 #[inline]
297 pub const fn watch_trades(&self) -> bool {
298 self.inner.contains(Capabilities::WATCH_TRADES)
299 }
300
301 #[inline]
302 pub const fn watch_ohlcv(&self) -> bool {
303 self.inner.contains(Capabilities::WATCH_OHLCV)
304 }
305
306 #[inline]
307 pub const fn watch_balance(&self) -> bool {
308 self.inner.contains(Capabilities::WATCH_BALANCE)
309 }
310
311 #[inline]
312 pub const fn watch_orders(&self) -> bool {
313 self.inner.contains(Capabilities::WATCH_ORDERS)
314 }
315
316 #[inline]
317 pub const fn watch_my_trades(&self) -> bool {
318 self.inner.contains(Capabilities::WATCH_MY_TRADES)
319 }
320
321 pub fn builder() -> ExchangeCapabilitiesBuilder {
325 ExchangeCapabilitiesBuilder::new()
326 }
327
328 pub const fn spot_exchange() -> Self {
332 Self {
333 inner: Capabilities::from_bits_truncate(
334 Capabilities::MARKET_DATA.bits()
335 | Capabilities::TRADING.bits()
336 | Capabilities::ACCOUNT.bits()
337 | Capabilities::WEBSOCKET.bits()
338 | Capabilities::WATCH_TICKER.bits()
339 | Capabilities::WATCH_ORDER_BOOK.bits()
340 | Capabilities::WATCH_TRADES.bits(),
341 ),
342 }
343 }
344
345 pub const fn futures_exchange() -> Self {
347 Self {
348 inner: Capabilities::from_bits_truncate(
349 Capabilities::MARKET_DATA.bits()
350 | Capabilities::TRADING.bits()
351 | Capabilities::ACCOUNT.bits()
352 | Capabilities::MARGIN.bits()
353 | Capabilities::WEBSOCKET_ALL.bits(),
354 ),
355 }
356 }
357
358 pub const fn full_featured() -> Self {
360 Self {
361 inner: Capabilities::ALL,
362 }
363 }
364
365 #[inline]
368 pub const fn supports_market_data(&self) -> bool {
369 self.inner
370 .contains(TraitCategory::MarketData.minimum_capabilities())
371 }
372
373 #[inline]
374 pub const fn supports_trading(&self) -> bool {
375 self.inner
376 .contains(TraitCategory::Trading.minimum_capabilities())
377 }
378
379 #[inline]
380 pub const fn supports_account(&self) -> bool {
381 self.inner
382 .contains(TraitCategory::Account.minimum_capabilities())
383 }
384
385 #[inline]
386 pub const fn supports_margin(&self) -> bool {
387 self.inner
388 .contains(TraitCategory::Margin.minimum_capabilities())
389 }
390
391 #[inline]
392 pub const fn supports_funding(&self) -> bool {
393 self.inner
394 .contains(TraitCategory::Funding.minimum_capabilities())
395 }
396
397 #[inline]
398 pub const fn supports_websocket(&self) -> bool {
399 self.inner
400 .contains(TraitCategory::WebSocket.minimum_capabilities())
401 }
402
403 #[inline]
404 pub const fn supports_full_exchange(&self) -> bool {
405 self.supports_market_data()
406 && self.supports_trading()
407 && self.supports_account()
408 && self.supports_margin()
409 && self.supports_funding()
410 }
411
412 pub const fn supports_trait(&self, category: TraitCategory) -> bool {
413 match category {
414 TraitCategory::PublicExchange => true,
415 TraitCategory::MarketData => self.supports_market_data(),
416 TraitCategory::Trading => self.supports_trading(),
417 TraitCategory::Account => self.supports_account(),
418 TraitCategory::Margin => self.supports_margin(),
419 TraitCategory::Funding => self.supports_funding(),
420 TraitCategory::WebSocket => self.supports_websocket(),
421 }
422 }
423
424 pub fn supported_traits(&self) -> Vec<TraitCategory> {
425 TraitCategory::all()
426 .iter()
427 .filter(|cat| self.supports_trait(**cat))
428 .copied()
429 .collect()
430 }
431
432 pub const fn capabilities_for_trait(&self, category: TraitCategory) -> Capabilities {
433 Capabilities::from_bits_truncate(self.inner.bits() & category.capabilities().bits())
434 }
435
436 pub const fn trait_for_capability(capability: Capability) -> TraitCategory {
437 capability.trait_category()
438 }
439}
440
441impl From<Capabilities> for ExchangeCapabilities {
442 fn from(caps: Capabilities) -> Self {
443 Self::from_capabilities(caps)
444 }
445}
446
447impl fmt::Display for ExchangeCapabilities {
448 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
449 write!(f, "ExchangeCapabilities({})", self.inner)
450 }
451}
452
453#[derive(Debug, Clone, Default)]
455pub struct ExchangeCapabilitiesBuilder {
456 inner: Capabilities,
457}
458
459impl ExchangeCapabilitiesBuilder {
460 pub fn new() -> Self {
461 Self {
462 inner: Capabilities::empty(),
463 }
464 }
465
466 pub fn market_data(mut self) -> Self {
467 self.inner |= Capabilities::MARKET_DATA;
468 self
469 }
470
471 pub fn trading(mut self) -> Self {
472 self.inner |= Capabilities::TRADING;
473 self
474 }
475
476 pub fn account(mut self) -> Self {
477 self.inner |= Capabilities::ACCOUNT;
478 self
479 }
480
481 pub fn funding(mut self) -> Self {
482 self.inner |= Capabilities::FUNDING;
483 self
484 }
485
486 pub fn margin(mut self) -> Self {
487 self.inner |= Capabilities::MARGIN;
488 self
489 }
490
491 pub fn websocket_all(mut self) -> Self {
492 self.inner |= Capabilities::WEBSOCKET_ALL;
493 self
494 }
495
496 pub fn websocket(mut self) -> Self {
497 self.inner |= Capabilities::WEBSOCKET;
498 self
499 }
500
501 pub fn rest_all(mut self) -> Self {
502 self.inner |= Capabilities::REST_ALL;
503 self
504 }
505
506 pub fn all(mut self) -> Self {
507 self.inner = Capabilities::ALL;
508 self
509 }
510
511 pub fn capability(mut self, cap: Capability) -> Self {
512 self.inner |= Capabilities::from(cap);
513 self
514 }
515
516 pub fn capabilities<I: IntoIterator<Item = Capability>>(mut self, caps: I) -> Self {
517 for cap in caps {
518 self.inner |= Capabilities::from(cap);
519 }
520 self
521 }
522
523 pub fn raw(mut self, caps: Capabilities) -> Self {
524 self.inner |= caps;
525 self
526 }
527
528 pub fn without_capability(mut self, cap: Capability) -> Self {
529 self.inner.remove(Capabilities::from(cap));
530 self
531 }
532
533 pub fn without(mut self, caps: Capabilities) -> Self {
534 self.inner.remove(caps);
535 self
536 }
537
538 pub fn build(self) -> ExchangeCapabilities {
539 ExchangeCapabilities { inner: self.inner }
540 }
541}
542
543#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
545pub enum TraitCategory {
546 PublicExchange,
547 MarketData,
548 Trading,
549 Account,
550 Margin,
551 Funding,
552 WebSocket,
553}
554
555impl TraitCategory {
556 pub const fn all() -> [Self; 7] {
557 [
558 Self::PublicExchange,
559 Self::MarketData,
560 Self::Trading,
561 Self::Account,
562 Self::Margin,
563 Self::Funding,
564 Self::WebSocket,
565 ]
566 }
567
568 pub const fn name(&self) -> &'static str {
569 match self {
570 Self::PublicExchange => "PublicExchange",
571 Self::MarketData => "MarketData",
572 Self::Trading => "Trading",
573 Self::Account => "Account",
574 Self::Margin => "Margin",
575 Self::Funding => "Funding",
576 Self::WebSocket => "WebSocket",
577 }
578 }
579
580 pub const fn capabilities(&self) -> Capabilities {
581 match self {
582 Self::PublicExchange => Capabilities::empty(),
583 Self::MarketData => Capabilities::MARKET_DATA,
584 Self::Trading => Capabilities::TRADING,
585 Self::Account => Capabilities::ACCOUNT,
586 Self::Margin => Capabilities::MARGIN,
587 Self::Funding => Capabilities::FUNDING,
588 Self::WebSocket => Capabilities::WEBSOCKET_ALL,
589 }
590 }
591
592 pub const fn minimum_capabilities(&self) -> Capabilities {
593 match self {
594 Self::PublicExchange => Capabilities::empty(),
595 Self::MarketData => Capabilities::from_bits_truncate(
596 Capabilities::FETCH_MARKETS.bits() | Capabilities::FETCH_TICKER.bits(),
597 ),
598 Self::Trading => Capabilities::from_bits_truncate(
599 Capabilities::CREATE_ORDER.bits() | Capabilities::CANCEL_ORDER.bits(),
600 ),
601 Self::Account => Capabilities::FETCH_BALANCE,
602 Self::Margin => Capabilities::FETCH_POSITIONS,
603 Self::Funding => Capabilities::FETCH_DEPOSIT_ADDRESS,
604 Self::WebSocket => Capabilities::WEBSOCKET,
605 }
606 }
607}
608
609impl fmt::Display for TraitCategory {
610 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
611 write!(f, "{}", self.name())
612 }
613}