mod utils;
const EXCHANGE_NAME: &str = "huobi";
#[cfg(test)]
mod trade {
use super::EXCHANGE_NAME;
use crypto_market_type::MarketType;
use crypto_message::TradeSide;
use crypto_msg_parser::{extract_symbol, extract_timestamp, parse_trade, round};
#[test]
fn spot() {
let raw_msg = r#"{"ch":"market.btcusdt.trade.detail","ts":1616243199157,"tick":{"id":123140716701,"ts":1616243199156,"data":[{"id":123140716701236887569077664,"ts":1616243199156,"tradeId":102357140867,"amount":1.98E-4,"price":58911.07,"direction":"sell"}]}}"#;
let trade = &parse_trade(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()[0];
crate::utils::check_trade_fields(
EXCHANGE_NAME,
MarketType::Spot,
"BTC/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap(),
trade,
raw_msg,
);
assert_eq!(
1616243199157,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap()
);
assert_eq!(trade.quantity_base, 1.98E-4);
assert_eq!(trade.side, TradeSide::Sell);
}
#[test]
fn inverse_future() {
let raw_msg = r#"{"ch":"market.BTC_CQ.trade.detail","ts":1616231995793,"tick":{"id":128974648797,"ts":1616231995768,"data":[{"amount":2,"quantity":0.0031859832031779545255059460801016711,"ts":1616231995768,"id":1289746487970000,"price":62774.97,"direction":"buy"}]}}"#;
let trade = &parse_trade(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap()[0];
crate::utils::check_trade_fields(
EXCHANGE_NAME,
MarketType::InverseFuture,
"BTC/USD".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap(),
trade,
raw_msg,
);
assert_eq!(trade.quantity_base, 200.0 / 62774.97);
assert_eq!(trade.quantity_quote, 200.0);
assert_eq!(trade.quantity_contract, Some(2.0));
assert_eq!(trade.side, TradeSide::Buy);
let raw_msg = r#"{"ch":"market.ETH_CQ.trade.detail","ts":1616269629976,"tick":{"id":128632765054,"ts":1616269629958,"data":[{"amount":2,"quantity":0.0100143605930904917651912843016886215,"ts":1616269629958,"id":1286327650540000,"price":1997.132,"direction":"sell"}]}}"#;
let trade = &parse_trade(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap()[0];
crate::utils::check_trade_fields(
EXCHANGE_NAME,
MarketType::InverseFuture,
"ETH/USD".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap(),
trade,
raw_msg,
);
assert_eq!(
1616269629976,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap()
);
assert_eq!(trade.quantity_base, 20.0 / 1997.132);
assert_eq!(trade.quantity_quote, 20.0);
assert_eq!(trade.quantity_contract, Some(2.0));
assert_eq!(trade.side, TradeSide::Sell);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"ch":"market.BTC-USD.trade.detail","ts":1616233683377,"tick":{"id":84230699705,"ts":1616233683352,"data":[{"amount":6,"quantity":0.0102273366481267780650901795408948579,"ts":1616233683352,"id":842306997050000,"price":58666.3,"direction":"buy"}]}}"#;
let trade = &parse_trade(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()[0];
crate::utils::check_trade_fields(
EXCHANGE_NAME,
MarketType::InverseSwap,
"BTC/USD".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap(),
trade,
raw_msg,
);
assert_eq!(trade.quantity_base, 600.0 / 58666.3);
assert_eq!(trade.quantity_quote, 600.0);
assert_eq!(trade.quantity_contract, Some(6.0));
assert_eq!(trade.side, TradeSide::Buy);
let raw_msg = r#"{"ch":"market.ETH-USD.trade.detail","ts":1616269812566,"tick":{"id":79855942906,"ts":1616269812548,"data":[{"amount":346,"quantity":1.871099622535394066559231659438237489,"ts":1616269812548,"id":798559429060000,"price":1849.18,"direction":"sell"}]}}"#;
let trade = &parse_trade(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()[0];
crate::utils::check_trade_fields(
EXCHANGE_NAME,
MarketType::InverseSwap,
"ETH/USD".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap(),
trade,
raw_msg,
);
assert_eq!(
1616269812566,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(trade.quantity_base, 3460.0 / 1849.18);
assert_eq!(trade.quantity_quote, 3460.0);
assert_eq!(trade.quantity_contract, Some(346.0));
assert_eq!(trade.side, TradeSide::Sell);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"ch":"market.BTC-USDT.trade.detail","ts":1616233478594,"tick":{"id":22419995164,"ts":1616233478583,"data":[{"amount":40,"quantity":0.04,"trade_turnover":2350.796,"ts":1616233478583,"id":224199951640000,"price":58769.9,"direction":"sell"}]}}"#;
let trade = &parse_trade(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()[0];
crate::utils::check_trade_fields(
EXCHANGE_NAME,
MarketType::LinearSwap,
"BTC/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(),
trade,
raw_msg,
);
assert_eq!(
1616233478594,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(trade.quantity_base, 0.04);
assert_eq!(trade.quantity_quote, 2350.796);
assert_eq!(trade.quantity_contract, Some(40.0));
assert_eq!(trade.side, TradeSide::Sell);
let raw_msg = r#"{"ch":"market.ETH-USDT.trade.detail","ts":1616270565862,"tick":{"id":19056652696,"ts":1616270565838,"data":[{"amount":18,"quantity":0.18,"trade_turnover":332.487,"ts":1616270565838,"id":190566526960000,"price":1847.15,"direction":"sell"}]}}"#;
let trade = &parse_trade(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()[0];
crate::utils::check_trade_fields(
EXCHANGE_NAME,
MarketType::LinearSwap,
"ETH/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(),
trade,
raw_msg,
);
assert_eq!(trade.quantity_base, 0.18);
assert_eq!(trade.quantity_quote, 332.487);
assert_eq!(trade.quantity_contract, Some(18.0));
assert_eq!(trade.side, TradeSide::Sell);
}
#[test]
fn linear_swap_2() {
let raw_msg = r#"{"ch":"market.PEOPLE-USDT.trade.detail","ts":1677643151579,"tick":{"id":100000023131161,"ts":1677643151577,"data":[{"amount":308,"quantity":3080.000000000000000000,"ts":1677643151577,"id":1000000231311610000,"price":0.02645,"direction":"buy"}]}}"#;
let trade = &parse_trade(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()[0];
crate::utils::check_trade_fields(
EXCHANGE_NAME,
MarketType::LinearSwap,
"PEOPLE/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(),
trade,
raw_msg,
);
assert_eq!(
1677643151579,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(trade.timestamp, 1677643151577);
assert_eq!(trade.price, 0.02645);
assert_eq!(trade.quantity_base, 3080.0);
assert_eq!(trade.quantity_quote, round(0.02645 * 3080.0));
assert_eq!(trade.quantity_contract, Some(308.0));
assert_eq!(trade.side, TradeSide::Buy);
}
#[test]
fn linear_option() {
let raw_msg = r#"{"ch":"market.BTC-USDT-210326-C-32000.trade.detail","ts":1616246303142,"tick":{"id":674495368,"ts":1616246303133,"data":[{"amount":36,"quantity":0.036,"trade_turnover":971.69976,"ts":1616246303133,"id":6744953680000,"price":26991.66,"direction":"buy"},{"amount":42,"quantity":0.042,"trade_turnover":1134,"ts":1616246303133,"id":6744953680001,"price":27000,"direction":"buy"}]}}"#;
let trades = &parse_trade(EXCHANGE_NAME, MarketType::EuropeanOption, raw_msg).unwrap();
assert_eq!(trades.len(), 2);
for trade in trades.iter() {
crate::utils::check_trade_fields(
EXCHANGE_NAME,
MarketType::EuropeanOption,
"BTC/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::EuropeanOption, raw_msg).unwrap(),
trade,
raw_msg,
);
}
assert_eq!(
1616246303142,
extract_timestamp(EXCHANGE_NAME, MarketType::EuropeanOption, raw_msg).unwrap().unwrap()
);
assert_eq!(trades[0].quantity_base, 0.036);
assert_eq!(trades[0].quantity_quote, 971.69976);
assert_eq!(trades[0].quantity_contract, Some(36.0));
assert_eq!(trades[0].side, TradeSide::Buy);
assert_eq!(trades[1].quantity_base, 0.042);
assert_eq!(trades[1].quantity_quote, 1134.0);
assert_eq!(trades[1].quantity_contract, Some(42.0));
assert_eq!(trades[1].side, TradeSide::Buy);
}
}
#[cfg(test)]
mod funding_rate {
use super::EXCHANGE_NAME;
use crypto_market_type::MarketType;
use crypto_msg_parser::{extract_symbol, extract_timestamp, parse_funding_rate};
#[test]
fn inverse_swap() {
let raw_msg = r#"{"op":"notify","topic":"public.BTC-USD.funding_rate","ts":1617309842839,"data":[{"symbol":"BTC","contract_code":"BTC-USD","fee_asset":"BTC","funding_time":"1617309840000","funding_rate":"0.000624180443735412","estimated_rate":"0.000807076648698898","settlement_time":"1617321600000"}]}"#;
let funding_rates =
&parse_funding_rate(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg, None).unwrap();
assert_eq!(funding_rates.len(), 1);
for rate in funding_rates.iter() {
crate::utils::check_funding_rate_fields(
EXCHANGE_NAME,
MarketType::InverseSwap,
rate,
raw_msg,
);
}
assert_eq!(
"BTC-USD",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
assert_eq!(
1617309842839,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(funding_rates[0].pair, "BTC/USD".to_string());
assert_eq!(funding_rates[0].funding_rate, 0.000624180443735412);
assert_eq!(funding_rates[0].estimated_rate, Some(0.000807076648698898));
assert_eq!(funding_rates[0].funding_time, 1617321600000);
assert_eq!(funding_rates[0].timestamp, 1617309842839);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"op":"notify","topic":"public.BTC-USDT.funding_rate","ts":1617309787271,"data":[{"symbol":"BTC","contract_code":"BTC-USDT","fee_asset":"USDT","funding_time":"1617309780000","funding_rate":"0.000754108135233895","estimated_rate":"0.000429934303518805","settlement_time":"1617321600000"}]}"#;
let funding_rates =
&parse_funding_rate(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, None).unwrap();
assert_eq!(funding_rates.len(), 1);
for rate in funding_rates.iter() {
crate::utils::check_funding_rate_fields(
EXCHANGE_NAME,
MarketType::LinearSwap,
rate,
raw_msg,
);
}
assert_eq!(
"BTC-USDT",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
assert_eq!(
1617309787271,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(funding_rates[0].pair, "BTC/USDT".to_string());
assert_eq!(funding_rates[0].funding_rate, 0.000754108135233895);
assert_eq!(funding_rates[0].estimated_rate, Some(0.000429934303518805));
assert_eq!(funding_rates[0].funding_time, 1617321600000);
assert_eq!(funding_rates[0].timestamp, 1617309787271);
}
#[test]
fn all() {
let raw_msg = r#"{"op":"notify","topic":"public.*.funding_rate","ts":1654174017332,"data":[{"symbol":"BTC","contract_code":"BTC-USD","fee_asset":"BTC","funding_time":"1654173960000","funding_rate":"0.000046774664737679","estimated_rate":"-0.000042194357938054","settlement_time":"1654185600000"},{"symbol":"ETH","contract_code":"ETH-USD","fee_asset":"ETH","funding_time":"1654173960000","funding_rate":"-0.000050627986553411","estimated_rate":"0.000074887269002104","settlement_time":"1654185600000"}]}"#;
let funding_rates =
&parse_funding_rate(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg, None).unwrap();
assert_eq!(funding_rates.len(), 2);
for rate in funding_rates.iter() {
crate::utils::check_funding_rate_fields(
EXCHANGE_NAME,
MarketType::InverseSwap,
rate,
raw_msg,
);
}
assert_eq!("ALL", extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap());
assert_eq!(
1654174017332,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(funding_rates[0].pair, "BTC/USD".to_string());
assert_eq!(funding_rates[0].funding_rate, 0.000046774664737679);
assert_eq!(funding_rates[0].estimated_rate, Some(-0.000042194357938054));
assert_eq!(funding_rates[0].funding_time, 1654185600000);
assert_eq!(funding_rates[0].timestamp, 1654174017332);
assert_eq!(funding_rates[1].pair, "ETH/USD".to_string());
assert_eq!(funding_rates[1].funding_rate, -0.000050627986553411);
assert_eq!(funding_rates[1].estimated_rate, Some(0.000074887269002104));
assert_eq!(funding_rates[1].funding_time, 1654185600000);
assert_eq!(funding_rates[1].timestamp, 1654174017332);
}
}
#[cfg(test)]
mod l2_event {
use super::EXCHANGE_NAME;
use crypto_market_type::MarketType;
use crypto_msg_parser::{extract_symbol, extract_timestamp, parse_l2, round};
use crypto_msg_type::MessageType;
#[test]
fn spot_update() {
let raw_msg = r#"{"ch":"market.btcusdt.mbp.20","ts":1622707662703,"tick":{"seqNum":129803485567,"prevSeqNum":129803485424,"bids":[[38765.39,0.0],[38762.87,0.009708]],"asks":[[38762.88,0.102302]]}}"#;
let orderbook = &parse_l2(EXCHANGE_NAME, MarketType::Spot, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 1);
assert_eq!(orderbook.bids.len(), 2);
assert!(!orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::Spot,
MessageType::L2Event,
"BTC/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1622707662703,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1622707662703);
assert_eq!(orderbook.seq_id, Some(129803485567));
assert_eq!(orderbook.prev_seq_id, Some(129803485424));
assert_eq!(orderbook.asks[0].price, 38762.88);
assert_eq!(orderbook.asks[0].quantity_base, 0.102302);
assert_eq!(orderbook.asks[0].quantity_quote, 38762.88 * 0.102302);
assert_eq!(orderbook.bids[0].price, 38765.39);
assert_eq!(orderbook.bids[0].quantity_base, 0.0);
assert_eq!(orderbook.bids[0].quantity_quote, 0.0);
assert_eq!(orderbook.bids[1].price, 38762.87);
assert_eq!(orderbook.bids[1].quantity_base, 0.009708);
assert_eq!(orderbook.bids[1].quantity_quote, 38762.87 * 0.009708);
let raw_msg = r#"{"ch":"market.btcusdt.mbp.20","ts":1634601197516,"tick":{"seqNum":140059393690,"prevSeqNum":140059393689,"asks":[[61945.07,5.33E-4]]}}"#;
let orderbook = &parse_l2(EXCHANGE_NAME, MarketType::Spot, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 1);
assert_eq!(orderbook.bids.len(), 0);
assert!(!orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::Spot,
MessageType::L2Event,
"BTC/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1634601197516,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1634601197516);
assert_eq!(orderbook.asks[0].price, 61945.07);
assert_eq!(orderbook.asks[0].quantity_base, 0.000533);
assert_eq!(orderbook.asks[0].quantity_quote, 61945.07 * 0.000533);
}
#[test]
fn inverse_future_snapshot() {
let raw_msg = r#"{"ch":"market.BTC_CQ.depth.size_150.high_freq","tick":{"asks":[[38884.91,652],[38886.32,21],[38887.88,4]],"bids":[[38884.9,6],[38883.86,6],[38880.25,3]],"ch":"market.BTC_CQ.depth.size_150.high_freq","event":"snapshot","id":138216299603,"mrid":138216299603,"ts":1622708089134,"version":1223482159},"ts":1622708089134}"#;
let orderbook =
&parse_l2(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 3);
assert_eq!(orderbook.bids.len(), 3);
assert!(orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::InverseFuture,
MessageType::L2Event,
"BTC/USD".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1622708089134,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1622708089134);
assert_eq!(orderbook.seq_id, Some(138216299603));
assert_eq!(orderbook.asks[0].price, 38884.91);
assert_eq!(orderbook.asks[0].quantity_base, 65200.0 / 38884.91);
assert_eq!(orderbook.asks[0].quantity_quote, 65200.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 652.0);
assert_eq!(orderbook.asks[2].price, 38887.88);
assert_eq!(orderbook.asks[2].quantity_base, 400.0 / 38887.88);
assert_eq!(orderbook.asks[2].quantity_quote, 400.0);
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 4.0);
assert_eq!(orderbook.bids[0].price, 38884.9);
assert_eq!(orderbook.bids[0].quantity_base, 600.0 / 38884.9);
assert_eq!(orderbook.bids[0].quantity_quote, 600.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 6.0);
assert_eq!(orderbook.bids[2].price, 38880.25);
assert_eq!(orderbook.bids[2].quantity_base, 300.0 / 38880.25);
assert_eq!(orderbook.bids[2].quantity_quote, 300.0);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 3.0);
}
#[test]
fn inverse_future_update() {
let raw_msg = r#"{"ch":"market.BTC_CQ.depth.size_150.high_freq","tick":{"asks":[[38939.82,10],[38958.06,100],[38973.97,0]],"bids":[[38932.53,200],[38926.08,0],[38912.29,0]],"ch":"market.BTC_CQ.depth.size_150.high_freq","event":"update","id":138219575176,"mrid":138219575176,"ts":1622711041458,"version":1223606224},"ts":1622711041458}"#;
let orderbook =
&parse_l2(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 3);
assert_eq!(orderbook.bids.len(), 3);
assert!(!orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::InverseFuture,
MessageType::L2Event,
"BTC/USD".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1622711041458,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1622711041458);
assert_eq!(orderbook.seq_id, Some(138219575176));
assert_eq!(orderbook.asks[0].price, 38939.82);
assert_eq!(orderbook.asks[0].quantity_base, 1000.0 / 38939.82);
assert_eq!(orderbook.asks[0].quantity_quote, 1000.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 10.0);
assert_eq!(orderbook.asks[2].price, 38973.97);
assert_eq!(orderbook.asks[2].quantity_base, 0.0);
assert_eq!(orderbook.asks[2].quantity_quote, 0.0);
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 0.0);
assert_eq!(orderbook.bids[0].price, 38932.53);
assert_eq!(orderbook.bids[0].quantity_base, 20000.0 / 38932.53);
assert_eq!(orderbook.bids[0].quantity_quote, 20000.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 200.0);
assert_eq!(orderbook.bids[2].price, 38912.29);
assert_eq!(orderbook.bids[2].quantity_base, 0.0);
assert_eq!(orderbook.bids[2].quantity_quote, 0.0);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 0.0);
}
#[test]
fn inverse_future_snapshot_2() {
let raw_msg = r#"{"ch":"market.DOT_CW.depth.size_20.high_freq","tick":{"asks":[[9.9252,1569],[9.9301,1964],[10.0029,44]],"bids":null,"ch":"market.DOT_CW.depth.size_20.high_freq","event":"snapshot","id":222100052218419,"mrid":222100052218419,"ts":1653033431770,"version":865562932},"ts":1653033431770}"#;
let orderbook =
&parse_l2(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 3);
assert_eq!(orderbook.bids.len(), 0);
assert!(orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::InverseFuture,
MessageType::L2Event,
"DOT/USD".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
"DOT_CW",
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap()
);
assert_eq!(
1653033431770,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1653033431770);
assert_eq!(orderbook.seq_id, Some(222100052218419));
assert_eq!(orderbook.asks[0].price, 9.9252);
assert_eq!(orderbook.asks[0].quantity_base, 15690.0 / 9.9252);
assert_eq!(orderbook.asks[0].quantity_quote, 15690.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 1569.0);
assert_eq!(orderbook.asks[2].price, 10.0029);
assert_eq!(orderbook.asks[2].quantity_base, 440.0 / 10.0029);
assert_eq!(orderbook.asks[2].quantity_quote, 440.0);
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 44.0);
}
#[test]
fn inverse_swap_snapshot() {
let raw_msg = r#"{"ch":"market.BTC-USD.depth.size_150.high_freq","tick":{"asks":[[38888,9949],[38888.1,1],[38888.2,1]],"bids":[[38887.9,3832],[38887.8,4],[38887.7,3]],"ch":"market.BTC-USD.depth.size_150.high_freq","event":"snapshot","id":99893955238,"mrid":99893955238,"ts":1622711365595,"version":1300632701},"ts":1622711365595}"#;
let orderbook =
&parse_l2(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 3);
assert_eq!(orderbook.bids.len(), 3);
assert!(orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::InverseSwap,
MessageType::L2Event,
"BTC/USD".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1622711365595,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1622711365595);
assert_eq!(orderbook.seq_id, Some(99893955238));
assert_eq!(orderbook.asks[0].price, 38888.0);
assert_eq!(orderbook.asks[0].quantity_base, 994900.0 / 38888.0);
assert_eq!(orderbook.asks[0].quantity_quote, 994900.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 9949.0);
assert_eq!(orderbook.asks[2].price, 38888.2);
assert_eq!(orderbook.asks[2].quantity_base, 100.0 / 38888.2);
assert_eq!(orderbook.asks[2].quantity_quote, 100.0);
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 1.0);
assert_eq!(orderbook.bids[0].price, 38887.9);
assert_eq!(orderbook.bids[0].quantity_base, 383200.0 / 38887.9);
assert_eq!(orderbook.bids[0].quantity_quote, 383200.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 3832.0);
assert_eq!(orderbook.bids[2].price, 38887.7);
assert_eq!(orderbook.bids[2].quantity_base, 300.0 / 38887.7);
assert_eq!(orderbook.bids[2].quantity_quote, 300.0);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 3.0);
}
#[test]
fn inverse_swap_update() {
let raw_msg = r#"{"ch":"market.BTC-USD.depth.size_150.high_freq","tick":{"asks":[[38895.7,1635]],"bids":[[38880.6,0],[38868.2,50]],"ch":"market.BTC-USD.depth.size_150.high_freq","event":"update","id":99893958868,"mrid":99893958868,"ts":1622711368355,"version":1300632845},"ts":1622711368355}"#;
let orderbook =
&parse_l2(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 1);
assert_eq!(orderbook.bids.len(), 2);
assert!(!orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::InverseSwap,
MessageType::L2Event,
"BTC/USD".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1622711368355,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1622711368355);
assert_eq!(orderbook.seq_id, Some(99893958868));
assert_eq!(orderbook.asks[0].price, 38895.7);
assert_eq!(orderbook.asks[0].quantity_base, 163500.0 / 38895.7);
assert_eq!(orderbook.asks[0].quantity_quote, 163500.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 1635.0);
assert_eq!(orderbook.bids[0].price, 38880.6);
assert_eq!(orderbook.bids[0].quantity_base, 0.0);
assert_eq!(orderbook.bids[0].quantity_quote, 0.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 0.0);
assert_eq!(orderbook.bids[1].price, 38868.2);
assert_eq!(orderbook.bids[1].quantity_base, 5000.0 / 38868.2);
assert_eq!(orderbook.bids[1].quantity_quote, 5000.0);
assert_eq!(orderbook.bids[1].quantity_contract.unwrap(), 50.0);
}
#[test]
fn linear_swap_snapshot() {
let raw_msg = r#"{"ch":"market.BTC-USDT.depth.size_150.high_freq","tick":{"asks":[[39055,19345],[39056.8,1200],[39057.5,85]],"bids":[[39054.9,4754],[39054.8,1],[39054.7,1]],"ch":"market.BTC-USDT.depth.size_150.high_freq","event":"snapshot","id":39536665398,"mrid":39536665398,"ts":1622711946534,"version":709648689},"ts":1622711946534}"#;
let orderbook = &parse_l2(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 3);
assert_eq!(orderbook.bids.len(), 3);
assert!(orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::LinearSwap,
MessageType::L2Event,
"BTC/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1622711946534,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1622711946534);
assert_eq!(orderbook.seq_id, Some(39536665398));
assert_eq!(orderbook.asks[0].price, 39055.0);
assert_eq!(orderbook.asks[0].quantity_base, 19.345);
assert_eq!(orderbook.asks[0].quantity_quote, 39055.0 * 19.345);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 19345.0);
assert_eq!(orderbook.asks[2].price, 39057.5);
assert_eq!(orderbook.asks[2].quantity_base, 0.085);
assert_eq!(orderbook.asks[2].quantity_quote, round(39057.5 * 0.085));
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 85.0);
assert_eq!(orderbook.bids[0].price, 39054.9);
assert_eq!(orderbook.bids[0].quantity_base, 4.754);
assert_eq!(orderbook.bids[0].quantity_quote, round(39054.9 * 4.754));
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 4754.0);
assert_eq!(orderbook.bids[2].price, 39054.7);
assert_eq!(orderbook.bids[2].quantity_base, 0.001);
assert_eq!(orderbook.bids[2].quantity_quote, 39054.7 * 0.001);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 1.0);
}
#[test]
fn linear_swap_update() {
let raw_msg = r#"{"ch":"market.BTC-USDT.depth.size_150.high_freq","tick":{"asks":[[39055,16634],[39060.1,0]],"bids":[[39050.8,40]],"ch":"market.BTC-USDT.depth.size_150.high_freq","event":"update","id":39536668357,"mrid":39536668357,"ts":1622711948514,"version":709648808},"ts":1622711948514}"#;
let orderbook = &parse_l2(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 2);
assert_eq!(orderbook.bids.len(), 1);
assert!(!orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::LinearSwap,
MessageType::L2Event,
"BTC/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1622711948514,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1622711948514);
assert_eq!(orderbook.seq_id, Some(39536668357));
assert_eq!(orderbook.asks[0].price, 39055.0);
assert_eq!(orderbook.asks[0].quantity_base, 16.634);
assert_eq!(orderbook.asks[0].quantity_quote, 39055.0 * 16.634);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 16634.0);
assert_eq!(orderbook.asks[1].price, 39060.1);
assert_eq!(orderbook.asks[1].quantity_base, 0.0);
assert_eq!(orderbook.asks[1].quantity_quote, 0.0);
assert_eq!(orderbook.asks[1].quantity_contract.unwrap(), 0.0);
assert_eq!(orderbook.bids[0].price, 39050.8);
assert_eq!(orderbook.bids[0].quantity_base, 0.04);
assert_eq!(orderbook.bids[0].quantity_quote, round(39050.8 * 0.04));
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 40.0);
}
}
#[cfg(test)]
mod l2_topk {
use super::EXCHANGE_NAME;
use crypto_market_type::MarketType;
use crypto_msg_parser::{extract_symbol, extract_timestamp, parse_l2_topk, round};
use crypto_msg_type::MessageType;
#[test]
fn spot() {
let raw_msg = r#"{"ch":"market.btcusdt.depth.step1","ts":1653985338657,"tick":{"bids":[[31638.9,2.436837],[31638.5,0.349474],[31637.9,0.862589]],"asks":[[31639.0,1.062193],[31642.4,0.381939],[31642.7,0.190963]],"version":155386874272,"ts":1653985338000}}"#;
let orderbook = &parse_l2_topk(EXCHANGE_NAME, MarketType::Spot, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 3);
assert_eq!(orderbook.bids.len(), 3);
assert!(orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::Spot,
MessageType::L2TopK,
"BTC/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1653985338657,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1653985338657);
assert_eq!(orderbook.seq_id, None);
assert_eq!(orderbook.prev_seq_id, None);
assert_eq!(orderbook.asks[0].price, 31639.0);
assert_eq!(orderbook.asks[0].quantity_base, 1.062193);
assert_eq!(orderbook.asks[0].quantity_quote, 31639.0 * 1.062193);
assert_eq!(orderbook.asks[0].quantity_contract, None);
assert_eq!(orderbook.asks[2].price, 31642.7);
assert_eq!(orderbook.asks[2].quantity_base, 0.190963);
assert_eq!(orderbook.asks[2].quantity_quote, 31642.7 * 0.190963);
assert_eq!(orderbook.asks[2].quantity_contract, None);
assert_eq!(orderbook.bids[0].price, 31638.9);
assert_eq!(orderbook.bids[0].quantity_base, 2.436837);
assert_eq!(orderbook.bids[0].quantity_quote, 31638.9 * 2.436837);
assert_eq!(orderbook.bids[0].quantity_contract, None);
assert_eq!(orderbook.bids[2].price, 31637.9);
assert_eq!(orderbook.bids[2].quantity_base, 0.862589);
assert_eq!(orderbook.bids[2].quantity_quote, 31637.9 * 0.862589);
assert_eq!(orderbook.bids[2].quantity_contract, None);
}
#[test]
fn inverse_future() {
let raw_msg = r#"{"ch":"market.BTC_CQ.depth.step7","ts":1653986872201,"tick":{"mrid":222601050340438,"id":1653986872,"bids":[[31676.53,42],[31676,4],[31675.98,800]],"asks":[[31676.54,1],[31676.95,1],[31676.96,215]],"ts":1653986872197,"version":1653986872,"ch":"market.BTC_CQ.depth.step7"}}"#;
let orderbook =
&parse_l2_topk(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 3);
assert_eq!(orderbook.bids.len(), 3);
assert!(orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::InverseFuture,
MessageType::L2TopK,
"BTC/USD".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1653986872201,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1653986872201);
assert_eq!(orderbook.seq_id, Some(222601050340438));
assert_eq!(orderbook.prev_seq_id, None);
assert_eq!(orderbook.asks[0].price, 31676.54);
assert_eq!(orderbook.asks[0].quantity_base, 100.0 / 31676.54);
assert_eq!(orderbook.asks[0].quantity_quote, 100.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 1.0);
assert_eq!(orderbook.asks[2].price, 31676.96);
assert_eq!(orderbook.asks[2].quantity_base, 21500.0 / 31676.96);
assert_eq!(orderbook.asks[2].quantity_quote, 21500.0);
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 215.0);
assert_eq!(orderbook.bids[0].price, 31676.53);
assert_eq!(orderbook.bids[0].quantity_base, 4200.0 / 31676.53);
assert_eq!(orderbook.bids[0].quantity_quote, 4200.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 42.0);
assert_eq!(orderbook.bids[2].price, 31675.98);
assert_eq!(orderbook.bids[2].quantity_base, 80000.0 / 31675.98);
assert_eq!(orderbook.bids[2].quantity_quote, 80000.0);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 800.0);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"ch":"market.BTC-USD.depth.step7","ts":1653988195290,"tick":{"mrid":136445301207,"id":1653988195,"bids":[[31565.4,564],[31564.1,7],[31563.4,200]],"asks":[[31565.5,2749],[31566.6,95],[31567,65]],"ts":1653988195288,"version":1653988195,"ch":"market.BTC-USD.depth.step7"}}"#;
let orderbook =
&parse_l2_topk(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 3);
assert_eq!(orderbook.bids.len(), 3);
assert!(orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::InverseSwap,
MessageType::L2TopK,
"BTC/USD".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1653988195290,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1653988195290);
assert_eq!(orderbook.seq_id, Some(136445301207));
assert_eq!(orderbook.prev_seq_id, None);
assert_eq!(orderbook.asks[0].price, 31565.5);
assert_eq!(orderbook.asks[0].quantity_base, 274900.0 / 31565.5);
assert_eq!(orderbook.asks[0].quantity_quote, 274900.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 2749.0);
assert_eq!(orderbook.asks[2].price, 31567.0);
assert_eq!(orderbook.asks[2].quantity_base, 6500.0 / 31567.0);
assert_eq!(orderbook.asks[2].quantity_quote, 6500.0);
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 65.0);
assert_eq!(orderbook.bids[0].price, 31565.4);
assert_eq!(orderbook.bids[0].quantity_base, 56400.0 / 31565.4);
assert_eq!(orderbook.bids[0].quantity_quote, 56400.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 564.0);
assert_eq!(orderbook.bids[2].price, 31563.4);
assert_eq!(orderbook.bids[2].quantity_base, 20000.0 / 31563.4);
assert_eq!(orderbook.bids[2].quantity_quote, 20000.0);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 200.0);
}
#[test]
fn inverse_swap_2() {
let raw_msg = r#"{"ch":"market.ANT-USD.depth.step7","ts":1653868800233,"tick":{"mrid":68112277468,"id":1653868800,"ts":1653868800233,"version":1653868800,"ch":"market.ANT-USD.depth.step7"}}"#;
let orderbook =
&parse_l2_topk(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg, None).unwrap()[0];
assert!(orderbook.asks.is_empty());
assert!(orderbook.bids.is_empty());
assert!(orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::InverseSwap,
MessageType::L2TopK,
"ANT/USD".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1653868800233,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1653868800233);
assert_eq!(orderbook.seq_id, Some(68112277468));
assert_eq!(orderbook.prev_seq_id, None);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"ch":"market.BTC-USDT.depth.step7","ts":1653988444928,"tick":{"mrid":108706801887,"id":1653988444,"bids":[[31589.9,2397],[31589.6,500],[31588.6,1]],"asks":[[31590,3053],[31590.5,6],[31590.6,692]],"ts":1653988444925,"version":1653988444,"ch":"market.BTC-USDT.depth.step7"}}"#;
let orderbook =
&parse_l2_topk(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 3);
assert_eq!(orderbook.bids.len(), 3);
assert!(orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::LinearSwap,
MessageType::L2TopK,
"BTC/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1653988444928,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1653988444928);
assert_eq!(orderbook.seq_id, Some(108706801887));
assert_eq!(orderbook.prev_seq_id, None);
assert_eq!(orderbook.asks[0].price, 31590.0);
assert_eq!(orderbook.asks[0].quantity_base, 3.053);
assert_eq!(orderbook.asks[0].quantity_quote, 31590.0 * 3.053);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 3053.0);
assert_eq!(orderbook.asks[2].price, 31590.6);
assert_eq!(orderbook.asks[2].quantity_base, 0.692);
assert_eq!(orderbook.asks[2].quantity_quote, round(31590.6 * 0.692));
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 692.0);
assert_eq!(orderbook.bids[0].price, 31589.9);
assert_eq!(orderbook.bids[0].quantity_base, 2.397);
assert_eq!(orderbook.bids[0].quantity_quote, round(31589.9 * 2.397));
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 2397.0);
assert_eq!(orderbook.bids[2].price, 31588.6);
assert_eq!(orderbook.bids[2].quantity_base, 0.001);
assert_eq!(orderbook.bids[2].quantity_quote, 31588.6 * 0.001);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 1.0);
}
#[test]
fn linear_swap_2() {
let raw_msg = r#"{"ch":"market.GST-USDT.depth.step7","ts":1651233614936,"tick":{"mrid":34526821266,"id":1651233614,"asks":[[7.5042,4218],[7.7385,194],[7.7451,67],[7.7484,281],[7.7517,439]],"ts":1651233614936,"version":1651233614,"ch":"market.GST-USDT.depth.step7"}}"#;
let orderbook =
&parse_l2_topk(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 5);
assert_eq!(orderbook.bids.len(), 0);
assert!(orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::LinearSwap,
MessageType::L2TopK,
"GST/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
"GST-USDT",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
assert_eq!(
1651233614936,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1651233614936);
assert_eq!(orderbook.seq_id, Some(34526821266));
assert_eq!(orderbook.prev_seq_id, None);
assert_eq!(orderbook.asks[0].price, 7.5042);
assert_eq!(orderbook.asks[0].quantity_base, 0.1 * 4218.0);
assert_eq!(orderbook.asks[0].quantity_quote, 0.1 * 4218.0 * 7.5042);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 4218.0);
assert_eq!(orderbook.asks[4].price, 7.7517);
assert_eq!(orderbook.asks[4].quantity_base, round(0.1 * 439.0));
assert_eq!(orderbook.asks[4].quantity_quote, round(7.7517 * 0.1 * 439.0));
assert_eq!(orderbook.asks[4].quantity_contract.unwrap(), 439.0);
}
}
#[cfg(test)]
mod bbo {
use super::EXCHANGE_NAME;
use crypto_market_type::MarketType;
use crypto_msg_parser::{extract_symbol, extract_timestamp, parse_bbo, round};
use crypto_msg_type::MessageType;
#[test]
fn spot() {
let raw_msg = r#"{"ch":"market.btcusdt.bbo","ts":1654031600066,"tick":{"seqId":155441231856,"ask":31764.09,"askSize":0.794873,"bid":31764.08,"bidSize":4.378544,"quoteTime":1654031600064,"symbol":"btcusdt"}}"#;
assert_eq!(
1654031600066,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap()
);
assert_eq!("btcusdt", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap());
let bbo_msg = &parse_bbo(EXCHANGE_NAME, MarketType::Spot, raw_msg, None).unwrap()[0];
assert_eq!(MessageType::BBO, bbo_msg.msg_type);
assert_eq!("btcusdt", bbo_msg.symbol);
assert_eq!(1654031600066, bbo_msg.timestamp);
assert_eq!(Some(155441231856), bbo_msg.id);
assert_eq!(31764.09, bbo_msg.ask_price);
assert_eq!(0.794873, bbo_msg.ask_quantity_base);
assert_eq!(31764.09 * 0.794873, bbo_msg.ask_quantity_quote);
assert_eq!(None, bbo_msg.ask_quantity_contract);
assert_eq!(31764.08, bbo_msg.bid_price);
assert_eq!(4.378544, bbo_msg.bid_quantity_base);
assert_eq!(31764.08 * 4.378544, bbo_msg.bid_quantity_quote);
assert_eq!(None, bbo_msg.bid_quantity_contract);
}
#[test]
fn inverse_future() {
let raw_msg = r#"{"ch":"market.BTC_CQ.bbo","ts":1654031781978,"tick":{"mrid":222601060251593,"id":1654031781,"bid":[31781.79,609],"ask":[31781.8,22],"ts":1654031781978,"version":222601060251593,"ch":"market.BTC_CQ.bbo"}}"#;
assert_eq!(
1654031781978,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC_CQ",
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap()
);
let bbo_msg =
&parse_bbo(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg, None).unwrap()[0];
assert_eq!(MessageType::BBO, bbo_msg.msg_type);
assert_eq!("BTC_CQ", bbo_msg.symbol);
assert_eq!(1654031781978, bbo_msg.timestamp);
assert_eq!(Some(222601060251593), bbo_msg.id);
assert_eq!(31781.8, bbo_msg.ask_price);
assert_eq!(2200.0 / 31781.8, bbo_msg.ask_quantity_base);
assert_eq!(2200.0, bbo_msg.ask_quantity_quote);
assert_eq!(Some(22.0), bbo_msg.ask_quantity_contract);
assert_eq!(31781.79, bbo_msg.bid_price);
assert_eq!(60900.0 / 31781.79, bbo_msg.bid_quantity_base);
assert_eq!(60900.0, bbo_msg.bid_quantity_quote);
assert_eq!(Some(609.0), bbo_msg.bid_quantity_contract);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"ch":"market.BTC-USD.bbo","ts":1654031818692,"tick":{"mrid":136465693726,"id":1654031818,"bid":[31753.2,2495],"ask":[31753.3,249],"ts":1654031818692,"version":136465693726,"ch":"market.BTC-USD.bbo"}}"#;
assert_eq!(
1654031818692,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-USD",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
let bbo_msg = &parse_bbo(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg, None).unwrap()[0];
assert_eq!(MessageType::BBO, bbo_msg.msg_type);
assert_eq!("BTC-USD", bbo_msg.symbol);
assert_eq!(1654031818692, bbo_msg.timestamp);
assert_eq!(Some(136465693726), bbo_msg.id);
assert_eq!(31753.3, bbo_msg.ask_price);
assert_eq!(24900.0 / 31753.3, bbo_msg.ask_quantity_base);
assert_eq!(24900.0, bbo_msg.ask_quantity_quote);
assert_eq!(Some(249.0), bbo_msg.ask_quantity_contract);
assert_eq!(31753.2, bbo_msg.bid_price);
assert_eq!(249500.0 / 31753.2, bbo_msg.bid_quantity_base);
assert_eq!(249500.0, bbo_msg.bid_quantity_quote);
assert_eq!(Some(2495.0), bbo_msg.bid_quantity_contract);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"ch":"market.BTC-USDT.bbo","ts":1654031855127,"tick":{"mrid":108746530167,"id":1654031855,"bid":[31784.1,5911],"ask":[31784.2,4],"ts":1654031855127,"version":108746530167,"ch":"market.BTC-USDT.bbo"}}"#;
assert_eq!(
1654031855127,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-USDT",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
let bbo_msg = &parse_bbo(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, None).unwrap()[0];
assert_eq!(MessageType::BBO, bbo_msg.msg_type);
assert_eq!("BTC-USDT", bbo_msg.symbol);
assert_eq!(1654031855127, bbo_msg.timestamp);
assert_eq!(Some(108746530167), bbo_msg.id);
assert_eq!(31784.2, bbo_msg.ask_price);
assert_eq!(0.004, bbo_msg.ask_quantity_base);
assert_eq!(round(31784.2 * 0.004), bbo_msg.ask_quantity_quote);
assert_eq!(Some(4.0), bbo_msg.ask_quantity_contract);
assert_eq!(31784.1, bbo_msg.bid_price);
assert_eq!(5.911, bbo_msg.bid_quantity_base);
assert_eq!(round(31784.1 * 5.911), bbo_msg.bid_quantity_quote);
assert_eq!(Some(5911.0), bbo_msg.bid_quantity_contract);
}
}
#[cfg(test)]
mod candlestick {
use super::EXCHANGE_NAME;
use crypto_market_type::MarketType;
use crypto_msg_parser::{extract_symbol, extract_timestamp, parse_candlestick};
#[test]
fn spot() {
let raw_msg = r#"{"ch":"market.btcusdt.kline.1min","ts":1654081322624,"tick":{"id":1654081320,"open":31545.71,"close":31545.72,"low":31545.71,"high":31545.72,"amount":0.015443758717188892,"vol":487.1844552,"count":4}}"#;
assert_eq!(
1654081322624,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap()
);
assert_eq!("btcusdt", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap());
let arr = parse_candlestick(EXCHANGE_NAME, MarketType::Spot, raw_msg, None).unwrap();
assert_eq!(1, arr.len());
let candlestick_msg = &arr[0];
assert_eq!("btcusdt", candlestick_msg.symbol);
assert_eq!(1654081322624, candlestick_msg.timestamp);
assert_eq!("1min", candlestick_msg.period);
assert_eq!(1654081320, candlestick_msg.begin_time);
assert_eq!(31545.71, candlestick_msg.open);
assert_eq!(31545.72, candlestick_msg.high);
assert_eq!(31545.71, candlestick_msg.low);
assert_eq!(31545.72, candlestick_msg.close);
assert_eq!(0.015443758717188892, candlestick_msg.volume);
assert_eq!(Some(487.1844552), candlestick_msg.quote_volume);
}
#[test]
fn inverse_future() {
let raw_msg = r#"{"ch":"market.BTC_CQ.kline.1min","ts":1654081396435,"tick":{"id":1654081380,"mrid":222601067490403,"open":31565.04,"close":31565.04,"high":31565.04,"low":31565.04,"amount":0.0063361237622382230467631278148229814,"vol":2,"count":1}}"#;
assert_eq!(
1654081396435,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC_CQ",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
let arr =
parse_candlestick(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg, None).unwrap();
assert_eq!(1, arr.len());
let candlestick_msg = &arr[0];
assert_eq!("BTC_CQ", candlestick_msg.symbol);
assert_eq!(1654081396435, candlestick_msg.timestamp);
assert_eq!("1min", candlestick_msg.period);
assert_eq!(1654081380, candlestick_msg.begin_time);
assert_eq!(31565.04, candlestick_msg.open);
assert_eq!(31565.04, candlestick_msg.high);
assert_eq!(31565.04, candlestick_msg.low);
assert_eq!(31565.04, candlestick_msg.close);
assert_eq!(0.006_336_123_762_238_223, candlestick_msg.volume);
assert_eq!(Some(200.0), candlestick_msg.quote_volume);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"ch":"market.BTC-USD.kline.1min","ts":1662710342762,"tick":{"id":1662710340,"mrid":139336967831,"open":20635.1,"close":20635.1,"high":20635.1,"low":20635.1,"amount":3.3050481945810778721692649902350848798,"vol":682,"count":5}}"#;
assert_eq!(
1662710342762,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-USD",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
let arr = parse_candlestick(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg, None).unwrap();
assert_eq!(1, arr.len());
let candlestick_msg = &arr[0];
assert_eq!("BTC-USD", candlestick_msg.symbol);
assert_eq!(1662710342762, candlestick_msg.timestamp);
assert_eq!("1min", candlestick_msg.period);
assert_eq!(1662710340, candlestick_msg.begin_time);
assert_eq!(20635.1, candlestick_msg.open);
assert_eq!(20635.1, candlestick_msg.high);
assert_eq!(20635.1, candlestick_msg.low);
assert_eq!(20635.1, candlestick_msg.close);
assert_eq!(3.305048194581078, candlestick_msg.volume);
assert_eq!(Some(68200.0), candlestick_msg.quote_volume);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"ch":"market.BTC-USDT.kline.1min","ts":1654081448870,"tick":{"id":1654081440,"mrid":108782988900,"open":31531.9,"close":31531.9,"high":31532,"low":31531.9,"amount":0.532,"vol":532,"trade_turnover":16774.9728,"count":5}}"#;
assert_eq!(
1654081448870,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-USDT",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
let arr = parse_candlestick(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, None).unwrap();
assert_eq!(1, arr.len());
let candlestick_msg = &arr[0];
assert_eq!("BTC-USDT", candlestick_msg.symbol);
assert_eq!(1654081448870, candlestick_msg.timestamp);
assert_eq!("1min", candlestick_msg.period);
assert_eq!(1654081440, candlestick_msg.begin_time);
assert_eq!(31531.9, candlestick_msg.open);
assert_eq!(31532.0, candlestick_msg.high);
assert_eq!(31531.9, candlestick_msg.low);
assert_eq!(31531.9, candlestick_msg.close);
assert_eq!(0.532, candlestick_msg.volume);
assert_eq!(Some(16774.9728), candlestick_msg.quote_volume);
}
}
#[cfg(test)]
mod ticker {
use super::EXCHANGE_NAME;
use crypto_market_type::MarketType;
use crypto_msg_parser::{extract_symbol, extract_timestamp};
#[test]
fn spot() {
let raw_msg = r#"{"ch":"market.btcusdt.detail","ts":1654164208520,"tick":{"id":311070770838,"low":29326.15,"high":31899.51,"open":31666.3,"close":29952.31,"vol":8.181588598785326E8,"amount":26897.159881877742,"version":311070770838,"count":699452}}"#;
assert_eq!(
1654164208520,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap()
);
assert_eq!("btcusdt", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap());
}
#[test]
fn inverse_future() {
let raw_msg = r#"{"ch":"market.BTC_CQ.detail","ts":1654164240700,"tick":{"id":1654164240,"mrid":222601084481815,"open":30723.59,"close":29936.45,"high":30723.59,"low":29301.65,"amount":12397.7225650589211059171392145260319091988,"vol":3753910,"count":46935,"ask":[29940.08,415],"bid":[29940.07,916]}}"#;
assert_eq!(
1654164240700,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC_CQ",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"ch":"market.BTC-USD.detail","ts":1654164360125,"tick":{"id":1654164360,"mrid":136520778365,"open":30694.1,"close":29925,"high":30694.9,"low":29258.1,"amount":13439.9875087391570765718450164053828468124,"vol":4074828,"count":39735,"ask":[29925.1,555],"bid":[29925,959]}}"#;
assert_eq!(
1654164360125,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-USD",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"ch":"market.BTC-USDT.detail","ts":1654164279373,"tick":{"id":1654164240,"mrid":108854811173,"open":30728.4,"close":29944.4,"high":30729.5,"low":29306.6,"amount":34473.406,"vol":34473406,"trade_turnover":1047364677.232,"count":203526,"ask":[29940.5,2138],"bid":[29940.4,3743]}}"#;
assert_eq!(
1654164279373,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-USDT",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
}
}
#[cfg(test)]
mod l2_snapshot {
use super::EXCHANGE_NAME;
use crypto_market_type::MarketType;
use crypto_msg_parser::{extract_symbol, extract_timestamp};
#[test]
fn spot() {
let raw_msg = r#"{"ch":"market.btcusdt.depth.step0","status":"ok","ts":1654253117316,"tick":{"bids":[[29805.62,0.309487],[29804.73,2.0E-4],[29804.43,0.030335],[29804.42,0.325215],[29802.06,0.03]],"asks":[[29805.63,1.650216],[29805.66,0.02902],[29807.73,2.0E-4],[29808.1,0.145506],[29808.74,0.420813]],"version":155671698426,"ts":1654253116701}}"#;
assert_eq!(
1654253117316,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap()
);
assert_eq!("btcusdt", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap());
}
#[test]
fn inverse_future() {
let raw_msg = r#"{"ch":"market.BTC_CQ.depth.step0","status":"ok","tick":{"asks":[[29799.58,2],[29802.55,216],[29802.79,9],[29803.64,2],[29804.19,20]],"bids":[[29795.25,24],[29795.24,1],[29793.3,2],[29792.15,19],[29792.14,400]],"ch":"market.BTC_CQ.depth.step0","id":1654253101,"mrid":222601100912603,"ts":1654253101500,"version":1654253101},"ts":1654253101541}"#;
assert_eq!(
1654253101541,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC_CQ",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"ch":"market.BTC-USD.depth.step0","status":"ok","tick":{"asks":[[29768.2,915],[29769.1,400],[29769.5,50],[29770.6,400],[29771,1036]],"bids":[[29768.1,516],[29768,1],[29767.4,150],[29767.1,25],[29765.5,218]],"ch":"market.BTC-USD.depth.step0","id":1654253101,"mrid":136558127685,"ts":1654253101089,"version":1654253101},"ts":1654253101098}"#;
assert_eq!(
1654253101098,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-USD",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"ch":"market.BTC-USDT.depth.step0","status":"ok","tick":{"asks":[[29796.8,4025],[29797.1,49],[29797.2,16],[29797.3,700],[29797.5,4]],"bids":[[29796.7,305],[29795.9,265],[29795.6,1],[29794.4,165],[29793.7,165]],"ch":"market.BTC-USDT.depth.step0","id":1654253113,"mrid":108917760661,"ts":1654253113226,"version":1654253113},"ts":1654253113251}"#;
assert_eq!(
1654253113251,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-USDT",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
}
}
#[cfg(test)]
mod open_interest {
use super::EXCHANGE_NAME;
use crypto_market_type::MarketType;
use crypto_msg_parser::{extract_symbol, extract_timestamp};
#[test]
fn inverse_future() {
let raw_msg = r#"{"status":"ok","data":[{"volume":9724.000000000000000000,"amount":10561.414560502221111967,"symbol":"DOT","contract_type":"next_week","contract_code":"DOT220617","trade_amount":202723.214486601744902941274231535293939693,"trade_volume":187732,"trade_turnover":1877320.000000000000000000},{"volume":209593.000000000000000000,"amount":707.442741972231269946,"symbol":"BTC","contract_type":"quarter","contract_code":"BTC220624","trade_amount":6024.809855090449174997774141172323490409,"trade_volume":1784034,"trade_turnover":178403400.000000000000000000}],"ts":1654344900121}"#;
assert_eq!(
1654344900121,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!("ALL", extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap());
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"status":"ok","data":[{"volume":119125.000000000000000000,"amount":945962.042404510442309219,"symbol":"EOS","contract_code":"EOS-USD","trade_amount":10322249.2071798754485976941552166206559822668,"trade_volume":1295420,"trade_turnover":12954200.000000000000000000},{"volume":6629.000000000000000000,"amount":68665.837994613631655272,"symbol":"MANA","contract_code":"MANA-USD","trade_amount":2774709.7417757547949533097365134609798406114,"trade_volume":270184,"trade_turnover":2701840.000000000000000000}],"ts":1654346524275}"#;
assert_eq!(
1654346524275,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!("ALL", extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap());
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"status":"ok","data":[{"volume":288491.000000000000000000,"amount":2884910.000000000000000000,"symbol":"MANA","value":2788265.515000000000000000,"contract_code":"MANA-USDT","trade_amount":8073320,"trade_volume":807332,"trade_turnover":7868174.158,"business_type":"swap","pair":"MANA-USDT","contract_type":"swap","trade_partition":"USDT"},{"volume":270380.000000000000000000,"amount":2703800.000000000000000000,"symbol":"NKN","value":243747.570000000000000000,"contract_code":"NKN-USDT","trade_amount":18409180,"trade_volume":1840918,"trade_turnover":1678370.2842,"business_type":"swap","pair":"NKN-USDT","contract_type":"swap","trade_partition":"USDT"}],"ts":1654346577824}"#;
assert_eq!(
1654346577824,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!("ALL", extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap());
}
}