crypto_contract_value/exchanges/
bitmex.rs1use std::collections::{BTreeMap, HashMap};
2
3use super::utils::http_get;
4use crypto_market_type::MarketType;
5use once_cell::sync::Lazy;
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8
9static CONTRACT_VALUES: Lazy<HashMap<String, f64>> = Lazy::new(|| {
11 let mut m: HashMap<String, f64> = vec![
13 ("inverse_future.BTC/USD", 1.0),
14 ("inverse_future.ETH/USD", 1.0),
15 ("inverse_swap.BTC/EUR", 1.0),
16 ("inverse_swap.BTC/USD", 1.0),
17 ("inverse_swap.ETH/USD", 1.0),
18 ("inverse_swap.XBTETH/BTC", 0.01),
19 ("linear_future.ADA/BTC", 0.01),
20 ("linear_future.BTC/USDT", 0.000001),
21 ("linear_future.ETH/BTC", 0.00001),
22 ("linear_future.ETH/USDT", 0.00001),
23 ("linear_future.ETHPOW/USDT", 0.00001),
24 ("linear_future.XRP/BTC", 0.01),
25 ("linear_swap.ADA/USDT", 0.01),
26 ("linear_swap.APE/USDT", 0.001),
27 ("linear_swap.APT/USDT", 0.001),
28 ("linear_swap.ARB/USDT", 0.001),
29 ("linear_swap.AVAX/USDT", 0.0001),
30 ("linear_swap.BCH/USDT", 0.00001),
31 ("linear_swap.BIGTIME/USDT", 1.0),
32 ("linear_swap.BLUR/USDT", 0.001),
33 ("linear_swap.BMEX/USDT", 0.001),
34 ("linear_swap.BNB/USDT", 0.0001),
35 ("linear_swap.BTC/USDT", 0.000001),
36 ("linear_swap.CRO/USDT", 0.01),
37 ("linear_swap.CYBER/USDT", 1.0),
38 ("linear_swap.DEFIMEXT/USDT", 0.0001),
39 ("linear_swap.DOGE/USDT", 0.01),
40 ("linear_swap.DOT/USDT", 0.001),
41 ("linear_swap.EOS/USDT", 0.001),
42 ("linear_swap.ETH/USDT", 0.00001),
43 ("linear_swap.FIL/USDT", 1.0),
44 ("linear_swap.FTM/USDT", 0.01),
45 ("linear_swap.FTT/USDT", 0.0001),
46 ("linear_swap.GAL/USDT", 0.001),
47 ("linear_swap.GMT/USDT", 0.001),
48 ("linear_swap.KLAY/USDT", 0.01),
49 ("linear_swap.LINK/USDT", 0.001),
50 ("linear_swap.LTC/USDT", 0.0001),
51 ("linear_swap.LUNA/USDT", 0.001),
52 ("linear_swap.MANA/USDT", 0.001),
53 ("linear_swap.MATIC/USDT", 0.01),
54 ("linear_swap.MEME/USDT", 1.0),
55 ("linear_swap.NEAR/USDT", 0.001),
56 ("linear_swap.OP/USDT", 0.001),
57 ("linear_swap.ORBS/USDT", 1.0),
58 ("linear_swap.PEPE/USDT", 1.0),
59 ("linear_swap.PYTH/USDT", 1.0),
60 ("linear_swap.SAND/USDT", 0.001),
61 ("linear_swap.SEI/USDT", 1.0),
62 ("linear_swap.SHIB/USDT", 1.0),
63 ("linear_swap.SOL/USDT", 0.0001),
64 ("linear_swap.SUI/USDT", 0.001),
65 ("linear_swap.TIA/USDT", 1.0),
66 ("linear_swap.TRX/USDT", 0.1),
67 ("linear_swap.XRP/USDT", 0.01),
68 ("quanto_swap.EUR/USDT", 1.0),
69 ("quanto_swap.NZD/USDT", 1.0),
70 ]
71 .into_iter()
72 .map(|x| (x.0.to_string(), x.1))
73 .collect();
74
75 let from_online = fetch_contract_values();
76 for (pair, contract_value) in from_online {
77 m.insert(pair, contract_value);
78 }
79
80 m
81});
82
83#[derive(Clone, Serialize, Deserialize)]
84#[allow(non_snake_case)]
85struct Instrument {
86 symbol: String,
87 state: String,
88 typ: String,
89 quoteCurrency: String,
90 multiplier: f64,
91 isQuanto: bool,
92 isInverse: bool,
93 hasLiquidity: bool,
94 openInterest: i64,
95 volume: i64,
96 volume24h: i64,
97 turnover: i64,
98 turnover24h: i64,
99 underlyingToSettleMultiplier: Option<f64>,
100 underlyingToPositionMultiplier: Option<f64>,
101 quoteToSettleMultiplier: Option<f64>,
102 #[serde(flatten)]
103 extra: HashMap<String, Value>,
104}
105
106fn fetch_contract_values() -> BTreeMap<String, f64> {
107 let mut mapping: BTreeMap<String, f64> = BTreeMap::new();
108
109 if let Ok(text) = http_get("https://www.bitmex.com/api/v1/instrument/active") {
110 let instruments: Vec<Instrument> = serde_json::from_str::<Vec<Instrument>>(&text)
111 .unwrap()
112 .into_iter()
113 .filter(|x| x.state == "Open" && x.hasLiquidity && x.volume24h > 0 && x.turnover24h > 0)
114 .collect();
115
116 for instrument in instruments
117 .iter()
118 .filter(|instrument| !instrument.isQuanto && instrument.typ != "IFXXXP")
119 {
120 let market_type = crypto_pair::get_market_type(&instrument.symbol, "bitmex", None);
121 let pair = crypto_pair::normalize_pair(&instrument.symbol, "bitmex").unwrap();
122 mapping.insert(
123 market_type.to_string() + "." + pair.as_str(),
124 if let Some(x) = instrument.underlyingToSettleMultiplier {
125 instrument.multiplier / x
126 } else {
127 instrument.multiplier / instrument.quoteToSettleMultiplier.unwrap()
128 },
129 );
130 }
131 }
132
133 mapping
134}
135
136pub(crate) fn get_contract_value(market_type: MarketType, pair: &str) -> Option<f64> {
137 if market_type == MarketType::Unknown {
138 panic!("Must be a specific market type");
139 }
140 let key = market_type.to_string() + "." + pair;
141 if CONTRACT_VALUES.contains_key(key.as_str()) { Some(CONTRACT_VALUES[&key]) } else { Some(1.0) }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::fetch_contract_values;
147
148 #[ignore]
149 #[test]
150 fn test_fetch_contract_values() {
151 let mut mapping = fetch_contract_values();
152 for (key, value) in super::CONTRACT_VALUES.iter() {
153 if !mapping.contains_key(key) {
154 mapping.insert(key.to_string(), *value);
155 }
156 }
157 for (pair, contract_value) in &mapping {
158 println!("(\"{pair}\", {contract_value}),");
159 }
160 }
161}