mod utils; const EXCHANGE_NAME: &str = "bitfinex"; #[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_te() { let raw_msg = r#"[{"symbol":"tBTCUST","channel":"trades"},"te",[637771130,1615232733897,0.11546588,51350]]"#; 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!( 1615232733897, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap() ); assert_eq!(trade.quantity_base, 0.11546588); assert_eq!(trade.quantity_quote, round(0.11546588 * 51350.0)); assert_eq!(trade.quantity_contract, None); assert_eq!(trade.side, TradeSide::Buy); } #[test] fn spot_tu() { let raw_msg = r#"[{"symbol":"tBTCUST","channel":"trades"},"tu",[637771130,1615232733897,0.11546588,51350]]"#; 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!( 1615232733897, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap() ); assert_eq!(trade.quantity_base, 0.11546588); assert_eq!(trade.quantity_quote, round(0.11546588 * 51350.0)); assert_eq!(trade.quantity_contract, None); assert_eq!(trade.side, TradeSide::Buy); } #[test] fn spot_snapshot() { let raw_msg = r#"[{"channel":"trades","symbol":"tBTCUST"},[[647229117,1616217509543,0.0033,58239],[647229114,1616217326462,0.05605347,58296],[647229113,1616217326462,0.00102018,58296]]]"#; let trades = &parse_trade(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap(); assert_eq!(trades.len(), 3); for trade in trades.iter() { 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!( 1616217509543, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap() ); } #[test] fn swap_te() { let raw_msg = r#"[{"channel":"trades","symbol":"tBTCF0:USTF0"},"te",[647256282,1616219711336,0.00020449,58244]]"#; 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!( 1616219711336, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap() ); assert_eq!(trade.quantity_base, 0.00020449); assert_eq!(trade.quantity_quote, round(0.00020449 * 58244.0)); assert_eq!(trade.quantity_contract, Some(0.00020449)); assert_eq!(trade.side, TradeSide::Buy); } #[test] fn swap_tu() { let raw_msg = r#"[{"channel":"trades","symbol":"tBTCF0:USTF0"},"tu",[647256282,1616219711336,0.00020449,58244]]"#; 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!( 1616219711336, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap() ); assert_eq!(trade.quantity_base, 0.00020449); assert_eq!(trade.quantity_quote, round(0.00020449 * 58244.0)); assert_eq!(trade.quantity_contract, Some(0.00020449)); assert_eq!(trade.side, TradeSide::Buy); } #[test] fn swap_snapshot() { let raw_msg = r#"[{"channel":"trades","symbol":"tBTCF0:USTF0"},[[647256201,1616219105954,-0.06153795,58119],[647256191,1616219094921,0.0257,58138],[647256188,1616219088734,0.01679516,58138]]]"#; let trades = &parse_trade(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(); assert_eq!(trades.len(), 3); for trade in trades.iter() { 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!( 1616219105954, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap() ); } } #[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, round}; use crypto_msg_type::MessageType; #[test] fn spot_snapshot() { let raw_msg = r#"[{"symbol":"tBTCUST","len":"25","freq":"F0","channel":"book","prec":"P0"},[[36167,1,0.48403686],[36162,2,0.22625024],[36161,1,0.43250047],[36158,1,0.209],[36155,2,0.48229814],[36171,1,-0.000006],[36172,1,-0.0002],[36173,1,-0.0002],[36174,2,-0.0102],[36175,1,-0.0002]]]"#; 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(), 5); assert_eq!(orderbook.bids.len(), 5); 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, 36167.0); assert_eq!(orderbook.bids[0].quantity_base, 0.48403686); assert_eq!(orderbook.bids[0].quantity_quote, 36167.0 * 0.48403686); assert_eq!(orderbook.bids[4].price, 36155.0); assert_eq!(orderbook.bids[4].quantity_base, 0.48229814); assert_eq!(orderbook.bids[4].quantity_quote, 36155.0 * 0.48229814); assert_eq!(orderbook.asks[0].price, 36171.0); assert_eq!(orderbook.asks[0].quantity_base, 0.000006); assert_eq!(orderbook.asks[0].quantity_quote, 36171.0 * 0.000006); assert_eq!(orderbook.asks[4].price, 36175.0); assert_eq!(orderbook.asks[4].quantity_base, 0.0002); assert_eq!(orderbook.asks[4].quantity_quote, 36175.0 * 0.0002); } #[test] fn spot_update() { let raw_msg = r#"[{"symbol":"tBTCUST","channel":"book","len":"25","freq":"F0","prec":"P0"},[34668,1,-0.00813136]]"#; 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(), 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!(None, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()); assert_eq!(orderbook.asks[0].price, 34668.0); assert_eq!(orderbook.asks[0].quantity_base, 0.00813136); assert_eq!(orderbook.asks[0].quantity_quote, round(34668.0 * 0.00813136)); } #[test] fn linear_swap_snapshot() { let raw_msg = r#"[{"freq":"F0","channel":"book","prec":"P0","len":"25","symbol":"tBTCF0:USTF0"},[[34840,2,0.20047952],[34837,1,0.17573],[34829,1,0.0857],[34828,1,0.17155],[34826,2,0.25510833],[34841,1,-0.00034929],[34843,4,-0.70368583],[34844,1,-0.51672161],[34845,2,-0.78960194],[34846,1,-1.0339621]]]"#; let received_at = Utc::now().timestamp_millis(); let orderbook = &parse_l2(EXCHANGE_NAME, MarketType::LinearSwap, 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::LinearSwap, MessageType::L2Event, "BTC/USDT".to_string(), extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(), orderbook, raw_msg, ); assert_eq!(None, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()); assert_eq!(orderbook.bids[0].price, 34840.0); assert_eq!(orderbook.bids[0].quantity_base, 0.20047952); assert_eq!(orderbook.bids[0].quantity_quote, 34840.0 * 0.20047952); assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 0.20047952); assert_eq!(orderbook.bids[4].price, 34826.0); assert_eq!(orderbook.bids[4].quantity_base, 0.25510833); assert_eq!(orderbook.bids[4].quantity_quote, 34826.0 * 0.25510833); assert_eq!(orderbook.bids[4].quantity_contract.unwrap(), 0.25510833); assert_eq!(orderbook.asks[0].price, 34841.0); assert_eq!(orderbook.asks[0].quantity_base, 0.00034929); assert_eq!(orderbook.asks[0].quantity_quote, 34841.0 * 0.00034929); assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 0.00034929); assert_eq!(orderbook.asks[4].price, 34846.0); assert_eq!(orderbook.asks[4].quantity_base, 1.0339621); assert_eq!(orderbook.asks[4].quantity_quote, 34846.0 * 1.0339621); assert_eq!(orderbook.asks[4].quantity_contract.unwrap(), 1.0339621); } #[test] fn linear_swap_update() { let raw_msg = r#"[{"freq":"F0","symbol":"tBTCF0:USTF0","channel":"book","len":"25","prec":"P0"},[34442,2,2.27726294]]"#; let received_at = Utc::now().timestamp_millis(); let orderbook = &parse_l2(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, Some(received_at)).unwrap() [0]; assert_eq!(orderbook.asks.len(), 0); 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!(None, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()); assert_eq!(orderbook.bids[0].price, 34442.0); assert_eq!(orderbook.bids[0].quantity_base, 2.27726294); assert_eq!(orderbook.bids[0].quantity_quote, 34442.0 * 2.27726294); assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 2.27726294); } } #[cfg(test)] mod l3_event { use super::EXCHANGE_NAME; use crypto_market_type::MarketType; use crypto_msg_parser::{extract_symbol, extract_timestamp}; #[test] fn spot_snapshot() { let raw_msg = r#"[{"len":"250","symbol":"tBTCUST","channel":"book","prec":"R0","freq":"F0"},[[96124382782,31534,0.0285],[96124397723,31534,0.01],[96118584550,31532,0.01586],[96118584551,31544,-0.01585],[96124364148,31544,-0.27332593],[96124396297,31547,-0.6338]]]"#; assert_eq!(None, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()); assert_eq!("tBTCUST", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()); } #[test] fn spot_update() { let raw_msg = r#"[{"len":"250","symbol":"tBTCUST","channel":"book","prec":"R0","freq":"F0"},[96118584550,31535,0.01586]]"#; assert_eq!(None, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()); assert_eq!("tBTCUST", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()); } #[test] fn linear_swap_snapshot() { let raw_msg = r#"[{"freq":"F0","channel":"book","prec":"R0","symbol":"tBTCF0:USTF0","len":"250"},[[96124920207,31556,0.19100648],[96124877610,31555,0.031],[96124911151,31555,0.25466876],[96124920217,31557,-0.19103873],[96124919043,31558,-0.25474405],[96124858873,31560,-0.31772226]]]"#; assert_eq!( None, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap() ); assert_eq!( "tBTCF0:USTF0", extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap() ); } #[test] fn linear_swap_update() { let raw_msg = r#"[{"freq":"F0","channel":"book","prec":"R0","symbol":"tBTCF0:USTF0","len":"250"},[96124877612,31555,0.039]]"#; assert_eq!( None, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap() ); assert_eq!( "tBTCF0:USTF0", extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).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_snapshot() { let raw_msg = r#"[{"key":"trade:1m:tBTCUST","channel":"candles"},[[1654074480000,31636,31636,31636,31636,0.0001],[1654074420000,31633,31631,31640,31631,0.11289119],[1654074300000,31631,31626,31631,31626,0.00047848]]]"#; assert_eq!( 1654074480000, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap() ); assert_eq!("tBTCUST", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()); let arr = parse_candlestick(EXCHANGE_NAME, MarketType::Spot, raw_msg, None).unwrap(); assert_eq!(3, arr.len()); let candlestick_msg = &arr[0]; assert_eq!("tBTCUST", candlestick_msg.symbol); assert_eq!(1654074480000, candlestick_msg.timestamp); assert_eq!("1m", candlestick_msg.period); assert_eq!(31636.0, candlestick_msg.open); assert_eq!(31636.0, candlestick_msg.high); assert_eq!(31636.0, candlestick_msg.low); assert_eq!(31636.0, candlestick_msg.close); assert_eq!(0.0001, candlestick_msg.volume); } #[test] fn spot_update() { let raw_msg = r#"[{"channel":"candles","key":"trade:1m:tBTCUST"},[1654075080000,31619,31619,31619,31619,0.00843875]]"#; assert_eq!( 1654075080000, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap() ); assert_eq!("tBTCUST", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()); let candlestick_msg = &parse_candlestick(EXCHANGE_NAME, MarketType::Spot, raw_msg, None).unwrap()[0]; assert_eq!("tBTCUST", candlestick_msg.symbol); assert_eq!(1654075080000, candlestick_msg.timestamp); assert_eq!("1m", candlestick_msg.period); assert_eq!(31619.0, candlestick_msg.open); assert_eq!(31619.0, candlestick_msg.high); assert_eq!(31619.0, candlestick_msg.low); assert_eq!(31619.0, candlestick_msg.close); assert_eq!(0.00843875, candlestick_msg.volume); } #[test] fn linear_swap_snapshot() { let raw_msg = r#"[{"channel":"candles","key":"trade:1m:tBTCF0:USTF0"},[[1654076100000,31672,31667,31672,31667,0.053312790000000006],[1654076040000,31672,31673,31673,31667,0.00118434],[1654075980000,31669,31672,31672,31669,0.0008369499999999999]]]"#; assert_eq!( 1654076100000, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap() ); assert_eq!( "tBTCF0:USTF0", extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap() ); let arr = parse_candlestick(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, None).unwrap(); assert_eq!(3, arr.len()); let candlestick_msg = &arr[0]; assert_eq!("tBTCF0:USTF0", candlestick_msg.symbol); assert_eq!(1654076100000, candlestick_msg.timestamp); assert_eq!("1m", candlestick_msg.period); assert_eq!(31672.0, candlestick_msg.open); assert_eq!(31672.0, candlestick_msg.high); assert_eq!(31667.0, candlestick_msg.low); assert_eq!(31667.0, candlestick_msg.close); assert_eq!(0.053312790000000006, candlestick_msg.volume); } #[test] fn linear_swap_update() { let raw_msg = r#"[{"channel":"candles","key":"trade:1m:tBTCF0:USTF0"},[1654076040000,31672,31673,31673,31667,0.00118434]]"#; assert_eq!( 1654076040000, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap() ); assert_eq!( "tBTCF0:USTF0", extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap() ); let candlestick_msg = &parse_candlestick(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, None).unwrap()[0]; assert_eq!("tBTCF0:USTF0", candlestick_msg.symbol); assert_eq!(1654076040000, candlestick_msg.timestamp); assert_eq!("1m", candlestick_msg.period); assert_eq!(31672.0, candlestick_msg.open); assert_eq!(31673.0, candlestick_msg.high); assert_eq!(31667.0, candlestick_msg.low); assert_eq!(31673.0, candlestick_msg.close); assert_eq!(0.00118434, candlestick_msg.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#"[{"symbol":"tBTCUST","channel":"ticker"},[29967,8.32497516,29976,13.30144555,-1674,-0.0529,29966,488.04182112,31887,29335]]"#; assert_eq!(None, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()); assert_eq!("tBTCUST", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()); } #[test] fn linear_swap() { let raw_msg = r#"[{"symbol":"tBTCF0:USTF0","channel":"ticker"},[29936,25.086598379999998,29940,38.29793123,-1692,-0.0535,29940,3957.33360529,31878,29308]]"#; assert_eq!( None, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap() ); assert_eq!( "tBTCF0:USTF0", 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#"[[30428,1,0.01],[30426,1,0.1],[30424,1,0.2954],[30423,1,0.3333],[30422,3,0.72231346],[30420,2,0.3349],[30416,2,0.29700845],[30415,3,0.482257],[30414,1,0.4],[30413,1,0.15439084]]"#; 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 linear_swap() { let raw_msg = r#"[[28293,1,0.0350506],[28291,1,0.0526735],[28289,2,0.1037385],[28287,1,0.1059222],[28285,1,0.1324028],[28284,1,0.1765371],[28282,1,0.2206713],[28280,1,0.2427385],[28277,1,0.2648056]]"#; assert_eq!("NONE", extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()); assert_eq!( None, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap() ); } }