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(
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")]
135pub 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 pub const OPTION_EXCHANGES: &'static [Self] = &[
202 Self::BinanceOptions,
203 Self::BinanceEuropeanOptions,
204 Self::BybitOptions,
205 Self::OkexOptions,
206 Self::HuobiDmOptions,
207 ];
208
209 #[must_use]
210 pub fn is_option_exchange(&self) -> bool {
211 Self::OPTION_EXCHANGES.contains(self)
212 }
213
214 #[must_use]
215 pub fn from_venue_str(s: &str) -> Vec<Self> {
216 let s = s.to_ascii_uppercase();
217 match s.as_str() {
218 "ASCENDEX" => vec![Self::Ascendex],
219 "BINANCE" => vec![
220 Self::Binance,
221 Self::BinanceDex,
222 Self::BinanceEuropeanOptions,
223 Self::BinanceFutures,
224 Self::BinanceJersey,
225 Self::BinanceOptions,
226 ],
227 "BINANCE_DELIVERY" => vec![Self::BinanceDelivery],
228 "BINANCE_US" => vec![Self::BinanceUs],
229 "BITFINEX" => vec![Self::Bitfinex, Self::BitfinexDerivatives],
230 "BITFLYER" => vec![Self::Bitflyer],
231 "BITGET" => vec![Self::Bitget, Self::BitgetFutures],
232 "BITMEX" => vec![Self::Bitmex],
233 "BITNOMIAL" => vec![Self::Bitnomial],
234 "BITSTAMP" => vec![Self::Bitstamp],
235 "BLOCKCHAIN_COM" => vec![Self::BlockchainCom],
236 "BYBIT" => vec![Self::Bybit, Self::BybitOptions, Self::BybitSpot],
237 "COINBASE" => vec![Self::Coinbase],
238 "COINBASE_INTX" => vec![Self::CoinbaseInternational],
239 "COINFLEX" => vec![Self::Coinflex],
240 "CRYPTO_COM" => vec![Self::CryptoCom, Self::CryptoComDerivatives],
241 "CRYPTOFACILITIES" => vec![Self::Cryptofacilities],
242 "DELTA" => vec![Self::Delta],
243 "DERIBIT" => vec![Self::Deribit],
244 "DYDX" => vec![Self::Dydx],
245 "DYDX_V4" => vec![Self::DydxV4],
246 "FTX" => vec![Self::Ftx, Self::FtxUs],
247 "GATE_IO" => vec![Self::GateIo, Self::GateIoFutures],
248 "GEMINI" => vec![Self::Gemini],
249 "HITBTC" => vec![Self::Hitbtc],
250 "HUOBI" => vec![
251 Self::Huobi,
252 Self::HuobiDm,
253 Self::HuobiDmLinearSwap,
254 Self::HuobiDmOptions,
255 ],
256 "HUOBI_DELIVERY" => vec![Self::HuobiDmSwap],
257 "HYPERLIQUID" => vec![Self::Hyperliquid],
258 "KRAKEN" => vec![Self::Kraken],
259 "KUCOIN" => vec![Self::Kucoin, Self::KucoinFutures],
260 "MANGO" => vec![Self::Mango],
261 "OKCOIN" => vec![Self::Okcoin],
262 "OKEX" => vec![
263 Self::Okex,
264 Self::OkexFutures,
265 Self::OkexOptions,
266 Self::OkexSpreads,
267 Self::OkexSwap,
268 ],
269 "PHEMEX" => vec![Self::Phemex],
270 "POLONIEX" => vec![Self::Poloniex],
271 "SERUM" => vec![Self::Serum],
272 "STAR_ATLAS" => vec![Self::StarAtlas],
273 "UPBIT" => vec![Self::Upbit],
274 "WOO_X" => vec![Self::WooX],
275 _ => Vec::new(),
276 }
277 }
278
279 #[must_use]
280 pub const fn as_venue_str(&self) -> &str {
281 match self {
282 Self::Ascendex => "ASCENDEX",
283 Self::Binance => "BINANCE",
284 Self::BinanceDelivery => "BINANCE_DELIVERY",
285 Self::BinanceDex => "BINANCE",
286 Self::BinanceEuropeanOptions => "BINANCE",
287 Self::BinanceFutures => "BINANCE",
288 Self::BinanceJersey => "BINANCE",
289 Self::BinanceOptions => "BINANCE",
290 Self::BinanceUs => "BINANCE_US",
291 Self::Bitfinex => "BITFINEX",
292 Self::BitfinexDerivatives => "BITFINEX",
293 Self::Bitflyer => "BITFLYER",
294 Self::Bitget => "BITGET",
295 Self::BitgetFutures => "BITGET",
296 Self::Bitmex => "BITMEX",
297 Self::Bitnomial => "BITNOMIAL",
298 Self::Bitstamp => "BITSTAMP",
299 Self::BlockchainCom => "BLOCKCHAIN_COM",
300 Self::Bybit => "BYBIT",
301 Self::BybitOptions => "BYBIT",
302 Self::BybitSpot => "BYBIT",
303 Self::Coinbase => "COINBASE",
304 Self::CoinbaseInternational => "COINBASE_INTX",
305 Self::Coinflex => "COINFLEX",
306 Self::CryptoCom => "CRYPTO_COM",
307 Self::CryptoComDerivatives => "CRYPTO_COM",
308 Self::Cryptofacilities => "CRYPTOFACILITIES",
309 Self::Delta => "DELTA",
310 Self::Deribit => "DERIBIT",
311 Self::Dydx => "DYDX",
312 Self::DydxV4 => "DYDX_V4",
313 Self::Ftx => "FTX",
314 Self::FtxUs => "FTX",
315 Self::GateIo => "GATE_IO",
316 Self::GateIoFutures => "GATE_IO",
317 Self::Gemini => "GEMINI",
318 Self::Hitbtc => "HITBTC",
319 Self::Huobi => "HUOBI",
320 Self::HuobiDm => "HUOBI",
321 Self::HuobiDmLinearSwap => "HUOBI",
322 Self::HuobiDmOptions => "HUOBI",
323 Self::HuobiDmSwap => "HUOBI_DELIVERY",
324 Self::Hyperliquid => "HYPERLIQUID",
325 Self::Kraken => "KRAKEN",
326 Self::Kucoin => "KUCOIN",
327 Self::KucoinFutures => "KUCOIN",
328 Self::Mango => "MANGO",
329 Self::Okcoin => "OKCOIN",
330 Self::Okex => "OKEX",
331 Self::OkexFutures => "OKEX",
332 Self::OkexOptions => "OKEX",
333 Self::OkexSpreads => "OKEX",
334 Self::OkexSwap => "OKEX",
335 Self::Phemex => "PHEMEX",
336 Self::Poloniex => "POLONIEX",
337 Self::Serum => "SERUM",
338 Self::StarAtlas => "STAR_ATLAS",
339 Self::Upbit => "UPBIT",
340 Self::WooX => "WOO_X",
341 }
342 }
343
344 #[must_use]
345 pub fn as_venue(&self) -> Venue {
346 Venue::from_ustr_unchecked(Ustr::from(self.as_venue_str()))
347 }
348}
349
350#[cfg(test)]
351mod tests {
352 use rstest::rstest;
353 use strum::IntoEnumIterator;
354
355 use super::*;
356
357 #[rstest]
358 fn test_exchange_to_venue_mapping() {
359 for exchange in TardisExchange::iter() {
360 let venue_str = exchange.as_venue_str();
361 assert!(
362 Venue::new_checked(venue_str).is_ok(),
363 "Tardis exchange '{exchange:?}' maps to invalid Nautilus venue '{venue_str}'",
364 );
365 }
366 }
367
368 #[rstest]
369 fn test_venue_to_exchange_mapping_bidirectional() {
370 let test_venues = [
371 "BINANCE",
372 "BITMEX",
373 "DERIBIT",
374 "KRAKEN",
375 "COINBASE",
376 "BYBIT",
377 "OKEX",
378 "HUOBI",
379 "GATE_IO",
380 "KUCOIN",
381 "BITFINEX",
382 "GEMINI",
383 "BITSTAMP",
384 "ASCENDEX",
385 "PHEMEX",
386 "POLONIEX",
387 "UPBIT",
388 "WOO_X",
389 "HYPERLIQUID",
390 "CRYPTO_COM",
391 "DYDX",
392 "HITBTC",
393 ];
394
395 for venue_str in test_venues {
396 let venue = Venue::new(venue_str);
397 let exchanges = TardisExchange::from_venue_str(venue.as_str());
398
399 for exchange in exchanges {
400 assert_eq!(
401 exchange.as_venue_str(),
402 venue_str,
403 "Bidirectional mapping failed: Nautilus venue '{venue_str}' -> Tardis exchange '{exchange:?}' -> Nautilus venue '{}'",
404 exchange.as_venue_str()
405 );
406 }
407 }
408 }
409}