crypto_markets/exchanges/
bithumb.rs1use std::collections::HashMap;
2
3use super::utils::http_get;
4use crate::{
5 error::{Error, Result},
6 Fees, Market, MarketType, Precision,
7};
8
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11
12pub(crate) fn fetch_symbols(market_type: MarketType) -> Result<Vec<String>> {
13 match market_type {
14 MarketType::Spot => fetch_spot_symbols(),
15 _ => panic!("Unsupported market_type: {market_type}"),
16 }
17}
18
19pub(crate) fn fetch_markets(market_type: MarketType) -> Result<Vec<Market>> {
20 match market_type {
21 MarketType::Spot => fetch_spot_markets(),
22 _ => panic!("Unsupported market_type: {market_type}"),
23 }
24}
25
26#[derive(Serialize, Deserialize)]
27#[allow(non_snake_case)]
28struct CoinConfig {
29 makerFeeRate: serde_json::Value, minTxAmt: Option<String>,
31 name: String,
32 depositStatus: String,
33 fullName: String,
34 takerFeeRate: serde_json::Value, minWithdraw: String,
36 withdrawFee: String,
37 withdrawStatus: String,
38 #[serde(flatten)]
39 extra: HashMap<String, Value>,
40}
41
42#[derive(Serialize, Deserialize)]
43#[allow(non_snake_case)]
44struct PercentPrice {
45 multiplierDown: String,
46 multiplierUp: String,
47}
48
49#[derive(Serialize, Deserialize)]
50#[allow(non_snake_case)]
51struct SpotConfig {
52 symbol: String,
53 percentPrice: PercentPrice,
54 accuracy: Vec<String>,
55 openPrice: String,
56 openTime: i64,
57 #[serde(flatten)]
58 extra: HashMap<String, Value>,
59}
60
61#[derive(Serialize, Deserialize)]
62#[allow(non_snake_case)]
63struct Data {
64 coinConfig: Vec<CoinConfig>,
65 spotConfig: Vec<SpotConfig>,
66}
67
68#[derive(Serialize, Deserialize)]
69struct Response {
70 data: Data,
71 code: String,
72 msg: String,
73 timestamp: i64,
74}
75
76fn fetch_spot_coing() -> Result<Data> {
78 let txt = http_get("https://global-openapi.bithumb.pro/openapi/v1/spot/config", None)?;
79 let resp = serde_json::from_str::<Response>(&txt)?;
80 if resp.code != "0" { Err(Error(txt)) } else { Ok(resp.data) }
81}
82
83fn fetch_spot_symbols() -> Result<Vec<String>> {
84 let symbols =
85 fetch_spot_coing()?.spotConfig.into_iter().map(|m| m.symbol).collect::<Vec<String>>();
86 Ok(symbols)
87}
88
89fn fetch_spot_markets() -> Result<Vec<Market>> {
90 let markets = fetch_spot_coing()?
91 .spotConfig
92 .into_iter()
93 .map(|m| {
94 let info = serde_json::to_value(&m).unwrap().as_object().unwrap().clone();
95 let pair = crypto_pair::normalize_pair(&m.symbol, "bithumb").unwrap();
96 let (base, quote) = {
97 let v: Vec<&str> = pair.split('/').collect();
98 (v[0].to_string(), v[1].to_string())
99 };
100 let (base_id, quote_id) = {
101 let v: Vec<&str> = m.symbol.split('-').collect();
102 (v[0].to_string(), v[1].to_string())
103 };
104 Market {
105 exchange: "bithumb".to_string(),
106 market_type: MarketType::Spot,
107 symbol: m.symbol,
108 base_id,
109 quote_id,
110 settle_id: None,
111 base,
112 quote,
113 settle: None,
114 active: true,
115 margin: false,
116 fees: Fees { maker: 0.001, taker: 0.001 },
118 precision: Precision {
119 tick_size: 1.0 / (10_i64.pow(m.accuracy[0].parse::<u32>().unwrap()) as f64),
120 lot_size: 1.0 / (10_i64.pow(m.accuracy[1].parse::<u32>().unwrap()) as f64),
121 },
122 quantity_limit: None,
123 contract_value: None,
124 delivery_date: None,
125 info,
126 }
127 })
128 .collect::<Vec<Market>>();
129 Ok(markets)
130}