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 #[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}