crypto_markets/exchanges/gate/
gate_swap.rs

1use std::collections::HashMap;
2
3use super::super::utils::http_get;
4use crate::{error::Result, Fees, Market, Precision, QuantityLimit};
5
6use crypto_market_type::MarketType;
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9
10// https://www.gateio.pro/docs/apiv4/zh_CN/#contract
11#[derive(Clone, Serialize, Deserialize)]
12#[allow(non_snake_case)]
13struct SwapMarket {
14    name: String,
15    #[serde(rename = "type")]
16    type_: String, // inverse, direct
17    quanto_multiplier: String,
18    leverage_min: String,
19    leverage_max: String,
20    maintenance_rate: String,
21    mark_type: String, // internal, index
22    maker_fee_rate: String,
23    taker_fee_rate: String,
24    order_price_round: String,
25    mark_price_round: String,
26    funding_rate: String,
27    order_size_min: f64,
28    order_size_max: f64,
29    in_delisting: bool,
30    #[serde(flatten)]
31    extra: HashMap<String, Value>,
32}
33
34// See https://www.gateio.pro/docs/apiv4/zh_CN/index.html#595cd9fe3c
35fn fetch_swap_markets_raw(settle: &str) -> Result<Vec<SwapMarket>> {
36    let txt = http_get(
37        format!("https://api.gateio.ws/api/v4/futures/{settle}/contracts").as_str(),
38        None,
39    )?;
40    let markets = serde_json::from_str::<Vec<SwapMarket>>(&txt)?;
41    Ok(markets.into_iter().filter(|x| !x.in_delisting).collect::<Vec<SwapMarket>>())
42}
43
44pub(super) fn fetch_inverse_swap_symbols() -> Result<Vec<String>> {
45    let symbols =
46        fetch_swap_markets_raw("btc")?.into_iter().map(|m| m.name).collect::<Vec<String>>();
47    Ok(symbols)
48}
49
50pub(super) fn fetch_linear_swap_symbols() -> Result<Vec<String>> {
51    let symbols =
52        fetch_swap_markets_raw("usdt")?.into_iter().map(|m| m.name).collect::<Vec<String>>();
53    Ok(symbols)
54}
55
56fn to_market(raw_market: &SwapMarket) -> Market {
57    let pair = crypto_pair::normalize_pair(&raw_market.name, "gate").unwrap();
58    let (base, quote) = {
59        let v: Vec<&str> = pair.split('/').collect();
60        (v[0].to_string(), v[1].to_string())
61    };
62    let (base_id, quote_id) = {
63        let v: Vec<&str> = raw_market.name.split('_').collect();
64        (v[0].to_string(), v[1].to_string())
65    };
66    let market_type = if raw_market.name.ends_with("_USD") {
67        MarketType::InverseSwap
68    } else if raw_market.name.ends_with("_USDT") {
69        MarketType::LinearSwap
70    } else {
71        panic!("Failed to detect market type for {}", raw_market.name);
72    };
73    let mut quanto_multiplier = raw_market.quanto_multiplier.parse::<f64>().unwrap();
74    if raw_market.name == "BTC_USD" {
75        assert_eq!(quanto_multiplier, 0.0);
76        quanto_multiplier = 1.0;
77    }
78    assert!(quanto_multiplier > 0.0);
79
80    Market {
81        exchange: "gate".to_string(),
82        market_type,
83        symbol: raw_market.name.to_string(),
84        base_id: base_id.clone(),
85        quote_id: quote_id.clone(),
86        settle_id: if market_type == MarketType::InverseSwap {
87            Some(base_id)
88        } else {
89            Some(quote_id)
90        },
91        base: base.clone(),
92        quote: quote.clone(),
93        settle: if market_type == MarketType::InverseSwap { Some(base) } else { Some(quote) },
94        active: !raw_market.in_delisting,
95        margin: true,
96        fees: Fees {
97            maker: raw_market.maker_fee_rate.parse::<f64>().unwrap(),
98            taker: raw_market.taker_fee_rate.parse::<f64>().unwrap(),
99        },
100        precision: Precision {
101            tick_size: raw_market.order_price_round.parse::<f64>().unwrap(),
102            lot_size: quanto_multiplier,
103        },
104        quantity_limit: Some(QuantityLimit {
105            min: Some(raw_market.order_size_min),
106            max: Some(raw_market.order_size_max),
107            notional_min: None,
108            notional_max: None,
109        }),
110        contract_value: Some(quanto_multiplier),
111        delivery_date: None,
112        info: serde_json::to_value(raw_market).unwrap().as_object().unwrap().clone(),
113    }
114}
115
116pub(super) fn fetch_inverse_swap_markets() -> Result<Vec<Market>> {
117    let markets =
118        fetch_swap_markets_raw("btc")?.into_iter().map(|m| to_market(&m)).collect::<Vec<Market>>();
119    Ok(markets)
120}
121
122pub(super) fn fetch_linear_swap_markets() -> Result<Vec<Market>> {
123    let markets =
124        fetch_swap_markets_raw("usdt")?.into_iter().map(|m| to_market(&m)).collect::<Vec<Market>>();
125    Ok(markets)
126}