mod utils;
use crypto_market_type::MarketType;
use crypto_pair::{get_market_type, normalize_currency, normalize_pair};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use utils::http_get;
const EXCHANGE_NAME: &str = "bitget";
#[derive(Clone, Serialize, Deserialize)]
#[allow(non_snake_case)]
struct SpotMarket {
symbol: String, symbolName: String, baseCoin: String, quoteCoin: String, status: String, #[serde(flatten)]
extra: HashMap<String, Value>,
}
#[derive(Clone, Serialize, Deserialize)]
#[allow(non_snake_case)]
struct SwapMarket {
symbol: String, baseCoin: String, quoteCoin: String, #[serde(flatten)]
extra: HashMap<String, Value>,
}
fn fetch_spot_markets_raw() -> Vec<SpotMarket> {
#[derive(Serialize, Deserialize)]
#[allow(non_snake_case)]
struct Response {
code: String,
msg: String,
data: Vec<SpotMarket>,
requestTime: Value,
#[serde(flatten)]
extra: HashMap<String, Value>,
}
let txt = http_get("https://api.bitget.com/api/spot/v1/public/products").unwrap();
let resp = serde_json::from_str::<Response>(&txt).unwrap();
if resp.msg != "success" {
Vec::new()
} else {
resp.data
.into_iter()
.filter(|x| x.status == "online" && x.symbol.ends_with("USDT_SPBL"))
.collect::<Vec<SpotMarket>>()
}
}
fn fetch_swap_markets_raw(product_type: &str) -> Vec<SwapMarket> {
#[derive(Serialize, Deserialize)]
#[allow(non_snake_case)]
struct Response {
code: String,
msg: String,
data: Vec<SwapMarket>,
requestTime: Value,
#[serde(flatten)]
extra: HashMap<String, Value>,
}
let txt = http_get(
format!("https://api.bitget.com/api/mix/v1/market/contracts?productType={product_type}")
.as_str(),
)
.unwrap();
let resp = serde_json::from_str::<Response>(&txt).unwrap();
if resp.msg != "success" { Vec::new() } else { resp.data }
}
#[test]
fn verify_spot_symbols() {
let markets = fetch_spot_markets_raw();
for market in markets.iter() {
let pair = normalize_pair(&market.symbol, EXCHANGE_NAME).unwrap();
let pair_expected = format!(
"{}/{}",
normalize_currency(&market.baseCoin, EXCHANGE_NAME),
normalize_currency(&market.quoteCoin, EXCHANGE_NAME)
);
assert_eq!(pair.as_str(), pair_expected);
assert_eq!(MarketType::Spot, get_market_type(&market.symbol, EXCHANGE_NAME, None));
}
}
#[test]
fn verify_swap_symbols() {
let usdt_linear_markets = fetch_swap_markets_raw("umcbl");
let usdc_linear_markets = fetch_swap_markets_raw("cmcbl");
let inverse_markets = fetch_swap_markets_raw("dmcbl");
let markets = usdt_linear_markets
.into_iter()
.chain(usdc_linear_markets)
.chain(inverse_markets)
.collect::<Vec<SwapMarket>>();
for market in markets.iter() {
let pair = normalize_pair(&market.symbol, EXCHANGE_NAME).unwrap();
let pair_expected = format!(
"{}/{}",
normalize_currency(&market.baseCoin, EXCHANGE_NAME),
normalize_currency(
if market.symbol.ends_with("PERP_CMCBL") { "USDC" } else { &market.quoteCoin },
EXCHANGE_NAME
)
);
assert_eq!(pair.as_str(), pair_expected);
let market_type = get_market_type(&market.symbol, EXCHANGE_NAME, None);
assert!(
market_type == MarketType::LinearSwap
|| market_type == MarketType::InverseSwap
|| market_type == MarketType::InverseFuture
);
}
}