mod utils;
const EXCHANGE_NAME: &str = "binance";
#[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#"{"stream":"btcusdt@aggTrade","data":{"e":"aggTrade","E":1616176861895,"s":"BTCUSDT","a":640283266,"p":"58942.01000000","q":"0.00035600","f":716849523,"l":716849523,"T":1616176861893,"m":false,"M":true}}"#;
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!(
1616176861895,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap()
);
assert_eq!(trade.quantity_base, 0.00035600);
assert_eq!(trade.quantity_quote, 0.00035600 * 58942.01);
assert_eq!(trade.quantity_contract, None);
assert_eq!(trade.side, TradeSide::Buy);
}
#[test]
fn inverse_future() {
let raw_msg = r#"{"stream":"btcusd_210625@aggTrade","data":{"e":"aggTrade","E":1616201787561,"a":5091038,"s":"BTCUSD_210625","p":"62838.0","q":"5","f":7621250,"l":7621250,"T":1616201787407,"m":true}}"#;
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!(
1616201787561,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(trade.quantity_base, 500.0 / 62838.0);
assert_eq!(trade.quantity_quote, 500.0);
assert_eq!(trade.quantity_contract, Some(5.0));
assert_eq!(trade.side, TradeSide::Sell);
}
#[test]
fn linear_future() {
let raw_msg = r#"{"stream":"btcusdt_210625@aggTrade","data":{"e":"aggTrade","E":1616201036113,"a":21021,"s":"BTCUSDT_210625","p":"62595.8","q":"0.094","f":21824,"l":21824,"T":1616201035958,"m":false}}"#;
let trade = &parse_trade(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap()[0];
crate::utils::check_trade_fields(
EXCHANGE_NAME,
MarketType::LinearFuture,
"BTC/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap(),
trade,
raw_msg,
);
assert_eq!(
1616201036113,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(trade.quantity_base, 0.094);
assert_eq!(trade.quantity_quote, round(0.094 * 62595.8));
assert_eq!(trade.quantity_contract, Some(0.094));
assert_eq!(trade.side, TradeSide::Buy);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"stream":"btcusd_perp@aggTrade","data":{"e":"aggTrade","E":1616201883458,"a":41045788,"s":"BTCUSD_PERP","p":"58570.1","q":"58","f":91864326,"l":91864327,"T":1616201883304,"m":true}}"#;
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!(
1616201883458,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(trade.price, 58570.1);
assert_eq!(trade.quantity_base, 5800.0 / 58570.1);
assert_eq!(trade.quantity_quote, 5800.0);
assert_eq!(trade.quantity_contract, Some(58.0));
assert_eq!(trade.side, TradeSide::Sell);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"stream":"btcusdt@aggTrade","data":{"e":"aggTrade","E":1616202009196,"a":389551486,"s":"BTCUSDT","p":"58665.00","q":"0.043","f":621622993,"l":621622993,"T":1616202009188,"m":false}}"#;
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!(
1616202009196,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(trade.quantity_base, 0.043);
assert_eq!(trade.quantity_quote, 0.043 * 58665.00);
assert_eq!(trade.quantity_contract, Some(0.043));
assert_eq!(trade.side, TradeSide::Buy);
}
#[test]
fn option() {
let raw_msg = r#"{"stream":"BTCUSDT_C@TRADE_ALL","data":{"e":"trade_all","E":1616205287778,"s":"BTCUSDT_C","t":[{"t":"315","p":"4842.24","q":"0.0001","b":"4612047757752932782","a":"4612057653433061439","T":1616204382000,"s":"1","S":"BTC-210430-68000-C"},{"t":"805","p":"5616.36","q":"0.0001","b":"4612047757752932781","a":"4612057653433055969","T":1616204357000,"s":"1","S":"BTC-210430-64000-C"},{"t":"313","p":"7028.44","q":"0.0001","b":"4612015871915728334","a":"4612057653433051715","T":1616204344000,"s":"1","S":"BTC-210430-60000-C"}]}}"#;
assert_eq!("ALL", extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap());
assert_eq!(
1616205287778,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
}
}
#[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#"{"stream":"btcusd_perp@markPrice","data":{"e":"markPriceUpdate","E":1617309477000,"s":"BTCUSD_PERP","p":"59012.56007222","P":"58896.00503145","r":"0.00073689","T":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!(
"BTCUSD_PERP",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
assert_eq!(
1617309477000,
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.00073689);
assert_eq!(funding_rates[0].funding_time, 1617321600000);
assert_eq!(funding_rates[0].timestamp, 1617309477000);
}
#[test]
fn inverse_swap_all() {
let raw_msg = r#"{"stream":"!markPrice@arr","data":[{"e":"markPriceUpdate","E":1617309501002,"s":"BTCUSD_PERP","p":"59003.37984561","P":"58896.41602208","r":"0.00073684","T":1617321600000},{"e":"markPriceUpdate","E":1617309501002,"s":"ETHUSD_PERP","p":"1981.89000000","P":"1975.18948029","r":"0.00100944","T":1617321600000}]}"#;
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!(
1617309501002,
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.00073684);
assert_eq!(funding_rates[0].funding_time, 1617321600000);
assert_eq!(funding_rates[0].timestamp, 1617309501002);
assert_eq!(funding_rates[1].pair, "ETH/USD".to_string());
assert_eq!(funding_rates[1].funding_rate, 0.00100944);
assert_eq!(funding_rates[1].funding_time, 1617321600000);
assert_eq!(funding_rates[1].timestamp, 1617309501002);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"stream":"btcusdt@markPrice","data":{"e":"markPriceUpdate","E":1617308820003,"s":"BTCUSDT","p":"58940.14924532","P":"58905.14663658","i":"58857.26693664","r":"0.00058455","T":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!(
"BTCUSDT",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
assert_eq!(
1617308820003,
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.00058455);
assert_eq!(funding_rates[0].funding_time, 1617321600000);
assert_eq!(funding_rates[0].timestamp, 1617308820003);
}
#[test]
fn linear_swap_all() {
let raw_msg = r#"{"stream":"!markPrice@arr","data":[{"e":"markPriceUpdate","E":1617309024002,"s":"BTCUSDT","p":"59022.53514719","P":"58902.34482833","i":"58936.68384000","r":"0.00058959","T":1617321600000},{"e":"markPriceUpdate","E":1617309024002,"s":"ETHUSDT","p":"1981.15704420","P":"1974.79557094","i":"1978.08197502","r":"0.00059142","T":1617321600000}]}"#;
let funding_rates =
&parse_funding_rate(EXCHANGE_NAME, MarketType::LinearSwap, 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::LinearSwap,
rate,
raw_msg,
);
}
assert_eq!("ALL", extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap());
assert_eq!(
1617309024002,
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.00058959);
assert_eq!(funding_rates[0].funding_time, 1617321600000);
assert_eq!(funding_rates[0].timestamp, 1617309024002);
assert_eq!(funding_rates[1].pair, "ETH/USDT".to_string());
assert_eq!(funding_rates[1].funding_rate, 0.00059142);
assert_eq!(funding_rates[1].funding_time, 1617321600000);
assert_eq!(funding_rates[1].timestamp, 1617309024002);
}
}
#[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() {
let raw_msg = r#"{"stream":"btcusdt@depth@100ms","data":{"e":"depthUpdate","E":1622363903670,"s":"BTCUSDT","U":11294093710,"u":11294093726,"b":[["35743.98000000","0.00000000"],["35743.87000000","0.00001500"]],"a":[["35743.88000000","0.24000000"],["35743.97000000","0.00000000"]]}}"#;
let orderbook = &parse_l2(EXCHANGE_NAME, MarketType::Spot, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 2);
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!(
1622363903670,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1622363903670);
assert_eq!(orderbook.seq_id, Some(11294093726));
assert_eq!(orderbook.bids[0].price, 35743.98);
assert_eq!(orderbook.bids[0].quantity_base, 0.0);
assert_eq!(orderbook.bids[0].quantity_quote, 0.0);
assert_eq!(orderbook.bids[1].price, 35743.87);
assert_eq!(orderbook.bids[1].quantity_base, 0.000015);
assert_eq!(orderbook.bids[1].quantity_quote, 35743.87 * 0.000015);
assert_eq!(orderbook.asks[0].price, 35743.88);
assert_eq!(orderbook.asks[0].quantity_base, 0.24);
assert_eq!(orderbook.asks[0].quantity_quote, 35743.88 * 0.24);
assert_eq!(orderbook.asks[1].price, 35743.97);
assert_eq!(orderbook.asks[1].quantity_base, 0.0);
assert_eq!(orderbook.asks[1].quantity_quote, 0.0);
}
#[test]
fn inverse_future() {
let raw_msg = r#"{"stream":"btcusd_210625@depth@100ms","data":{"e":"depthUpdate","E":1622368000245,"T":1622368000234,"s":"BTCUSD_210625","ps":"BTCUSD","U":127531213607,"u":127531214406,"pu":127531213513,"b":[["35943.8","60"],["35965.2","896"]],"a":[["36038.3","9"],["36038.4","21"]]}}"#;
let orderbook =
&parse_l2(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 2);
assert_eq!(orderbook.bids.len(), 2);
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!(
1622368000245,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1622368000245);
assert_eq!(orderbook.seq_id, Some(127531214406));
assert_eq!(orderbook.prev_seq_id, Some(127531213513));
assert_eq!(orderbook.bids[0].price, 35943.8);
assert_eq!(orderbook.bids[0].quantity_base, 6000.0 / 35943.8);
assert_eq!(orderbook.bids[0].quantity_quote, 6000.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 60.0);
assert_eq!(orderbook.bids[1].price, 35965.2);
assert_eq!(orderbook.bids[1].quantity_base, 89600.0 / 35965.2);
assert_eq!(orderbook.bids[1].quantity_quote, 89600.0);
assert_eq!(orderbook.bids[1].quantity_contract.unwrap(), 896.0);
assert_eq!(orderbook.asks[0].price, 36038.3);
assert_eq!(orderbook.asks[0].quantity_base, 900.0 / 36038.3);
assert_eq!(orderbook.asks[0].quantity_quote, 900.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 9.0);
assert_eq!(orderbook.asks[1].price, 36038.4);
assert_eq!(orderbook.asks[1].quantity_base, 2100.0 / 36038.4);
assert_eq!(orderbook.asks[1].quantity_quote, 2100.0);
assert_eq!(orderbook.asks[1].quantity_contract.unwrap(), 21.0);
}
#[test]
fn linear_future() {
let raw_msg = r#"{"stream":"ethusdt_210625@depth@100ms","data":{"e":"depthUpdate","E":1622368962075,"T":1622368962065,"s":"ETHUSDT_210625","U":475700780918,"u":475700783070,"pu":475700774972,"b":[["2437.04","82.320"],["2437.07","0.000"]],"a":[["2441.23","1.500"],["2441.24","0.220"]]}}"#;
let orderbook =
&parse_l2(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 2);
assert_eq!(orderbook.bids.len(), 2);
assert!(!orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::LinearFuture,
MessageType::L2Event,
"ETH/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1622368962075,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1622368962075);
assert_eq!(orderbook.seq_id, Some(475700783070));
assert_eq!(orderbook.prev_seq_id, Some(475700774972));
assert_eq!(orderbook.bids[0].price, 2437.04);
assert_eq!(orderbook.bids[0].quantity_base, 82.32);
assert_eq!(orderbook.bids[0].quantity_quote, 2437.04 * 82.32);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 82.32);
assert_eq!(orderbook.bids[1].price, 2437.07);
assert_eq!(orderbook.bids[1].quantity_base, 0.0);
assert_eq!(orderbook.bids[1].quantity_quote, 0.0);
assert_eq!(orderbook.bids[1].quantity_contract.unwrap(), 0.0);
assert_eq!(orderbook.asks[0].price, 2441.23);
assert_eq!(orderbook.asks[0].quantity_base, 1.5);
assert_eq!(orderbook.asks[0].quantity_quote, round(2441.23 * 1.5));
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 1.5);
assert_eq!(orderbook.asks[1].price, 2441.24);
assert_eq!(orderbook.asks[1].quantity_base, 0.220);
assert_eq!(orderbook.asks[1].quantity_quote, round(2441.24 * 0.220));
assert_eq!(orderbook.asks[1].quantity_contract.unwrap(), 0.220);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"stream":"btcusdt@depth@100ms","data":{"e":"depthUpdate","E":1622371244693,"T":1622371244687,"s":"BTCUSDT","U":475776377463,"u":475776380184,"pu":475776377452,"b":[["35729.77","1.600"],["35750.00","5.106"]],"a":[["35819.20","0.211"],["35820.31","0.001"]]}}"#;
let orderbook = &parse_l2(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 2);
assert_eq!(orderbook.bids.len(), 2);
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!(
1622371244693,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1622371244693);
assert_eq!(orderbook.seq_id, Some(475776380184));
assert_eq!(orderbook.prev_seq_id, Some(475776377452));
assert_eq!(orderbook.bids[0].price, 35729.77);
assert_eq!(orderbook.bids[0].quantity_base, 1.6);
assert_eq!(orderbook.bids[0].quantity_quote, 35729.77 * 1.6);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 1.6);
assert_eq!(orderbook.bids[1].price, 35750.0);
assert_eq!(orderbook.bids[1].quantity_base, 5.106);
assert_eq!(orderbook.bids[1].quantity_quote, 35750.0 * 5.106);
assert_eq!(orderbook.bids[1].quantity_contract.unwrap(), 5.106);
assert_eq!(orderbook.asks[0].price, 35819.2);
assert_eq!(orderbook.asks[0].quantity_base, 0.211);
assert_eq!(orderbook.asks[0].quantity_quote, round(35819.2 * 0.211));
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 0.211);
assert_eq!(orderbook.asks[1].price, 35820.31);
assert_eq!(orderbook.asks[1].quantity_base, 0.001);
assert_eq!(orderbook.asks[1].quantity_quote, 35820.31 * 0.001);
assert_eq!(orderbook.asks[1].quantity_contract.unwrap(), 0.001);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"stream":"btcusd_perp@depth@100ms","data":{"e":"depthUpdate","E":1622370862564,"T":1622370862553,"s":"BTCUSD_PERP","ps":"BTCUSD","U":127559587191,"u":127559588177,"pu":127559587113,"b":[["35365.9","1400"],["35425.8","561"]],"a":[["35817.8","7885"],["35818.7","307"]]}}"#;
let orderbook =
&parse_l2(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 2);
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!(
1622370862564,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1622370862564);
assert_eq!(orderbook.seq_id, Some(127559588177));
assert_eq!(orderbook.prev_seq_id, Some(127559587113));
assert_eq!(orderbook.bids[0].price, 35365.9);
assert_eq!(orderbook.bids[0].quantity_base, 140000.0 / 35365.9);
assert_eq!(orderbook.bids[0].quantity_quote, 140000.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 1400.0);
assert_eq!(orderbook.bids[1].price, 35425.8);
assert_eq!(orderbook.bids[1].quantity_base, 56100.0 / 35425.8);
assert_eq!(orderbook.bids[1].quantity_quote, 56100.0);
assert_eq!(orderbook.bids[1].quantity_contract.unwrap(), 561.0);
assert_eq!(orderbook.asks[0].price, 35817.8);
assert_eq!(orderbook.asks[0].quantity_base, 788500.0 / 35817.8);
assert_eq!(orderbook.asks[0].quantity_quote, 788500.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 7885.0);
assert_eq!(orderbook.asks[1].price, 35818.7);
assert_eq!(orderbook.asks[1].quantity_base, 30700.0 / 35818.7);
assert_eq!(orderbook.asks[1].quantity_quote, 30700.0);
assert_eq!(orderbook.asks[1].quantity_contract.unwrap(), 307.0);
}
#[test]
fn option() {}
}
#[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#"{"stream":"ethusdt@depth20","data":{"lastUpdateId":17044571457,"bids":[["1782.00000000","6.48300000"],["1781.95000000","0.03000000"]],"asks":[["1782.01000000","15.46080000"],["1782.02000000","0.00780000"]]}}"#;
let received_at = 1622363903670;
let orderbook =
&parse_l2_topk(EXCHANGE_NAME, MarketType::Spot, raw_msg, Some(received_at)).unwrap()[0];
assert_eq!(orderbook.asks.len(), 2);
assert_eq!(orderbook.bids.len(), 2);
assert!(orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::Spot,
MessageType::L2TopK,
"ETH/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(None, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap());
assert_eq!(orderbook.timestamp, received_at);
assert_eq!(orderbook.seq_id, Some(17044571457));
assert_eq!(orderbook.prev_seq_id, None);
assert_eq!(orderbook.bids[0].price, 1782.0);
assert_eq!(orderbook.bids[0].quantity_base, 6.483);
assert_eq!(orderbook.bids[0].quantity_quote, 1782.0 * 6.483);
assert_eq!(orderbook.bids[0].quantity_contract, None);
assert_eq!(orderbook.bids[1].price, 1781.95);
assert_eq!(orderbook.bids[1].quantity_base, 0.03);
assert_eq!(orderbook.bids[1].quantity_quote, 1781.95 * 0.03);
assert_eq!(orderbook.bids[1].quantity_contract, None);
assert_eq!(orderbook.asks[0].price, 1782.01);
assert_eq!(orderbook.asks[0].quantity_base, 15.4608);
assert_eq!(orderbook.asks[0].quantity_quote, 1782.01 * 15.4608);
assert_eq!(orderbook.asks[0].quantity_contract, None);
assert_eq!(orderbook.asks[1].price, 1782.02);
assert_eq!(orderbook.asks[1].quantity_base, 0.0078);
assert_eq!(orderbook.asks[1].quantity_quote, 1782.02 * 0.0078);
assert_eq!(orderbook.asks[1].quantity_contract, None);
}
#[test]
fn inverse_future() {
let raw_msg = r#"{"stream":"btcusd_220624@depth20","data":{"e":"depthUpdate","E":1653863834495,"T":1653863834489,"s":"BTCUSD_220624","ps":"BTCUSD","U":462549791905,"u":462549794973,"pu":462549791429,"b":[["29538.2","195"],["29536.3","491"],["29534.6","44"]],"a":[["29538.3","144"],["29540.5","46"],["29540.6","180"]]}}"#;
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!(
1653863834495,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1653863834495);
assert_eq!(orderbook.seq_id, Some(462549794973));
assert_eq!(orderbook.prev_seq_id, Some(462549791429));
assert_eq!(orderbook.bids[0].price, 29538.2);
assert_eq!(orderbook.bids[0].quantity_base, 19500.0 / 29538.2);
assert_eq!(orderbook.bids[0].quantity_quote, 19500.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 195.0);
assert_eq!(orderbook.bids[2].price, 29534.6);
assert_eq!(orderbook.bids[2].quantity_base, 4400.0 / 29534.6);
assert_eq!(orderbook.bids[2].quantity_quote, 4400.0);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 44.0);
assert_eq!(orderbook.asks[0].price, 29538.3);
assert_eq!(orderbook.asks[0].quantity_base, 14400.0 / 29538.3);
assert_eq!(orderbook.asks[0].quantity_quote, 14400.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 144.0);
assert_eq!(orderbook.asks[2].price, 29540.6);
assert_eq!(orderbook.asks[2].quantity_base, 18000.0 / 29540.6);
assert_eq!(orderbook.asks[2].quantity_quote, 18000.0);
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 180.0);
}
#[test]
fn linear_future() {
let raw_msg = r#"{"stream":"ethusdt_220624@depth20","data":{"e":"depthUpdate","E":1653864801536,"T":1653864801453,"s":"ETHUSDT_220624","U":1555027694421,"u":1555027698095,"pu":1555027693966,"b":[["1817.59","0.246"],["1817.57","0.254"],["1817.55","0.254"]],"a":[["1817.98","0.704"],["1817.99","0.820"],["1818.10","0.246"]]}}"#;
let orderbook =
&parse_l2_topk(EXCHANGE_NAME, MarketType::LinearFuture, 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::LinearFuture,
MessageType::L2TopK,
"ETH/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1653864801536,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1653864801536);
assert_eq!(orderbook.seq_id, Some(1555027698095));
assert_eq!(orderbook.prev_seq_id, Some(1555027693966));
assert_eq!(orderbook.bids[0].price, 1817.59);
assert_eq!(orderbook.bids[0].quantity_base, 0.246);
assert_eq!(orderbook.bids[0].quantity_quote, 1817.59 * 0.246);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 0.246);
assert_eq!(orderbook.bids[2].price, 1817.55);
assert_eq!(orderbook.bids[2].quantity_base, 0.254);
assert_eq!(orderbook.bids[2].quantity_quote, 1817.55 * 0.254);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 0.254);
assert_eq!(orderbook.asks[0].price, 1817.98);
assert_eq!(orderbook.asks[0].quantity_base, 0.704);
assert_eq!(orderbook.asks[0].quantity_quote, 1817.98 * 0.704);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 0.704);
assert_eq!(orderbook.asks[2].price, 1818.10);
assert_eq!(orderbook.asks[2].quantity_base, 0.246);
assert_eq!(orderbook.asks[2].quantity_quote, 1818.10 * 0.246);
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 0.246);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"stream":"btcusd_perp@depth20","data":{"e":"depthUpdate","E":1653865197260,"T":1653865197065,"s":"BTCUSD_PERP","ps":"BTCUSD","U":462562184037,"u":462562184258,"pu":462562183567,"b":[["29389.3","6014"],["29389.2","111"],["29389.0","200"]],"a":[["29389.4","3926"],["29390.2","263"],["29391.0","953"]]}}"#;
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!(
1653865197260,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1653865197260);
assert_eq!(orderbook.seq_id, Some(462562184258));
assert_eq!(orderbook.prev_seq_id, Some(462562183567));
assert_eq!(orderbook.bids[0].price, 29389.3);
assert_eq!(orderbook.bids[0].quantity_base, 601400.0 / 29389.3);
assert_eq!(orderbook.bids[0].quantity_quote, 601400.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 6014.0);
assert_eq!(orderbook.bids[2].price, 29389.0);
assert_eq!(orderbook.bids[2].quantity_base, 20000.0 / 29389.0);
assert_eq!(orderbook.bids[2].quantity_quote, 20000.0);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 200.0);
assert_eq!(orderbook.asks[0].price, 29389.4);
assert_eq!(orderbook.asks[0].quantity_base, 392600.0 / 29389.4);
assert_eq!(orderbook.asks[0].quantity_quote, 392600.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 3926.0);
assert_eq!(orderbook.asks[2].price, 29391.0);
assert_eq!(orderbook.asks[2].quantity_base, 95300.0 / 29391.0);
assert_eq!(orderbook.asks[2].quantity_quote, 95300.0);
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 953.0);
}
#[test]
fn inverse_swap_2() {
let raw_msg = r#"{"stream":"runeusd_perp@depth5","data":{"e":"depthUpdate","E":1648006221596,"T":1648006221340,"s":"RUNEUSD_PERP","ps":"RUNEUSD","U":395028983849,"u":395028983849,"pu":-1,"b":[],"a":[["8.4400","2"]]}}"#;
let orderbook =
&parse_l2_topk(EXCHANGE_NAME, MarketType::InverseSwap, 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::InverseSwap,
MessageType::L2TopK,
"RUNE/USD".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
"RUNEUSD_PERP",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
assert_eq!(
1648006221596,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1648006221596);
assert_eq!(orderbook.seq_id, Some(395028983849));
assert_eq!(orderbook.prev_seq_id, None);
assert_eq!(orderbook.asks[0].price, 8.4400);
assert_eq!(orderbook.asks[0].quantity_base, 2.0 * 10.0 / 8.4400);
assert_eq!(orderbook.asks[0].quantity_quote, 2.0 * 10.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 2.0);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"stream":"ethusdt@depth20","data":{"e":"depthUpdate","E":1651122265861,"T":1651122265854,"s":"ETHUSDT","U":1437010873371,"u":1437010882721,"pu":1437010873329,"b":[["2886.71","0.454"],["2886.70","2.755"],["2886.67","1.000"]],"a":[["2886.72","77.215"],["2886.73","1.734"],["2886.74","0.181"]]}}"#;
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,
"ETH/USDT".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1651122265861,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1651122265861);
assert_eq!(orderbook.seq_id, Some(1437010882721));
assert_eq!(orderbook.prev_seq_id, Some(1437010873329));
assert_eq!(orderbook.bids[0].price, 2886.71);
assert_eq!(orderbook.bids[0].quantity_base, 0.454);
assert_eq!(orderbook.bids[0].quantity_quote, 2886.71 * 0.454);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 0.454);
assert_eq!(orderbook.bids[2].price, 2886.67);
assert_eq!(orderbook.bids[2].quantity_base, 1.0);
assert_eq!(orderbook.bids[2].quantity_quote, 2886.67 * 1.0);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 1.000);
assert_eq!(orderbook.asks[0].price, 2886.72);
assert_eq!(orderbook.asks[0].quantity_base, 77.215);
assert_eq!(orderbook.asks[0].quantity_quote, round(2886.72 * 77.215));
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 77.215);
assert_eq!(orderbook.asks[2].price, 2886.74);
assert_eq!(orderbook.asks[2].quantity_base, 0.181);
assert_eq!(orderbook.asks[2].quantity_quote, round(2886.74 * 0.181));
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 0.181);
}
}
#[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#"{"stream":"!bookTicker","data":{"u":19575390521,"s":"BTCUSDT","b":"29010.90000000","B":"13.94302000","a":"29010.91000000","A":"3.99953000"}}"#;
assert_eq!("BTCUSDT", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap());
assert_eq!(None, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap());
let received_at = 1651122265862;
let bbo_msg =
&parse_bbo(EXCHANGE_NAME, MarketType::Spot, raw_msg, Some(received_at)).unwrap()[0];
assert_eq!(MessageType::BBO, bbo_msg.msg_type);
assert_eq!("BTCUSDT", bbo_msg.symbol);
assert_eq!(received_at, bbo_msg.timestamp);
assert_eq!(Some(19575390521), bbo_msg.id);
assert_eq!(29010.91, bbo_msg.ask_price);
assert_eq!(3.99953, bbo_msg.ask_quantity_base);
assert_eq!(29010.91 * 3.99953, bbo_msg.ask_quantity_quote);
assert_eq!(None, bbo_msg.ask_quantity_contract);
assert_eq!(29010.9, bbo_msg.bid_price);
assert_eq!(13.94302, bbo_msg.bid_quantity_base);
assert_eq!(29010.9 * 13.94302, bbo_msg.bid_quantity_quote);
assert_eq!(None, bbo_msg.bid_quantity_contract);
}
#[test]
fn inverse_future() {
let raw_msg = r#"{"stream":"!bookTicker","data":{"u":462118190224,"e":"bookTicker","s":"XMRUSD_PERP","ps":"XMRUSD","b":"172.74","B":"86","a":"172.81","A":"25","T":1653811915499,"E":1653811915502}}"#;
assert_eq!(
"XMRUSD_PERP",
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap()
);
assert_eq!(
1653811915502,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().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!("XMRUSD_PERP", bbo_msg.symbol);
assert_eq!(1653811915502, bbo_msg.timestamp);
assert_eq!(Some(462118190224), bbo_msg.id);
assert_eq!(172.81, bbo_msg.ask_price);
assert_eq!(25.0 * 10.0 / 172.81, bbo_msg.ask_quantity_base);
assert_eq!(25.0 * 10.0, bbo_msg.ask_quantity_quote);
assert_eq!(Some(25.0), bbo_msg.ask_quantity_contract);
assert_eq!(172.74, bbo_msg.bid_price);
assert_eq!(86.0 * 10.0 / 172.74, bbo_msg.bid_quantity_base);
assert_eq!(86.0 * 10.0, bbo_msg.bid_quantity_quote);
assert_eq!(Some(86.0), bbo_msg.bid_quantity_contract);
}
#[test]
fn linear_future() {
let raw_msg = r#"{"stream":"!bookTicker","data":{"e":"bookTicker","u":1553205153844,"s":"BALUSDT","b":"6.718","B":"16.2","a":"6.719","A":"3.7","T":1653812037547,"E":1653812037552}}"#;
assert_eq!(
"BALUSDT",
extract_symbol(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap()
);
assert_eq!(
1653812037552,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap().unwrap()
);
let bbo_msg =
&parse_bbo(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg, None).unwrap()[0];
assert_eq!(MessageType::BBO, bbo_msg.msg_type);
assert_eq!("BALUSDT", bbo_msg.symbol);
assert_eq!(1653812037552, bbo_msg.timestamp);
assert_eq!(Some(1553205153844), bbo_msg.id);
assert_eq!(6.719, bbo_msg.ask_price);
assert_eq!(3.7, bbo_msg.ask_quantity_base);
assert_eq!(round(6.719 * 3.7), bbo_msg.ask_quantity_quote);
assert_eq!(Some(3.7), bbo_msg.ask_quantity_contract);
assert_eq!(6.718, bbo_msg.bid_price);
assert_eq!(16.2, bbo_msg.bid_quantity_base);
assert_eq!(6.718 * 16.2, bbo_msg.bid_quantity_quote);
assert_eq!(Some(16.2), bbo_msg.bid_quantity_contract);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"stream":"ethusd_perp@bookTicker","data":{"u":462169572570,"e":"bookTicker","s":"ETHUSD_PERP","ps":"ETHUSD","b":"1776.25","B":"10779","a":"1776.26","A":"37544","T":1653817930434,"E":1653817930438}}"#;
assert_eq!(
"ETHUSD_PERP",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
assert_eq!(
1653817930438,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().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!("ETHUSD_PERP", bbo_msg.symbol);
assert_eq!(1653817930438, bbo_msg.timestamp);
assert_eq!(Some(462169572570), bbo_msg.id);
assert_eq!(1776.26, bbo_msg.ask_price);
assert_eq!(37544.0 * 10.0 / 1776.26, bbo_msg.ask_quantity_base);
assert_eq!(37544.0 * 10.0, bbo_msg.ask_quantity_quote);
assert_eq!(Some(37544.0), bbo_msg.ask_quantity_contract);
assert_eq!(1776.25, bbo_msg.bid_price);
assert_eq!(10779.0 * 10.0 / 1776.25, bbo_msg.bid_quantity_base);
assert_eq!(10779.0 * 10.0, bbo_msg.bid_quantity_quote);
assert_eq!(Some(10779.0), bbo_msg.bid_quantity_contract);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"stream":"ethusdt@bookTicker","data":{"e":"bookTicker","u":1553413152520,"s":"ETHUSDT","b":"1778.54","B":"15.164","a":"1778.55","A":"7.289","T":1653817855284,"E":1653817855289}}"#;
assert_eq!(
"ETHUSDT",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
assert_eq!(
1653817855289,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
let bbo_msg =
&parse_bbo(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg, None).unwrap()[0];
assert_eq!(MessageType::BBO, bbo_msg.msg_type);
assert_eq!("ETHUSDT", bbo_msg.symbol);
assert_eq!(1653817855289, bbo_msg.timestamp);
assert_eq!(Some(1553413152520), bbo_msg.id);
assert_eq!(1778.55, bbo_msg.ask_price);
assert_eq!(7.289, bbo_msg.ask_quantity_base);
assert_eq!(1778.55 * 7.289, bbo_msg.ask_quantity_quote);
assert_eq!(Some(7.289), bbo_msg.ask_quantity_contract);
assert_eq!(1778.54, bbo_msg.bid_price);
assert_eq!(15.164, bbo_msg.bid_quantity_base);
assert_eq!(1778.54 * 15.164, bbo_msg.bid_quantity_quote);
assert_eq!(Some(15.164), bbo_msg.bid_quantity_contract);
}
}
#[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#"{"stream":"ethusdt@ticker","data":{"e":"24hrTicker","E":1653812650349,"s":"ETHUSDT","p":"28.23000000","P":"1.600","w":"1781.16275609","x":"1764.61000000","c":"1792.84000000","Q":"0.55720000","b":"1792.83000000","B":"1.62740000","a":"1792.84000000","A":"20.29140000","o":"1764.61000000","h":"1808.98000000","l":"1748.94000000","v":"471703.53110000","q":"840180761.51358100","O":1653726250344,"C":1653812650344,"F":841094172,"L":841646650,"n":552479}}"#;
assert_eq!("ETHUSDT", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap());
assert_eq!(
1653812650349,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap()
);
let raw_msg = r#"{"stream":"!ticker@arr","data":[{"e":"24hrTicker","E":1653812100450,"s":"ETHBTC","p":"0.00031500","P":"0.515","w":"0.06150587","x":"0.06118800","c":"0.06150300","Q":"0.74000000","b":"0.06150300","B":"18.96220000","a":"0.06150400","A":"10.94010000","o":"0.06118800","h":"0.06221700","l":"0.06079900","v":"116854.45230000","q":"7187.23459814","O":1653725700257,"C":1653812100257,"F":342624389,"L":342741830,"n":117442}]}"#;
assert_eq!("ALL", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap());
assert_eq!(
1653812100450,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap()
);
}
#[test]
fn inverse_future() {
let raw_msg = r#"{"stream":"bnbusd_220624@ticker","data":{"e":"24hrTicker","E":1653814590778,"s":"BNBUSD_220624","ps":"BNBUSD","p":"1.134","P":"0.384","w":"299.21521423","c":"296.672","Q":"2","o":"295.538","h":"305.367","l":"293.303","v":"654348","q":"21868.80776371","O":1653728160000,"C":1653814590774,"F":2127486,"L":2138545,"n":11060}}"#;
assert_eq!(
"BNBUSD_220624",
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap()
);
assert_eq!(
1653814590778,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
let raw_msg = r#"{"stream":"!ticker@arr","data":[{"e":"24hrTicker","E":1653814699950,"s":"AVAXUSD_PERP","ps":"AVAXUSD","p":"2.60","P":"11.439","w":"24.25184175","c":"25.33","Q":"516","o":"22.73","h":"25.92","l":"22.26","v":"3259077","q":"1343847.21496168","O":1653728280000,"C":1653814699945,"F":9534407,"L":9598591,"n":64185}]}"#;
assert_eq!(
"ALL",
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap()
);
assert_eq!(
1653814699950,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
}
#[test]
fn linear_future() {
let raw_msg = r#"{"stream":"btcusdt_220624@ticker","data":{"e":"24hrTicker","E":1653814783325,"s":"BTCUSDT_220624","p":"196.5","P":"0.679","w":"29043.7","c":"29122.5","Q":"0.004","o":"28926.0","h":"29335.0","l":"28834.4","v":"1047.859","q":"30433679.16","O":1653728340000,"C":1653814783320,"F":2872692,"L":2893528,"n":20837}}"#;
assert_eq!(
"BTCUSDT_220624",
extract_symbol(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap()
);
assert_eq!(
1653814783325,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap().unwrap()
);
let raw_msg = r#"{"stream":"!ticker@arr","data":[{"e":"24hrTicker","E":1653813900353,"s":"BTCUSDT","p":"213.70","P":"0.740","w":"28973.36","c":"29093.90","Q":"0.017","o":"28880.20","h":"29265.70","l":"28755.00","v":"173254.241","q":"5019757418.36","O":1653727500000,"C":1653813900348,"F":2299852977,"L":2301666553,"n":1813560}]}"#;
assert_eq!(
"ALL",
extract_symbol(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap()
);
assert_eq!(
1653813900353,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap().unwrap()
);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"stream":"btcusd_perp@ticker","data":{"e":"24hrTicker","E":1653815020148,"s":"BTCUSD_PERP","ps":"BTCUSD","p":"238.2","P":"0.827","w":"28943.21988874","c":"29031.8","Q":"83","o":"28793.6","h":"29222.8","l":"28728.4","v":"12229247","q":"42252.54497257","O":1653728580000,"C":1653815020145,"F":442530608,"L":442717685,"n":187078}}"#;
assert_eq!(
"BTCUSD_PERP",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
assert_eq!(
1653815020148,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
let raw_msg = r#"{"stream":"!ticker@arr","data":[{"e":"24hrTicker","E":1653814800360,"s":"APEUSD_PERP","ps":"APEUSD","p":"-0.0510","P":"-0.827","w":"6.20092494","c":"6.1180","Q":"200","o":"6.1690","h":"6.3870","l":"5.9620","v":"859567","q":"1386191.58913317","O":1653728400000,"C":1653814800354,"F":4337375,"L":4357994,"n":20620}]}"#;
assert_eq!("ALL", extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap());
assert_eq!(
1653814800360,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"stream":"ethusdt@ticker","data":{"e":"24hrTicker","E":1653815205866,"s":"ETHUSDT","p":"24.69","P":"1.405","w":"1782.01","c":"1782.02","Q":"0.003","o":"1757.33","h":"1809.33","l":"1750.45","v":"1678290.411","q":"2990736920.72","O":1653728760000,"C":1653815205856,"F":1689354205,"L":1691266554,"n":1912297}}"#;
assert_eq!(
"ETHUSDT",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
assert_eq!(
1653815205866,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
let raw_msg = r#"{"stream":"!ticker@arr","data":[{"e":"24hrTicker","E":1653814800126,"s":"IOTXUSDT","p":"0.00053","P":"1.525","w":"0.03552","c":"0.03529","Q":"861","o":"0.03476","h":"0.03645","l":"0.03465","v":"346584392","q":"12312309.61000","O":1653728400000,"C":1653814800117,"F":94208734,"L":94269527,"n":60794}]}"#;
assert_eq!("ALL", extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap());
assert_eq!(
1653814800126,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
}
#[test]
fn option() {
let raw_msg = r#"{"stream":"BTCUSDT@TICKER_ALL","data":{"e":"ticker_all","E":1654388207145,"s":"BTCUSDT","c":"1.7935","p":"1.2517"}}"#;
assert_eq!("ALL", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap());
assert_eq!(
1654388207145,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap()
);
}
}
#[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#"{"stream":"btcusdt@kline_1m","data":{"e":"kline","E":1653818762502,"s":"BTCUSDT","k":{"t":1653818760000,"T":1653818819999,"s":"BTCUSDT","i":"1m","f":1384844002,"L":1384844032,"o":"29038.46000000","c":"29038.47000000","h":"29038.47000000","l":"29038.46000000","v":"0.20926000","n":31,"x":false,"q":"6076.58918320","V":"0.10436000","Q":"3030.45472920","B":"0"}}}"#;
assert_eq!("BTCUSDT", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap());
assert_eq!(
1653818762502,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().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!("BTC/USDT", candlestick_msg.pair);
assert_eq!(1653818762502, candlestick_msg.timestamp);
assert_eq!(1653818760, candlestick_msg.begin_time);
assert_eq!("1m", candlestick_msg.period);
assert_eq!(29038.46, candlestick_msg.open);
assert_eq!(29038.47, candlestick_msg.high);
assert_eq!(29038.46, candlestick_msg.low);
assert_eq!(29038.47, candlestick_msg.close);
assert_eq!(0.20926, candlestick_msg.volume);
assert_eq!(Some(6076.5891832), candlestick_msg.quote_volume);
}
#[test]
fn inverse_future() {
let raw_msg = r#"{"stream":"btcusd_220624@kline_1m","data":{"e":"kline","E":1653818854836,"s":"BTCUSD_220624","k":{"t":1653818820000,"T":1653818879999,"s":"BTCUSD_220624","i":"1m","f":12373411,"L":12373422,"o":"29105.5","c":"29107.9","h":"29107.9","l":"29096.9","v":"191","n":12,"x":false,"q":"0.65623556","V":"34","Q":"0.11681070","B":"0"}}}"#;
assert_eq!(
"BTCUSD_220624",
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap()
);
assert_eq!(
1653818854836,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().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!("BTCUSD_220624", candlestick_msg.symbol);
assert_eq!(1653818854836, candlestick_msg.timestamp);
assert_eq!("1m", candlestick_msg.period);
assert_eq!(1653818820, candlestick_msg.begin_time);
assert_eq!(29105.5, candlestick_msg.open);
assert_eq!(29107.9, candlestick_msg.high);
assert_eq!(29096.9, candlestick_msg.low);
assert_eq!(29107.9, candlestick_msg.close);
assert_eq!(0.65623556, candlestick_msg.volume);
assert_eq!(Some(19100.0), candlestick_msg.quote_volume);
}
#[test]
fn linear_future() {
let raw_msg = r#"{"stream":"btcusdt_220624@kline_1m","data":{"e":"kline","E":1653818905630,"s":"BTCUSDT_220624","k":{"t":1653818880000,"T":1653818939999,"s":"BTCUSDT_220624","i":"1m","f":2894511,"L":2894528,"o":"29135.9","c":"29141.5","h":"29149.9","l":"29135.9","v":"1.447","n":18,"x":false,"q":"42169.8708","V":"0.241","Q":"7023.0583","B":"0"}}}"#;
assert_eq!(
"BTCUSDT_220624",
extract_symbol(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap()
);
assert_eq!(
1653818905630,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap().unwrap()
);
let arr =
parse_candlestick(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg, None).unwrap();
assert_eq!(1, arr.len());
let candlestick_msg = &arr[0];
assert_eq!("BTCUSDT_220624", candlestick_msg.symbol);
assert_eq!(1653818905630, candlestick_msg.timestamp);
assert_eq!("1m", candlestick_msg.period);
assert_eq!(1653818880, candlestick_msg.begin_time);
assert_eq!(29135.9, candlestick_msg.open);
assert_eq!(29149.9, candlestick_msg.high);
assert_eq!(29135.9, candlestick_msg.low);
assert_eq!(29141.5, candlestick_msg.close);
assert_eq!(1.447, candlestick_msg.volume);
assert_eq!(Some(42169.8708), candlestick_msg.quote_volume);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"stream":"ethusd_perp@kline_1m","data":{"e":"kline","E":1653818962599,"s":"ETHUSD_PERP","k":{"t":1653818940000,"T":1653818999999,"s":"ETHUSD_PERP","i":"1m","f":413873402,"L":413874164,"o":"1786.56","c":"1788.67","h":"1789.24","l":"1785.25","v":"401601","n":763,"x":false,"q":"2246.59444657","V":"254246","Q":"1422.31905487","B":"0"}}}"#;
assert_eq!(
"ETHUSD_PERP",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
assert_eq!(
1653818962599,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().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!("ETHUSD_PERP", candlestick_msg.symbol);
assert_eq!(1653818962599, candlestick_msg.timestamp);
assert_eq!("1m", candlestick_msg.period);
assert_eq!(1653818940, candlestick_msg.begin_time);
assert_eq!(1786.56, candlestick_msg.open);
assert_eq!(1789.24, candlestick_msg.high);
assert_eq!(1785.25, candlestick_msg.low);
assert_eq!(1788.67, candlestick_msg.close);
assert_eq!(2246.59444657, candlestick_msg.volume);
assert_eq!(Some(4016010.0), candlestick_msg.quote_volume);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"stream":"btcusdt@kline_1M","data":{"e":"kline","E":1653819041520,"s":"BTCUSDT","k":{"t":1651363200000,"T":1654041599999,"s":"BTCUSDT","i":"1M","f":2172726276,"L":2301806561,"o":"37614.40","c":"29075.50","h":"40071.70","l":"26631.00","v":"13431981.671","n":129025447,"x":false,"q":"423075730671.12853","V":"6700065.176","Q":"211000435586.65000","B":"0"}}}"#;
assert_eq!(
"BTCUSDT",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
assert_eq!(
1653819041520,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().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!("BTCUSDT", candlestick_msg.symbol);
assert_eq!(1653819041520, candlestick_msg.timestamp);
assert_eq!("1M", candlestick_msg.period);
assert_eq!(1651363200, candlestick_msg.begin_time);
assert_eq!(37614.40, candlestick_msg.open);
assert_eq!(40071.70, candlestick_msg.high);
assert_eq!(26631.0, candlestick_msg.low);
assert_eq!(29075.5, candlestick_msg.close);
assert_eq!(13431981.671, candlestick_msg.volume);
assert_eq!(Some(423075730671.12853), candlestick_msg.quote_volume);
}
}
#[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#"{"lastUpdateId":19689626134,"bids":[["30618.66000000","1.82881000"],["30618.61000000","0.02494000"],["30618.45000000","0.94258000"]],"asks":[["30618.67000000","3.28780000"],["30618.69000000","0.44985000"],["30618.70000000","0.03360000"]]}"#;
assert_eq!("NONE", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap());
assert_eq!(None, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap());
}
#[test]
fn inverse_future() {
let raw_msg = r#"{"lastUpdateId":466364745366,"E":1654222838718,"T":1654222838710,"symbol":"BTCUSD_220624","pair":"BTCUSD","bids":[["30626.7","827"],["30624.4","11"],["30624.3","1"]],"asks":[["30626.8","114"],["30627.7","30"],["30630.2","4"]]}"#;
assert_eq!(
"BTCUSD_220624",
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap()
);
assert_eq!(
1654222838718,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
}
#[test]
fn linear_future() {
let raw_msg = r#"{"lastUpdateId":1570223094073,"E":1654231622340,"T":1654231622320,"bids":[["30564.6","0.024"],["30561.1","0.003"],["30561.0","0.055"]],"asks":[["30569.5","0.141"],["30569.6","0.004"],["30569.7","0.067"]]}"#;
assert_eq!(
"NONE",
extract_symbol(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap()
);
assert_eq!(
1654231622340,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap().unwrap()
);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"lastUpdateId":466437000380,"E":1654232431449,"T":1654232431434,"symbol":"BTCUSD_PERP","pair":"BTCUSD","bids":[["30401.8","12984"],["30401.5","53"],["30401.4","150"]],"asks":[["30401.9","1788"],["30402.0","1"],["30402.1","384"]]}"#;
assert_eq!(
"BTCUSD_PERP",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
assert_eq!(
1654232431449,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"lastUpdateId":1570255790655,"E":1654232606707,"T":1654232606695,"bids":[["30430.80","0.482"],["30430.00","0.012"],["30429.90","0.001"]],"asks":[["30430.90","1.685"],["30431.00","0.001"],["30431.30","0.361"]]}"#;
assert_eq!("NONE", extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap());
assert_eq!(
1654232606707,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().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#"{"symbol":"BTCUSD_220624","pair":"BTCUSD","openInterest":"2470927","contractType":"CURRENT_QUARTER","time":1654336766113}"#;
assert_eq!(
"BTCUSD_220624",
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap()
);
assert_eq!(
1654336766113,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
}
#[test]
fn linear_future() {
let raw_msg =
r#"{"symbol":"BTCUSDT_220624","openInterest":"1275.028","time":1654336785074}"#;
assert_eq!(
"BTCUSDT_220624",
extract_symbol(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap()
);
assert_eq!(
1654336785074,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap().unwrap()
);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"symbol":"BTCUSD_PERP","pair":"BTCUSD","openInterest":"5827897","contractType":"PERPETUAL","time":1654336819740}"#;
assert_eq!(
"BTCUSD_PERP",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
assert_eq!(
1654336819740,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
}
#[test]
fn linear_swap() {
let raw_msg = r#"{"symbol":"BTCUSDT","openInterest":"84617.188","time":1654336844754}"#;
assert_eq!(
"BTCUSDT",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
assert_eq!(
1654336844754,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
}
}