use crypto_market_type::MarketType;
use crate::{MessageType, TradeMsg, TradeSide};
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use serde_json::{Result, Value};
use std::collections::HashMap;
const EXCHANGE_NAME: &str = "bitget";
lazy_static! {
static ref LINEAR_SWAP_MAPPING: HashMap<&'static str, f64> = vec![
("BTC", 0.001),
("EOS", 1.0),
("ETH", 0.1),
("LTC", 0.1),
("XRP", 10.0),
("BCH", 0.01),
("ETC", 1.0),
("ADA", 100.0),
("LINK", 1.0),
("TRX", 100.0),
("DOT", 1.0),
("XTZ", 1.0),
("UNI", 1.0),
("SUSHI", 1.0),
("YFI", 0.0001),
("ATOM", 1.0),
("FIL", 0.1),
("ALGO", 10.0),
("COMP", 0.01),
].into_iter().collect();
}
#[derive(Serialize, Deserialize)]
struct SwapTradeMsg {
instrument_id: String,
price: String,
side: String, size: String,
timestamp: String,
#[serde(flatten)]
extra: HashMap<String, Value>,
}
#[derive(Serialize, Deserialize)]
struct ResponseMsg<T: Sized> {
table: String,
data: Vec<T>,
}
fn calc_quantity_and_volume(
market_type: MarketType,
pair: &str,
price: f64,
quantity: f64,
) -> (f64, f64) {
if market_type == MarketType::LinearSwap {
let base = {
let slash_pos = pair.find('/').unwrap();
&pair[..slash_pos]
};
let contract_value = LINEAR_SWAP_MAPPING.get(base).unwrap();
let real_quantity = contract_value * quantity;
(real_quantity, real_quantity * price)
} else if market_type == MarketType::InverseSwap {
let volume = quantity;
(volume / price, volume)
} else {
panic!("Unknown market_type {}", market_type);
}
}
pub(crate) fn parse_trade(market_type: MarketType, msg: &str) -> Result<Vec<TradeMsg>> {
let ws_msg = serde_json::from_str::<ResponseMsg<SwapTradeMsg>>(&msg)?;
let trades: Vec<TradeMsg> = ws_msg
.data
.into_iter()
.map(|raw_trade| {
let mut trade = TradeMsg {
exchange: EXCHANGE_NAME.to_string(),
market_type,
symbol: raw_trade.instrument_id.clone(),
pair: crypto_pair::normalize_pair(&raw_trade.instrument_id, EXCHANGE_NAME).unwrap(),
msg_type: MessageType::Trade,
timestamp: raw_trade.timestamp.parse::<i64>().unwrap(),
price: raw_trade.price.parse::<f64>().unwrap(),
quantity: raw_trade.size.parse::<f64>().unwrap(),
volume: 0.0,
side: if raw_trade.side == "sell" {
TradeSide::Sell
} else {
TradeSide::Buy
},
trade_id: raw_trade.timestamp.to_string(),
raw: serde_json::to_value(&raw_trade).unwrap(),
};
let (quantity, volume) =
calc_quantity_and_volume(market_type, &trade.pair, trade.price, trade.quantity);
trade.quantity = quantity;
trade.volume = volume;
trade
})
.collect();
Ok(trades)
}