mod utils; const EXCHANGE_NAME: &str = "mexc"; #[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#"{"symbol":"BTC_USDT","data":{"deals":[{"t":1646996447307,"p":"39008.35","q":"0.003533","T":2}]},"channel":"push.deal"}"#; let trades = &parse_trade(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap(); assert_eq!(trades.len(), 1); let trade = &trades[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!( 1646996447307, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap() ); assert_eq!(trade.timestamp, 1646996447307); assert_eq!(trade.price, 39008.35); assert_eq!(trade.quantity_base, 0.003533); assert_eq!(trade.side, TradeSide::Sell); } #[test] fn linear_swap() { let raw_msg = r#"{"channel":"push.deal","data":{"M":1,"O":3,"T":2,"p":39766.5,"t":1646999591755,"v":32},"symbol":"BTC_USDT","ts":1646999591755}"#; let trades = &parse_trade(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(); assert_eq!(trades.len(), 1); let trade = &trades[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!( 1646999591755, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap() ); assert_eq!(trade.timestamp, 1646999591755); assert_eq!(trade.price, 39766.5); assert_eq!(trade.quantity_contract, Some(32.0)); assert_eq!(trade.quantity_base, 0.0001 * 32.0); assert_eq!(trade.quantity_quote, round(0.0001 * 32.0 * 39766.5)); assert_eq!(trade.side, TradeSide::Sell); } #[test] fn inverse_swap() { let raw_msg = r#"{"channel":"push.deal","data":{"M":1,"O":3,"T":2,"p":39885.5,"t":1647000043904,"v":8},"symbol":"BTC_USD","ts":1647000043904}"#; let trades = &parse_trade(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap(); assert_eq!(trades.len(), 1); let trade = &trades[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!( 1647000043904, extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap() ); assert_eq!(trade.timestamp, 1647000043904); assert_eq!(trade.price, 39885.5); assert_eq!(trade.quantity_contract, Some(8.0)); assert_eq!(trade.quantity_quote, 100.0 * 8.0); assert_eq!(trade.quantity_base, 100.0 * 8.0 / 39885.5); assert_eq!(trade.side, TradeSide::Sell); } } #[cfg(test)] mod l2_event { use super::EXCHANGE_NAME; use chrono::prelude::*; use crypto_market_type::MarketType; use crypto_msg_parser::{extract_symbol, extract_timestamp, parse_l2}; use crypto_msg_type::MessageType; #[test] fn spot() { let raw_msg = r#"{"symbol":"BTC_USDT","data":{"version":"672257402","bids":[{"p":"39763.35","q":"0.054069","a":"2149.96457"}]},"channel":"push.depth"}"#; let received_at = Utc::now().timestamp_millis(); let orderbook = &parse_l2(EXCHANGE_NAME, MarketType::Spot, raw_msg, Some(received_at)).unwrap()[0]; assert_eq!(orderbook.asks.len(), 0); assert_eq!(orderbook.bids.len(), 1); assert!(!orderbook.snapshot); assert_eq!(orderbook.seq_id, Some(672257402)); 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!(None, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg,).unwrap()); assert_eq!(orderbook.bids[0].price, 39763.35); assert_eq!(orderbook.bids[0].quantity_base, 0.054069); } #[test] fn linear_swap_update() { let raw_msg = r#"{"channel":"push.depth","data":{"asks":[[39961,0,0],[39961.5,0,0]],"bids":[[39962.5,58272,1]],"version":4702740808},"symbol":"BTC_USDT","ts":1647000258746}"#; 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); assert_eq!(orderbook.timestamp, 1647000258746); assert_eq!(orderbook.seq_id, Some(4702740808)); 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!( 1647000258746, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap() ); assert_eq!(orderbook.asks[0].price, 39961.0); assert_eq!(orderbook.asks[0].quantity_contract, Some(0.0)); assert_eq!(orderbook.asks[0].quantity_base, 0.0); assert_eq!(orderbook.asks[0].quantity_quote, 0.0); assert_eq!(orderbook.bids[0].price, 39962.5); assert_eq!(orderbook.bids[0].quantity_contract, Some(58272.0)); assert_eq!(orderbook.bids[0].quantity_base, 0.0001 * 58272.0); assert_eq!(orderbook.bids[0].quantity_quote, 0.0001 * 58272.0 * 39962.5); } #[test] fn inverse_swap_update() { let raw_msg = r#"{"channel":"push.depth","data":{"asks":[],"bids":[[39944,943,1]],"version":2768205529},"symbol":"BTC_USD","ts":1647000870946}"#; let orderbook = &parse_l2(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg, None).unwrap()[0]; assert_eq!(orderbook.asks.len(), 0); assert_eq!(orderbook.bids.len(), 1); assert!(!orderbook.snapshot); assert_eq!(orderbook.timestamp, 1647000870946); assert_eq!(orderbook.seq_id, Some(2768205529)); 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!( 1647000870946, extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap() ); assert_eq!(orderbook.bids[0].price, 39944.0); assert_eq!(orderbook.bids[0].quantity_contract, Some(943.0)); assert_eq!(orderbook.bids[0].quantity_quote, 100.0 * 943.0); assert_eq!(orderbook.bids[0].quantity_base, 100.0 * 943.0 / 39944.0); } } #[cfg(test)] mod l2_topk { use super::EXCHANGE_NAME; use chrono::prelude::*; 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#"{"channel":"push.limit.depth","symbol":"BTC_USDT","data":{"asks":[["31623.85","4.846968"],["31624.35","0.646284"],["31624.52","1.63524"],["31625.21","0.8769"],["31625.22","0.3"]],"bids":[["31623.82","0.179844"],["31623.8","0.001104"],["31623.79","0.052344"],["31623.75","1.397784"],["31623.69","0.002592"]]},"depth":5,"version":"1502380137"}"#; let received_at = Utc::now().timestamp_millis(); let orderbook = &parse_l2_topk(EXCHANGE_NAME, MarketType::Spot, raw_msg, Some(received_at)).unwrap()[0]; assert_eq!(orderbook.asks.len(), 5); assert_eq!(orderbook.bids.len(), 5); 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!(None, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg,).unwrap()); assert_eq!(received_at, orderbook.timestamp); assert_eq!(orderbook.seq_id, Some(1502380137)); assert_eq!(orderbook.prev_seq_id, None); assert_eq!(orderbook.bids[0].price, 31623.82); assert_eq!(orderbook.bids[0].quantity_base, 0.179844); assert_eq!(orderbook.bids[0].quantity_quote, 31623.82 * 0.179844); assert_eq!(orderbook.bids[0].quantity_contract, None); assert_eq!(orderbook.bids[4].price, 31623.69); assert_eq!(orderbook.bids[4].quantity_base, 0.002592); assert_eq!(orderbook.bids[4].quantity_quote, 31623.69 * 0.002592); assert_eq!(orderbook.bids[4].quantity_contract, None); assert_eq!(orderbook.asks[0].price, 31623.85); assert_eq!(orderbook.asks[0].quantity_base, 4.846968); assert_eq!(orderbook.asks[0].quantity_quote, 31623.85 * 4.846968); assert_eq!(orderbook.asks[0].quantity_contract, None); assert_eq!(orderbook.asks[4].price, 31625.22); assert_eq!(orderbook.asks[4].quantity_base, 0.3); assert_eq!(orderbook.asks[4].quantity_quote, 31625.22 * 0.3); assert_eq!(orderbook.asks[4].quantity_contract, None); } #[test] fn inverse_swap() { let raw_msg = r#"{"channel":"push.depth.full","data":{"asks":[[31647.5,1029,1],[31648,378,1],[31648.5,357,1]],"bids":[[31647,154,1],[31646.5,1470,1],[31646,140,1]],"version":3087532764},"symbol":"BTC_USD","ts":1653994948112}"#; 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!( 1653994948112, extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap() ); assert_eq!(orderbook.timestamp, 1653994948112); assert_eq!(orderbook.seq_id, Some(3087532764)); assert_eq!(orderbook.prev_seq_id, None); assert_eq!(orderbook.bids[0].price, 31647.0); assert_eq!(orderbook.bids[0].quantity_base, 100.0 * 154.0 / 31647.0); assert_eq!(orderbook.bids[0].quantity_quote, 100.0 * 154.0); assert_eq!(orderbook.bids[0].quantity_contract, Some(154.0)); assert_eq!(orderbook.bids[2].price, 31646.0); assert_eq!(orderbook.bids[2].quantity_base, 100.0 * 140.0 / 31646.0); assert_eq!(orderbook.bids[2].quantity_quote, 100.0 * 140.0); assert_eq!(orderbook.bids[2].quantity_contract, Some(140.0)); assert_eq!(orderbook.asks[0].price, 31647.5); assert_eq!(orderbook.asks[0].quantity_base, 100.0 * 1029.0 / 31647.5); assert_eq!(orderbook.asks[0].quantity_quote, 100.0 * 1029.0); assert_eq!(orderbook.asks[0].quantity_contract, Some(1029.0)); assert_eq!(orderbook.asks[2].price, 31648.5); assert_eq!(orderbook.asks[2].quantity_base, 100.0 * 357.0 / 31648.5); assert_eq!(orderbook.asks[2].quantity_quote, 100.0 * 357.0); assert_eq!(orderbook.asks[2].quantity_contract, Some(357.0)); } #[test] fn linear_swap() { let raw_msg = r#"{"channel":"push.depth.full","data":{"asks":[[31708.5,74950,2],[31709,8817,2],[31709.5,22296,2]],"bids":[[31708,3210,1],[31706,184756,2],[31705.5,10412,1]],"version":5194972869},"symbol":"BTC_USDT","ts":1653995843510}"#; 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!( 1653995843510, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap() ); assert_eq!(orderbook.timestamp, 1653995843510); assert_eq!(orderbook.seq_id, Some(5194972869)); assert_eq!(orderbook.prev_seq_id, None); assert_eq!(orderbook.bids[0].price, 31708.0); assert_eq!(orderbook.bids[0].quantity_base, 0.0001 * 3210.0); assert_eq!(orderbook.bids[0].quantity_quote, 0.0001 * 3210.0 * 31708.0); assert_eq!(orderbook.bids[0].quantity_contract, Some(3210.0)); assert_eq!(orderbook.bids[2].price, 31705.5); assert_eq!(orderbook.bids[2].quantity_base, round(0.0001 * 10412.0)); assert_eq!(orderbook.bids[2].quantity_quote, 0.0001 * 10412.0 * 31705.5); assert_eq!(orderbook.bids[2].quantity_contract, Some(10412.0)); assert_eq!(orderbook.asks[0].price, 31708.5); assert_eq!(orderbook.asks[0].quantity_base, 0.0001 * 74950.0); assert_eq!(orderbook.asks[0].quantity_quote, 0.0001 * 74950.0 * 31708.5); assert_eq!(orderbook.asks[0].quantity_contract, Some(74950.0)); assert_eq!(orderbook.asks[2].price, 31709.5); assert_eq!(orderbook.asks[2].quantity_base, 0.0001 * 22296.0); assert_eq!(orderbook.asks[2].quantity_quote, 0.0001 * 22296.0 * 31709.5); assert_eq!(orderbook.asks[2].quantity_contract, Some(22296.0)); } } #[cfg(test)] mod before_20220311 { #[cfg(test)] mod trade { use super::super::EXCHANGE_NAME; use crypto_market_type::MarketType; use crypto_message::TradeSide; use crypto_msg_parser::{extract_symbol, extract_timestamp, parse_trade}; #[test] fn spot() { let raw_msg = r#"["push.symbol",{"symbol":"BTC_USDT","data":{"deals":[{"t":1616373554541,"p":"57005.89","q":"0.007811","T":1}]}}]"#; let trades = &parse_trade(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap(); assert_eq!(trades.len(), 1); let trade = &trades[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!( 1616373554541, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap() ); assert_eq!(trade.quantity_base, 0.007811); assert_eq!(trade.side, TradeSide::Buy); } #[test] fn linear_swap() { let raw_msg = r#"{"channel":"push.deal","data":{"M":1,"O":3,"T":2,"p":57602,"t":1616370338806,"v":14},"symbol":"BTC_USDT","ts":1616370338806}"#; let trades = &parse_trade(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(); assert_eq!(trades.len(), 1); let trade = &trades[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!( 1616370338806, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap() ); assert_eq!(trade.timestamp, 1616370338806); assert_eq!(trade.price, 57602.0); assert_eq!(trade.quantity_contract, Some(14.0)); assert_eq!(trade.quantity_base, 0.0001 * 14.0); assert_eq!(trade.quantity_quote, 0.0001 * 14.0 * 57602.0); assert_eq!(trade.side, TradeSide::Sell); } #[test] fn inverse_swap() { let raw_msg = r#"{"channel":"push.deal","data":{"M":1,"O":3,"T":1,"p":57476.5,"t":1616370470356,"v":79},"symbol":"BTC_USD","ts":1616370470356}"#; let trades = &parse_trade(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap(); assert_eq!(trades.len(), 1); let trade = &trades[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!( 1616370470356, extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg) .unwrap() .unwrap() ); assert_eq!(trade.timestamp, 1616370470356); assert_eq!(trade.price, 57476.5); assert_eq!(trade.quantity_contract, Some(79.0)); assert_eq!(trade.quantity_quote, 100.0 * 79.0); assert_eq!(trade.quantity_base, 100.0 * 79.0 / 57476.5); assert_eq!(trade.side, TradeSide::Buy); } } #[cfg(test)] mod l2_event { use super::super::EXCHANGE_NAME; use chrono::prelude::*; use crypto_market_type::MarketType; use crypto_msg_parser::{extract_symbol, extract_timestamp, parse_l2}; use crypto_msg_type::MessageType; #[test] fn spot_update() { let raw_msg = r#"["push.symbol",{"symbol":"BTC_USDT","data":{"bids":[{"p":"38932.19","q":"0.049010","a":"1908.06663"},{"p":"38931.18","q":"0.038220","a":"1487.94969"}],"asks":[{"p":"38941.81","q":"0.000000","a":"0.00000000"},{"p":"38940.71","q":"0.000000","a":"0.00000000"}]}}]"#; let received_at = Utc::now().timestamp_millis(); let orderbook = &parse_l2(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::L2Event, "BTC/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.bids[0].price, 38932.19); assert_eq!(orderbook.bids[0].quantity_base, 0.04901); assert_eq!(orderbook.bids[0].quantity_quote, 1908.06663); } #[test] fn linear_swap_update() { let raw_msg = r#"{"channel":"push.depth","data":{"asks":[[38704.5,138686,1]],"bids":[],"version":2427341830},"symbol":"BTC_USDT","ts":1622722473816}"#; let orderbook = &parse_l2(EXCHANGE_NAME, MarketType::LinearSwap, 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::LinearSwap, MessageType::L2Event, "BTC/USDT".to_string(), extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(), orderbook, raw_msg, ); assert_eq!( 1622722473816, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap() ); assert_eq!(orderbook.timestamp, 1622722473816); assert_eq!(orderbook.seq_id, Some(2427341830)); assert_eq!(orderbook.asks[0].price, 38704.5); assert_eq!(orderbook.asks[0].quantity_base, 13.8686); assert_eq!(orderbook.asks[0].quantity_quote, 38704.5 * 13.8686); assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 138686.0); } #[test] fn inverse_swap_update() { let raw_msg = r#"{"channel":"push.depth","data":{"asks":[[38758.5,4172,2]],"bids":[],"version":1151578213},"symbol":"BTC_USD","ts":1622723010000}"#; let orderbook = &parse_l2(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::L2Event, "BTC/USD".to_string(), extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap(), orderbook, raw_msg, ); assert_eq!( 1622723010000, extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg) .unwrap() .unwrap() ); assert_eq!(orderbook.timestamp, 1622723010000); assert_eq!(orderbook.seq_id, Some(1151578213)); assert_eq!(orderbook.asks[0].price, 38758.5); assert_eq!(orderbook.asks[0].quantity_base, 417200.0 / 38758.5); assert_eq!(orderbook.asks[0].quantity_quote, 417200.0); assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 4172.0); } } } #[cfg(test)] mod candlestick { use super::EXCHANGE_NAME; use crypto_market_type::MarketType; use crypto_msg_parser::{extract_symbol, extract_timestamp, parse_candlestick, round}; #[test] fn spot() { let raw_msg = r#"{"symbol":"BTC_USDT","data":{"symbol":"BTC_USDT","interval":"Min1","t":1654083120,"o":31512.39,"c":31514.38,"h":31514.41,"l":31512.39,"v":273.4783858,"q":0.008678,"e":31512.39,"rh":31514.41,"rl":31512.39,"tdt":1654083133266},"channel":"push.kline","symbol_display":"BTC_USDT"}"#; let timestamp = extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap(); assert_eq!(1654083133266, timestamp.unwrap()); assert_eq!("BTC_USDT", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()); let arr = parse_candlestick(EXCHANGE_NAME, MarketType::Spot, raw_msg, timestamp).unwrap(); assert_eq!(1, arr.len()); let candlestick_msg = &arr[0]; assert_eq!("BTC_USDT", candlestick_msg.symbol); assert_eq!("BTC/USDT", candlestick_msg.pair); assert_eq!(1654083133266, candlestick_msg.timestamp); assert_eq!(1654083120 * 1000 - 60 * 1000, candlestick_msg.begin_time); assert_eq!("Min1", candlestick_msg.period); assert_eq!(31512.39, candlestick_msg.open); assert_eq!(31514.41, candlestick_msg.high); assert_eq!(31512.39, candlestick_msg.low); assert_eq!(31514.38, candlestick_msg.close); assert_eq!(0.008678, candlestick_msg.volume); assert_eq!(Some(273.4783858), candlestick_msg.quote_volume); } #[test] fn spot_sample_2() { let raw_msg = r#"["push.kline",{"symbol":"DXGM_USDT","data":{"symbol":"DXGM_USDT","interval":"Min5","t":1638241800,"o":0.0268,"c":0.02456,"h":0.0273,"l":0.02286,"v":31416.3765539,"q":1264843.57},"symbol_display":"DXGM_USDT"}]"#; let timestamp = extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap(); assert_eq!(1638241800000, timestamp.unwrap()); assert_eq!("DXGM_USDT", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()); let arr = parse_candlestick(EXCHANGE_NAME, MarketType::Spot, raw_msg, timestamp).unwrap(); assert_eq!(1, arr.len()); let candlestick_msg = &arr[0]; assert_eq!("DXGM_USDT", candlestick_msg.symbol); assert_eq!("DXGM/USDT", candlestick_msg.pair); assert_eq!(1638241800 * 1000, candlestick_msg.timestamp); assert_eq!(1638241800 * 1000 - 5 * 60 * 1000, candlestick_msg.begin_time); assert_eq!("Min5", candlestick_msg.period); assert_eq!(0.0268, candlestick_msg.open); assert_eq!(0.0273, candlestick_msg.high); assert_eq!(0.02286, candlestick_msg.low); assert_eq!(0.02456, candlestick_msg.close); assert_eq!(1264843.57, candlestick_msg.volume); assert_eq!(Some(31416.3765539), candlestick_msg.quote_volume) } #[test] fn inverse_swap() { let raw_msg = r#"{"channel":"push.kline","data":{"a":8.0759087605568165,"c":31439.5,"h":31439.5,"interval":"Min1","l":31439,"o":31439.5,"q":2539,"rc":31439.5,"rh":31439.5,"rl":31439,"ro":31439.5,"symbol":"BTC_USD","t":1654083720},"symbol":"BTC_USD","ts":1654083763923}"#; let timestamp = extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap(); assert_eq!(1654083763923, timestamp.unwrap()); assert_eq!( "BTC_USD", extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap() ); let arr = parse_candlestick(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg, timestamp).unwrap(); assert_eq!(1, arr.len()); let candlestick_msg = &arr[0]; assert_eq!("BTC_USD", candlestick_msg.symbol); assert_eq!("BTC/USD", candlestick_msg.pair); assert_eq!(1654083720 * 1000, candlestick_msg.timestamp); assert_eq!(1654083720 * 1000 - 60 * 1000, candlestick_msg.begin_time); assert_eq!("Min1", candlestick_msg.period); assert_eq!(31439.5, candlestick_msg.open); assert_eq!(31439.5, candlestick_msg.high); assert_eq!(31439.0, candlestick_msg.low); assert_eq!(31439.5, candlestick_msg.close); assert_eq!(8.0759087605568165, candlestick_msg.volume); assert_eq!(Some(253900.0), candlestick_msg.quote_volume) } #[test] fn linear_swap() { let raw_msg = r#"{"channel":"push.kline","data":{"a":99371.3865,"c":31575,"h":31585.5,"interval":"Min1","l":31574.5,"o":31576,"q":31468,"rc":31575,"rh":31585.5,"rl":31574.5,"ro":31576,"symbol":"BTC_USDT","t":1654083480},"symbol":"BTC_USDT","ts":1654083512507}"#; assert_eq!( "BTC_USDT", extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap() ); let timestamp = extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(); assert_eq!(1654083512507, timestamp.unwrap()); let arr = parse_candlestick(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, timestamp).unwrap(); assert_eq!(1, arr.len()); let candlestick_msg = &arr[0]; assert_eq!("BTC_USDT", candlestick_msg.symbol); assert_eq!("BTC/USDT", candlestick_msg.pair); assert_eq!(1654083480 * 1000, candlestick_msg.timestamp); assert_eq!(1654083480 * 1000 - 60 * 1000, candlestick_msg.begin_time); assert_eq!("Min1", candlestick_msg.period); assert_eq!(31576.0, candlestick_msg.open); assert_eq!(31585.5, candlestick_msg.high); assert_eq!(31574.5, candlestick_msg.low); assert_eq!(31575.0, candlestick_msg.close); assert_eq!(3.1468, round(candlestick_msg.volume)); assert_eq!(Some(99371.3865), 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 inverse_swap() { let raw_msg = r#"{"channel":"push.ticker","data":{"amount24":69402.4579798127137243,"ask1":29902.5,"bid1":29901.5,"contractId":77,"fairPrice":29903.13,"fundingRate":-0.000012,"high24Price":31873,"holdVol":17766,"indexPrice":29926.05,"lastPrice":29902,"lower24Price":29275.5,"maxBidPrice":32918.5,"minAskPrice":26933,"riseFallRate":-0.0264,"riseFallValue":-813,"symbol":"BTC_USD","timestamp":1654165977028,"volume24":21030740},"symbol":"BTC_USD","ts":1654165977028}"#; assert_eq!( 1654165977028, 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#"{"channel":"push.ticker","data":{"amount24":898120149.6331,"ask1":29911.5,"bid1":29911,"contractId":10,"fairPrice":29911.1,"fundingRate":0.000072,"high24Price":31905.5,"holdVol":12357864,"indexPrice":29926.9,"lastPrice":29911.5,"lower24Price":29316,"maxBidPrice":32919.5,"minAskPrice":26934,"riseFallRate":-0.0275,"riseFallValue":-846,"symbol":"BTC_USDT","timestamp":1654165943014,"volume24":295146577},"symbol":"BTC_USDT","ts":1654165943014}"#; assert_eq!( 1654165943014, 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#"{"code":200,"data":{"asks":[{"price":"29653.11","quantity":"2.401543"},{"price":"29653.12","quantity":"0.033048"},{"price":"29653.41","quantity":"0.40332"}],"bids":[{"price":"29653.08","quantity":"3.101382"},{"price":"29653.07","quantity":"0.018948"},{"price":"29653.04","quantity":"0.003084"}],"version":"1535017255"}}"#; assert_eq!( None, extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap() ); assert_eq!( "NONE", extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap() ); } #[test] fn inverse_swap() { let raw_msg = r#"{"success":true,"code":0,"data":{"asks":[[29625,630,1],[29625.5,371,1],[29626,581,1]],"bids":[[29618,357,1],[29617.5,357,1],[29617,581,1]],"version":3094693618,"timestamp":1654326901060}}"#; assert_eq!( 1654326901060, extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap() ); assert_eq!( "NONE", extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap() ); } #[test] fn linear_swap() { let raw_msg = r#"{"success":true,"code":0,"data":{"asks":[[29676.5,20696,2],[29677,19821,2],[29677.5,50122,2]],"bids":[[29675.5,59944,2],[29675,29676,2],[29674.5,15455,2]],"version":5216820883,"timestamp":1654328706778}}"#; assert_eq!( 1654328706778, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap() ); assert_eq!("NONE", extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()); } }