nautilus_tardis/
enums.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use nautilus_model::identifiers::Venue;
17use serde::{Deserialize, Serialize};
18use strum::{AsRefStr, Display, EnumIter, EnumString, FromRepr};
19use ustr::Ustr;
20
21#[derive(
22    Copy,
23    Clone,
24    Debug,
25    PartialEq,
26    Eq,
27    Hash,
28    Serialize,
29    Deserialize,
30    Display,
31    AsRefStr,
32    EnumIter,
33    EnumString,
34    FromRepr,
35)]
36#[strum(ascii_case_insensitive)]
37#[strum(serialize_all = "lowercase")]
38#[serde(rename_all = "lowercase")]
39/// The instrument type for the symbol.
40pub enum TardisInstrumentType {
41    Spot,
42    Perpetual,
43    Future,
44    Option,
45    Combo,
46}
47
48#[derive(
49    Copy,
50    Clone,
51    Debug,
52    PartialEq,
53    Eq,
54    Hash,
55    Serialize,
56    Deserialize,
57    Display,
58    AsRefStr,
59    EnumIter,
60    EnumString,
61    FromRepr,
62)]
63#[serde(rename_all = "lowercase")]
64/// The type of option.
65pub enum TardisOptionType {
66    Call,
67    Put,
68}
69
70/// The aggressor side of the trade.
71#[derive(
72    Copy,
73    Clone,
74    Debug,
75    PartialEq,
76    Eq,
77    Hash,
78    Serialize,
79    Deserialize,
80    Display,
81    AsRefStr,
82    EnumIter,
83    EnumString,
84    FromRepr,
85)]
86#[serde(rename_all = "lowercase")]
87pub enum TardisTradeSide {
88    Buy,
89    Sell,
90    Unknown,
91}
92
93/// The bar kind.
94#[allow(missing_docs)]
95#[derive(
96    Copy,
97    Clone,
98    Debug,
99    PartialEq,
100    Eq,
101    Hash,
102    Serialize,
103    Deserialize,
104    Display,
105    AsRefStr,
106    EnumIter,
107    EnumString,
108    FromRepr,
109)]
110#[serde(rename_all = "lowercase")]
111pub enum TardisBarKind {
112    Time,
113    Volume,
114    Tick,
115}
116
117#[derive(
118    Copy,
119    Clone,
120    Debug,
121    PartialEq,
122    Eq,
123    Hash,
124    Serialize,
125    Deserialize,
126    Display,
127    AsRefStr,
128    EnumIter,
129    EnumString,
130    FromRepr,
131)]
132#[strum(ascii_case_insensitive)]
133#[strum(serialize_all = "kebab-case")]
134#[serde(rename_all = "kebab-case")]
135/// Represents a crypto exchange.
136/// See <https://api.tardis.dev/v1/exchanges> for all supported exchanges.
137pub enum TardisExchange {
138    Ascendex,
139    Binance,
140    BinanceDelivery,
141    BinanceDex,
142    BinanceEuropeanOptions,
143    BinanceFutures,
144    BinanceJersey,
145    BinanceOptions,
146    BinanceUs,
147    Bitfinex,
148    BitfinexDerivatives,
149    Bitflyer,
150    Bitget,
151    BitgetFutures,
152    Bitmex,
153    Bitnomial,
154    Bitstamp,
155    BlockchainCom,
156    Bybit,
157    BybitOptions,
158    BybitSpot,
159    Coinbase,
160    CoinbaseInternational,
161    Coinflex,
162    CryptoCom,
163    CryptoComDerivatives,
164    Cryptofacilities,
165    Delta,
166    Deribit,
167    Dydx,
168    DydxV4,
169    Ftx,
170    FtxUs,
171    GateIo,
172    GateIoFutures,
173    Gemini,
174    Hitbtc,
175    Huobi,
176    HuobiDm,
177    HuobiDmLinearSwap,
178    HuobiDmOptions,
179    HuobiDmSwap,
180    Hyperliquid,
181    Kraken,
182    Kucoin,
183    KucoinFutures,
184    Mango,
185    Okcoin,
186    Okex,
187    OkexFutures,
188    OkexOptions,
189    OkexSpreads,
190    OkexSwap,
191    Phemex,
192    Poloniex,
193    Serum,
194    StarAtlas,
195    Upbit,
196    WooX,
197}
198
199impl TardisExchange {
200    #[must_use]
201    pub fn from_venue_str(s: &str) -> Vec<Self> {
202        let s = s.to_ascii_uppercase();
203        match s.as_str() {
204            "ASCENDEX" => vec![Self::Ascendex],
205            "BINANCE" => vec![
206                Self::Binance,
207                Self::BinanceDex,
208                Self::BinanceEuropeanOptions,
209                Self::BinanceFutures,
210                Self::BinanceJersey,
211                Self::BinanceOptions,
212            ],
213            "BINANCE_DELIVERY" => vec![Self::BinanceDelivery],
214            "BINANCE_US" => vec![Self::BinanceUs],
215            "BITFINEX" => vec![Self::Bitfinex, Self::BitfinexDerivatives],
216            "BITFLYER" => vec![Self::Bitflyer],
217            "BITGET" => vec![Self::Bitget, Self::BitgetFutures],
218            "BITMEX" => vec![Self::Bitmex],
219            "BITNOMIAL" => vec![Self::Bitnomial],
220            "BITSTAMP" => vec![Self::Bitstamp],
221            "BLOCKCHAIN_COM" => vec![Self::BlockchainCom],
222            "BYBIT" => vec![Self::Bybit, Self::BybitOptions, Self::BybitSpot],
223            "COINBASE" => vec![Self::Coinbase],
224            "COINBASE_INTX" => vec![Self::CoinbaseInternational],
225            "COINFLEX" => vec![Self::Coinflex],
226            "CRYPTO_COM" => vec![Self::CryptoCom, Self::CryptoComDerivatives],
227            "CRYPTOFACILITIES" => vec![Self::Cryptofacilities],
228            "DELTA" => vec![Self::Delta],
229            "DERIBIT" => vec![Self::Deribit],
230            "DYDX" => vec![Self::Dydx],
231            "DYDX_V4" => vec![Self::DydxV4],
232            "FTX" => vec![Self::Ftx, Self::FtxUs],
233            "GATE_IO" => vec![Self::GateIo, Self::GateIoFutures],
234            "GEMINI" => vec![Self::Gemini],
235            "HITBTC" => vec![Self::Hitbtc],
236            "HUOBI" => vec![
237                Self::Huobi,
238                Self::HuobiDm,
239                Self::HuobiDmLinearSwap,
240                Self::HuobiDmOptions,
241            ],
242            "HUOBI_DELIVERY" => vec![Self::HuobiDmSwap],
243            "HYPERLIQUID" => vec![Self::Hyperliquid],
244            "KRAKEN" => vec![Self::Kraken],
245            "KUCOIN" => vec![Self::Kucoin, Self::KucoinFutures],
246            "MANGO" => vec![Self::Mango],
247            "OKCOIN" => vec![Self::Okcoin],
248            "OKEX" => vec![
249                Self::Okex,
250                Self::OkexFutures,
251                Self::OkexOptions,
252                Self::OkexSpreads,
253                Self::OkexSwap,
254            ],
255            "PHEMEX" => vec![Self::Phemex],
256            "POLONIEX" => vec![Self::Poloniex],
257            "SERUM" => vec![Self::Serum],
258            "STAR_ATLAS" => vec![Self::StarAtlas],
259            "UPBIT" => vec![Self::Upbit],
260            "WOO_X" => vec![Self::WooX],
261            _ => Vec::new(),
262        }
263    }
264
265    #[must_use]
266    pub const fn as_venue_str(&self) -> &str {
267        match self {
268            Self::Ascendex => "ASCENDEX",
269            Self::Binance => "BINANCE",
270            Self::BinanceDelivery => "BINANCE_DELIVERY",
271            Self::BinanceDex => "BINANCE",
272            Self::BinanceEuropeanOptions => "BINANCE",
273            Self::BinanceFutures => "BINANCE",
274            Self::BinanceJersey => "BINANCE",
275            Self::BinanceOptions => "BINANCE",
276            Self::BinanceUs => "BINANCE_US",
277            Self::Bitfinex => "BITFINEX",
278            Self::BitfinexDerivatives => "BITFINEX",
279            Self::Bitflyer => "BITFLYER",
280            Self::Bitget => "BITGET",
281            Self::BitgetFutures => "BITGET",
282            Self::Bitmex => "BITMEX",
283            Self::Bitnomial => "BITNOMIAL",
284            Self::Bitstamp => "BITSTAMP",
285            Self::BlockchainCom => "BLOCKCHAIN_COM",
286            Self::Bybit => "BYBIT",
287            Self::BybitOptions => "BYBIT",
288            Self::BybitSpot => "BYBIT",
289            Self::Coinbase => "COINBASE",
290            Self::CoinbaseInternational => "COINBASE_INTX",
291            Self::Coinflex => "COINFLEX",
292            Self::CryptoCom => "CRYPTO_COM",
293            Self::CryptoComDerivatives => "CRYPTO_COM",
294            Self::Cryptofacilities => "CRYPTOFACILITIES",
295            Self::Delta => "DELTA",
296            Self::Deribit => "DERIBIT",
297            Self::Dydx => "DYDX",
298            Self::DydxV4 => "DYDX_V4",
299            Self::Ftx => "FTX",
300            Self::FtxUs => "FTX",
301            Self::GateIo => "GATE_IO",
302            Self::GateIoFutures => "GATE_IO",
303            Self::Gemini => "GEMINI",
304            Self::Hitbtc => "HITBTC",
305            Self::Huobi => "HUOBI",
306            Self::HuobiDm => "HUOBI",
307            Self::HuobiDmLinearSwap => "HUOBI",
308            Self::HuobiDmOptions => "HUOBI",
309            Self::HuobiDmSwap => "HUOBI_DELIVERY",
310            Self::Hyperliquid => "HYPERLIQUID",
311            Self::Kraken => "KRAKEN",
312            Self::Kucoin => "KUCOIN",
313            Self::KucoinFutures => "KUCOIN",
314            Self::Mango => "MANGO",
315            Self::Okcoin => "OKCOIN",
316            Self::Okex => "OKEX",
317            Self::OkexFutures => "OKEX",
318            Self::OkexOptions => "OKEX",
319            Self::OkexSpreads => "OKEX",
320            Self::OkexSwap => "OKEX",
321            Self::Phemex => "PHEMEX",
322            Self::Poloniex => "POLONIEX",
323            Self::Serum => "SERUM",
324            Self::StarAtlas => "STAR_ATLAS",
325            Self::Upbit => "UPBIT",
326            Self::WooX => "WOO_X",
327        }
328    }
329
330    #[must_use]
331    pub fn as_venue(&self) -> Venue {
332        Venue::from_ustr_unchecked(Ustr::from(self.as_venue_str()))
333    }
334}
335
336#[cfg(test)]
337mod tests {
338    use rstest::rstest;
339    use strum::IntoEnumIterator;
340
341    use super::*;
342
343    #[rstest]
344    fn test_exchange_to_venue_mapping() {
345        for exchange in TardisExchange::iter() {
346            let venue_str = exchange.as_venue_str();
347            assert!(
348                Venue::new_checked(venue_str).is_ok(),
349                "Tardis exchange '{exchange:?}' maps to invalid Nautilus venue '{venue_str}'",
350            );
351        }
352    }
353
354    #[rstest]
355    fn test_venue_to_exchange_mapping_bidirectional() {
356        let test_venues = [
357            "BINANCE",
358            "BITMEX",
359            "DERIBIT",
360            "KRAKEN",
361            "COINBASE",
362            "BYBIT",
363            "OKEX",
364            "HUOBI",
365            "GATE_IO",
366            "KUCOIN",
367            "BITFINEX",
368            "GEMINI",
369            "BITSTAMP",
370            "ASCENDEX",
371            "PHEMEX",
372            "POLONIEX",
373            "UPBIT",
374            "WOO_X",
375            "HYPERLIQUID",
376            "CRYPTO_COM",
377            "DYDX",
378            "HITBTC",
379        ];
380
381        for venue_str in test_venues {
382            let venue = Venue::new(venue_str);
383            let exchanges = TardisExchange::from_venue_str(venue.as_str());
384
385            for exchange in exchanges {
386                assert_eq!(
387                    exchange.as_venue_str(),
388                    venue_str,
389                    "Bidirectional mapping failed: Nautilus venue '{venue_str}' -> Tardis exchange '{exchange:?}' -> Nautilus venue '{}'",
390                    exchange.as_venue_str()
391                );
392            }
393        }
394    }
395}