1use 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")]
39pub 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")]
64pub enum TardisOptionType {
66 Call,
67 Put,
68}
69
70#[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#[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(
120 Copy,
121 Clone,
122 Debug,
123 PartialEq,
124 Eq,
125 Hash,
126 Serialize,
127 Deserialize,
128 Display,
129 AsRefStr,
130 EnumIter,
131 EnumString,
132 FromRepr,
133)]
134#[strum(serialize_all = "snake_case")]
135#[serde(rename_all = "snake_case")]
136pub enum TardisDataType {
137 Trade,
138 BookChange,
139 BookSnapshot,
140 DerivativeTicker,
141 Quote,
142 Disconnect,
143}
144
145impl TardisDataType {
146 #[must_use]
148 pub fn as_tardis_str(&self) -> &str {
149 match self {
150 Self::Trade => "trade",
151 Self::BookChange => "book_change",
152 Self::BookSnapshot => "book_snapshot",
153 Self::DerivativeTicker => "derivative_ticker",
154 Self::Quote => "quote",
155 Self::Disconnect => "disconnect",
156 }
157 }
158}
159
160#[derive(
161 Copy,
162 Clone,
163 Debug,
164 PartialEq,
165 Eq,
166 Hash,
167 Serialize,
168 Deserialize,
169 Display,
170 AsRefStr,
171 EnumIter,
172 EnumString,
173 FromRepr,
174)]
175#[strum(ascii_case_insensitive)]
176#[strum(serialize_all = "kebab-case")]
177#[serde(rename_all = "kebab-case")]
178pub enum TardisExchange {
181 Ascendex,
182 Binance,
183 BinanceDelivery,
184 BinanceDex,
185 BinanceEuropeanOptions,
186 BinanceFutures,
187 BinanceJersey,
188 BinanceOptions,
189 BinanceUs,
190 Bitfinex,
191 BitfinexDerivatives,
192 Bitflyer,
193 Bitget,
194 BitgetFutures,
195 Bitmex,
196 Bitnomial,
197 Bitstamp,
198 BlockchainCom,
199 Bybit,
200 BybitOptions,
201 BybitSpot,
202 Coinbase,
203 CoinbaseInternational,
204 Coinflex,
205 CryptoCom,
206 Cryptofacilities,
207 Delta,
208 Deribit,
209 Dydx,
210 DydxV4,
211 Ftx,
212 FtxUs,
213 GateIo,
214 GateIoFutures,
215 Gemini,
216 Hitbtc,
217 Huobi,
218 HuobiDm,
219 HuobiDmLinearSwap,
220 HuobiDmOptions,
221 HuobiDmSwap,
222 Hyperliquid,
223 Kraken,
224 Kucoin,
225 KucoinFutures,
226 Lighter,
227 Mango,
228 Mexc,
229 MexcFutures,
230 Okcoin,
231 Okex,
232 OkexFutures,
233 OkexOptions,
234 OkexSpreads,
235 OkexSwap,
236 Phemex,
237 Poloniex,
238 Serum,
239 StarAtlas,
240 Upbit,
241 WooX,
242}
243
244impl TardisExchange {
245 pub const OPTION_EXCHANGES: &'static [Self] = &[
247 Self::BinanceOptions,
248 Self::BinanceEuropeanOptions,
249 Self::BybitOptions,
250 Self::OkexOptions,
251 Self::HuobiDmOptions,
252 ];
253
254 #[must_use]
255 pub fn is_option_exchange(&self) -> bool {
256 Self::OPTION_EXCHANGES.contains(self)
257 }
258
259 #[must_use]
260 pub fn from_venue_str(s: &str) -> Vec<Self> {
261 let s = s.to_ascii_uppercase();
262 match s.as_str() {
263 "ASCENDEX" => vec![Self::Ascendex],
264 "BINANCE" => vec![
265 Self::Binance,
266 Self::BinanceDex,
267 Self::BinanceEuropeanOptions,
268 Self::BinanceFutures,
269 Self::BinanceJersey,
270 Self::BinanceOptions,
271 ],
272 "BINANCE_DELIVERY" => vec![Self::BinanceDelivery],
273 "BINANCE_US" => vec![Self::BinanceUs],
274 "BITFINEX" => vec![Self::Bitfinex, Self::BitfinexDerivatives],
275 "BITFLYER" => vec![Self::Bitflyer],
276 "BITGET" => vec![Self::Bitget, Self::BitgetFutures],
277 "BITMEX" => vec![Self::Bitmex],
278 "BITNOMIAL" => vec![Self::Bitnomial],
279 "BITSTAMP" => vec![Self::Bitstamp],
280 "BLOCKCHAIN_COM" => vec![Self::BlockchainCom],
281 "BYBIT" => vec![Self::Bybit, Self::BybitOptions, Self::BybitSpot],
282 "COINBASE" => vec![Self::Coinbase],
283 "COINBASE_INTX" => vec![Self::CoinbaseInternational],
284 "COINFLEX" => vec![Self::Coinflex],
285 "CRYPTO_COM" => vec![Self::CryptoCom],
286 "CRYPTOFACILITIES" => vec![Self::Cryptofacilities],
287 "DELTA" => vec![Self::Delta],
288 "DERIBIT" => vec![Self::Deribit],
289 "DYDX" => vec![Self::Dydx],
290 "DYDX_V4" => vec![Self::DydxV4],
291 "FTX" => vec![Self::Ftx, Self::FtxUs],
292 "GATE_IO" => vec![Self::GateIo, Self::GateIoFutures],
293 "GEMINI" => vec![Self::Gemini],
294 "HITBTC" => vec![Self::Hitbtc],
295 "HUOBI" => vec![
296 Self::Huobi,
297 Self::HuobiDm,
298 Self::HuobiDmLinearSwap,
299 Self::HuobiDmOptions,
300 ],
301 "HUOBI_DELIVERY" => vec![Self::HuobiDmSwap],
302 "HYPERLIQUID" => vec![Self::Hyperliquid],
303 "KRAKEN" => vec![Self::Kraken],
304 "KUCOIN" => vec![Self::Kucoin, Self::KucoinFutures],
305 "LIGHTER" => vec![Self::Lighter],
306 "MANGO" => vec![Self::Mango],
307 "MEXC" => vec![Self::Mexc, Self::MexcFutures],
308 "OKCOIN" => vec![Self::Okcoin],
309 "OKEX" => vec![
310 Self::Okex,
311 Self::OkexFutures,
312 Self::OkexOptions,
313 Self::OkexSpreads,
314 Self::OkexSwap,
315 ],
316 "PHEMEX" => vec![Self::Phemex],
317 "POLONIEX" => vec![Self::Poloniex],
318 "SERUM" => vec![Self::Serum],
319 "STAR_ATLAS" => vec![Self::StarAtlas],
320 "UPBIT" => vec![Self::Upbit],
321 "WOO_X" => vec![Self::WooX],
322 _ => Vec::new(),
323 }
324 }
325
326 #[must_use]
327 pub const fn as_venue_str(&self) -> &str {
328 match self {
329 Self::Ascendex => "ASCENDEX",
330 Self::Binance => "BINANCE",
331 Self::BinanceDelivery => "BINANCE_DELIVERY",
332 Self::BinanceDex => "BINANCE",
333 Self::BinanceEuropeanOptions => "BINANCE",
334 Self::BinanceFutures => "BINANCE",
335 Self::BinanceJersey => "BINANCE",
336 Self::BinanceOptions => "BINANCE",
337 Self::BinanceUs => "BINANCE_US",
338 Self::Bitfinex => "BITFINEX",
339 Self::BitfinexDerivatives => "BITFINEX",
340 Self::Bitflyer => "BITFLYER",
341 Self::Bitget => "BITGET",
342 Self::BitgetFutures => "BITGET",
343 Self::Bitmex => "BITMEX",
344 Self::Bitnomial => "BITNOMIAL",
345 Self::Bitstamp => "BITSTAMP",
346 Self::BlockchainCom => "BLOCKCHAIN_COM",
347 Self::Bybit => "BYBIT",
348 Self::BybitOptions => "BYBIT",
349 Self::BybitSpot => "BYBIT",
350 Self::Coinbase => "COINBASE",
351 Self::CoinbaseInternational => "COINBASE_INTX",
352 Self::Coinflex => "COINFLEX",
353 Self::CryptoCom => "CRYPTO_COM",
354 Self::Cryptofacilities => "CRYPTOFACILITIES",
355 Self::Delta => "DELTA",
356 Self::Deribit => "DERIBIT",
357 Self::Dydx => "DYDX",
358 Self::DydxV4 => "DYDX_V4",
359 Self::Ftx => "FTX",
360 Self::FtxUs => "FTX",
361 Self::GateIo => "GATE_IO",
362 Self::GateIoFutures => "GATE_IO",
363 Self::Gemini => "GEMINI",
364 Self::Hitbtc => "HITBTC",
365 Self::Huobi => "HUOBI",
366 Self::HuobiDm => "HUOBI",
367 Self::HuobiDmLinearSwap => "HUOBI",
368 Self::HuobiDmOptions => "HUOBI",
369 Self::HuobiDmSwap => "HUOBI_DELIVERY",
370 Self::Hyperliquid => "HYPERLIQUID",
371 Self::Kraken => "KRAKEN",
372 Self::Kucoin => "KUCOIN",
373 Self::KucoinFutures => "KUCOIN",
374 Self::Lighter => "LIGHTER",
375 Self::Mango => "MANGO",
376 Self::Mexc => "MEXC",
377 Self::MexcFutures => "MEXC",
378 Self::Okcoin => "OKCOIN",
379 Self::Okex => "OKEX",
380 Self::OkexFutures => "OKEX",
381 Self::OkexOptions => "OKEX",
382 Self::OkexSpreads => "OKEX",
383 Self::OkexSwap => "OKEX",
384 Self::Phemex => "PHEMEX",
385 Self::Poloniex => "POLONIEX",
386 Self::Serum => "SERUM",
387 Self::StarAtlas => "STAR_ATLAS",
388 Self::Upbit => "UPBIT",
389 Self::WooX => "WOO_X",
390 }
391 }
392
393 #[must_use]
394 pub fn as_venue(&self) -> Venue {
395 Venue::from_ustr_unchecked(Ustr::from(self.as_venue_str()))
396 }
397}
398
399#[cfg(test)]
400mod tests {
401 use rstest::rstest;
402 use strum::IntoEnumIterator;
403
404 use super::*;
405
406 #[rstest]
407 fn test_exchange_to_venue_mapping() {
408 for exchange in TardisExchange::iter() {
409 let venue_str = exchange.as_venue_str();
410 assert!(
411 Venue::new_checked(venue_str).is_ok(),
412 "Tardis exchange '{exchange:?}' maps to invalid Nautilus venue '{venue_str}'",
413 );
414 }
415 }
416
417 #[rstest]
418 fn test_venue_to_exchange_mapping_bidirectional() {
419 assert_eq!(
420 TardisExchange::from_venue_str("MEXC"),
421 vec![TardisExchange::Mexc, TardisExchange::MexcFutures]
422 );
423
424 let test_venues = [
425 "BINANCE",
426 "BITMEX",
427 "DERIBIT",
428 "KRAKEN",
429 "COINBASE",
430 "BYBIT",
431 "OKEX",
432 "HUOBI",
433 "GATE_IO",
434 "KUCOIN",
435 "BITFINEX",
436 "GEMINI",
437 "BITSTAMP",
438 "ASCENDEX",
439 "PHEMEX",
440 "POLONIEX",
441 "UPBIT",
442 "WOO_X",
443 "HYPERLIQUID",
444 "LIGHTER",
445 "CRYPTO_COM",
446 "DYDX",
447 "HITBTC",
448 "MEXC",
449 ];
450
451 for venue_str in test_venues {
452 let venue = Venue::new(venue_str);
453 let exchanges = TardisExchange::from_venue_str(venue.as_str());
454
455 for exchange in exchanges {
456 assert_eq!(
457 exchange.as_venue_str(),
458 venue_str,
459 "Bidirectional mapping failed: Nautilus venue '{venue_str}' -> Tardis exchange '{exchange:?}' -> Nautilus venue '{}'",
460 exchange.as_venue_str()
461 );
462 }
463 }
464 }
465}