pragma_common/exchange/
mod.rs1use crate::{
2 pair::{AssetSymbol, RawMarketName},
3 Pair,
4};
5
6pub mod margin_type;
7pub use margin_type::MarginType;
8
9#[derive(
10 Clone,
11 Debug,
12 Hash,
13 PartialEq,
14 PartialOrd,
15 Ord,
16 Eq,
17 Copy,
18 strum::EnumString,
19 strum::Display,
20 strum::EnumIter,
21)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23#[cfg_attr(
24 feature = "borsh",
25 derive(borsh::BorshSerialize, borsh::BorshDeserialize)
26)]
27#[strum(ascii_case_insensitive, serialize_all = "UPPERCASE")]
28#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
29#[non_exhaustive]
30pub enum Exchange {
31 Hyperliquid,
32 Paradex,
33 Kraken,
34 Lmax,
35 Extended,
36}
37
38impl Exchange {
39 pub fn market_name_from_pair(&self, pair: &Pair) -> RawMarketName {
43 match self {
44 Exchange::Hyperliquid => pair.base.to_string(),
45 Exchange::Paradex => format!("{}-{}-PERP", pair.base, pair.quote),
46 Exchange::Kraken => match pair.base.as_str() {
47 "BTC" => "PF_XBTUSD".to_string(),
48 other => format!("PF_{}{}", other, pair.quote),
49 },
50 Exchange::Lmax | Exchange::Extended => format!("{}-{}", pair.base, pair.quote),
51 }
52 }
53
54 pub fn usd_market_name_from_asset_symbol(&self, asset_symbol: &AssetSymbol) -> RawMarketName {
56 match self {
57 Exchange::Hyperliquid => asset_symbol.to_string(),
58 Exchange::Paradex => format!("{asset_symbol}-USD-PERP"),
59 Exchange::Kraken => match asset_symbol.to_string().to_uppercase().as_str() {
60 "BTC" => "PF_XBTUSD".to_string(),
61 other => format!("PF_{other}USD"),
62 },
63 Exchange::Lmax | Exchange::Extended => format!("{asset_symbol}-USD"),
64 }
65 }
66
67 pub fn asset_symbol_from_raw_market_name(&self, market_name: &RawMarketName) -> AssetSymbol {
68 match self {
69 Exchange::Hyperliquid => AssetSymbol::from(market_name),
70 Exchange::Paradex | Exchange::Lmax | Exchange::Extended => {
71 market_name.split('-').next().unwrap().into()
72 }
73 Exchange::Kraken => {
74 if market_name.starts_with("PF_") && market_name.ends_with("USD") {
75 let base_part = &market_name[3..market_name.len() - 3];
76 match base_part {
77 "XBT" => "BTC".into(),
78 other => other.into(),
79 }
80 } else {
81 market_name.split('/').next().unwrap().into()
82 }
83 }
84 }
85 }
86
87 pub const fn taker_fees_rate(&self) -> f64 {
90 match self {
91 Exchange::Hyperliquid => 0.00045, Exchange::Paradex => 0.0003, Exchange::Kraken => 0.0002, Exchange::Extended => 0.00025, _ => todo!(),
97 }
98 }
99
100 pub const fn supports_leverage(&self) -> bool {
102 match self {
103 Exchange::Hyperliquid => true,
104 Exchange::Paradex => true,
105 Exchange::Kraken => false,
106 Exchange::Extended => true,
107 Exchange::Lmax => false,
108 }
109 }
110
111 pub const fn from_str_const(s: &str) -> Option<Self> {
112 match s.as_bytes() {
113 b"Lmax" | b"lmax" | b"LMAX" => Some(Exchange::Lmax),
114 b"Extended" | b"extended" | b"EXTENDED" => Some(Exchange::Extended),
115 b"Hyperliquid" | b"hyperliquid" | b"HYPERLIQUID" => Some(Exchange::Hyperliquid),
116 b"Paradex" | b"paradex" | b"PARADEX" => Some(Exchange::Paradex),
117 b"Kraken" | b"kraken" | b"KRAKEN" => Some(Exchange::Kraken),
118 _ => None,
119 }
120 }
121}