mod utils; const EXCHANGE_NAME: &str = "ftx"; #[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#"{"channel": "trades", "market": "BTC/USD", "type": "update", "data": [{"id": 632052557, "price": 56335.0, "size": 0.0444, "side": "buy", "liquidation": false, "time": "2021-03-21T10:24:37.319680+00:00"}]}"#; let trades = &parse_trade(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap(); assert_eq!(trades.len(), 1); for trade in trades.iter() { crate::utils::check_trade_fields( EXCHANGE_NAME, MarketType::Spot, "BTC/USD".to_string(), extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap(), trade, raw_msg, ); assert_eq!(trade.side, TradeSide::Buy); } assert_eq!( 1616322277319, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap() ); assert_eq!(trades[0].quantity_base, 0.0444); } #[test] fn linear_futre() { let raw_msg = r#"{"channel": "trades", "market": "BTC-0326", "type": "update", "data": [{"id": 632137285, "price": 56244.0, "size": 0.0043, "side": "sell", "liquidation": false, "time": "2021-03-21T10:58:26.498464+00:00"}]}"#; let trades = &parse_trade(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap(); assert_eq!(trades.len(), 1); for trade in trades.iter() { crate::utils::check_trade_fields( EXCHANGE_NAME, MarketType::LinearFuture, "BTC/USD".to_string(), extract_symbol(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap(), trade, raw_msg, ); } assert_eq!( 1616324306498, extract_timestamp(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap().unwrap() ); assert_eq!(trades[0].quantity_base, 0.0043); assert_eq!(trades[0].quantity_quote, 0.0043 * 56244.0); assert_eq!(trades[0].quantity_contract, Some(0.0043)); assert_eq!(trades[0].side, TradeSide::Sell); } #[test] fn linear_swap() { let raw_msg = r#"{"channel": "trades", "market": "BTC-PERP", "type": "update", "data": [{"id": 632141274, "price": 56115.0, "size": 0.005, "side": "buy", "liquidation": false, "time": "2021-03-21T11:00:38.933676+00:00"}]}"#; let trades = &parse_trade(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(); assert_eq!(trades.len(), 1); for trade in trades.iter() { crate::utils::check_trade_fields( EXCHANGE_NAME, MarketType::LinearSwap, "BTC/USD".to_string(), extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(), trade, raw_msg, ); } assert_eq!( 1616324438933, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap() ); assert_eq!(trades[0].quantity_base, 0.005); assert_eq!(trades[0].quantity_quote, 0.005 * 56115.0); assert_eq!(trades[0].quantity_contract, Some(0.005)); assert_eq!(trades[0].side, TradeSide::Buy); } #[test] fn volatility_move() { let raw_msg = r#"{"channel": "trades", "market": "BTC-MOVE-WK-0402", "type": "update", "data": [{"id": 619750489, "price": 5862.0, "size": 0.1136, "side": "buy", "liquidation": false, "time": "2021-03-18T17:47:50.727425+00:00"}]}"#; let trades = &parse_trade(EXCHANGE_NAME, MarketType::Move, raw_msg).unwrap(); assert_eq!(trades.len(), 1); for trade in trades.iter() { crate::utils::check_trade_fields( EXCHANGE_NAME, MarketType::Move, "BTC/USD".to_string(), extract_symbol(EXCHANGE_NAME, MarketType::Move, raw_msg).unwrap(), trade, raw_msg, ); } assert_eq!( 1616089670727, extract_timestamp(EXCHANGE_NAME, MarketType::Move, raw_msg).unwrap().unwrap() ); assert_eq!(trades[0].quantity_base, 0.1136); assert_eq!(trades[0].quantity_quote, round(0.1136 * 5862.0)); assert_eq!(trades[0].quantity_contract, Some(0.1136)); assert_eq!(trades[0].side, TradeSide::Buy); } } #[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_snapshot() { let raw_msg = r#"{"channel": "orderbook", "market": "BTC/USD", "type": "partial", "data": {"time": 1622668801.966823, "checksum": 4093133381, "bids": [[37875.0, 0.4537], [37874.0, 0.5673], [37872.0, 0.328]], "asks": [[37876.0, 0.1749], [37877.0, 0.0001], [37878.0, 0.5]], "action": "partial"}}"#; let orderbook = &parse_l2(EXCHANGE_NAME, MarketType::Spot, raw_msg, None).unwrap()[0]; assert_eq!(orderbook.asks.len(), 3); assert_eq!(orderbook.bids.len(), 3); assert!(orderbook.snapshot); crate::utils::check_orderbook_fields( EXCHANGE_NAME, MarketType::Spot, MessageType::L2Event, "BTC/USD".to_string(), extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap(), orderbook, raw_msg, ); assert_eq!( 1622668801966, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap() ); assert_eq!(orderbook.timestamp, 1622668801966); assert_eq!(orderbook.bids[0].price, 37875.0); assert_eq!(orderbook.bids[0].quantity_base, 0.4537); assert_eq!(orderbook.bids[0].quantity_quote, 37875.0 * 0.4537); assert_eq!(orderbook.bids[2].price, 37872.0); assert_eq!(orderbook.bids[2].quantity_base, 0.328); assert_eq!(orderbook.bids[2].quantity_quote, 37872.0 * 0.328); assert_eq!(orderbook.asks[0].price, 37876.0); assert_eq!(orderbook.asks[0].quantity_base, 0.1749); assert_eq!(orderbook.asks[0].quantity_quote, 37876.0 * 0.1749); assert_eq!(orderbook.asks[2].price, 37878.0); assert_eq!(orderbook.asks[2].quantity_base, 0.5); assert_eq!(orderbook.asks[2].quantity_quote, 37878.0 * 0.5); } #[test] fn spot_update() { let raw_msg = r#"{"channel": "orderbook", "market": "BTC/USD", "type": "update", "data": {"time": 1622668802.0262146, "checksum": 2044263315, "bids": [[37875.0, 0.446]], "asks": [[37886.0, 5.2109], [37889.0, 0.8493]], "action": "update"}}"#; let orderbook = &parse_l2(EXCHANGE_NAME, MarketType::Spot, raw_msg, None).unwrap()[0]; assert_eq!(orderbook.asks.len(), 2); assert_eq!(orderbook.bids.len(), 1); assert!(!orderbook.snapshot); crate::utils::check_orderbook_fields( EXCHANGE_NAME, MarketType::Spot, MessageType::L2Event, "BTC/USD".to_string(), extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap(), orderbook, raw_msg, ); assert_eq!( 1622668802026, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap() ); assert_eq!(orderbook.timestamp, 1622668802026); assert_eq!(orderbook.bids[0].price, 37875.0); assert_eq!(orderbook.bids[0].quantity_base, 0.446); assert_eq!(orderbook.bids[0].quantity_quote, 37875.0 * 0.446); assert_eq!(orderbook.asks[0].price, 37886.0); assert_eq!(orderbook.asks[0].quantity_base, 5.2109); assert_eq!(orderbook.asks[0].quantity_quote, 37886.0 * 5.2109); assert_eq!(orderbook.asks[1].price, 37889.0); assert_eq!(orderbook.asks[1].quantity_base, 0.8493); assert_eq!(orderbook.asks[1].quantity_quote, 37889.0 * 0.8493); } #[test] fn linear_future_snapshot() { let raw_msg = r#"{"channel": "orderbook", "market": "BTC-0625", "type": "partial", "data": {"time": 1622669504.8200636, "checksum": 1739399809, "bids": [[37965.0, 2.7939], [37961.0, 0.005], [37960.0, 11.4351]], "asks": [[37980.0, 0.2474], [37987.0, 0.0957], [37991.0, 0.0005]], "action": "partial"}}"#; let orderbook = &parse_l2(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::L2Event, "BTC/USD".to_string(), extract_symbol(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap(), orderbook, raw_msg, ); assert_eq!( 1622669504820, extract_timestamp(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap().unwrap() ); assert_eq!(orderbook.timestamp, 1622669504820); assert_eq!(orderbook.bids[0].price, 37965.0); assert_eq!(orderbook.bids[0].quantity_base, 2.7939); assert_eq!(orderbook.bids[0].quantity_quote, 37965.0 * 2.7939); assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 2.7939); assert_eq!(orderbook.bids[2].price, 37960.0); assert_eq!(orderbook.bids[2].quantity_base, 11.4351); assert_eq!(orderbook.bids[2].quantity_quote, 37960.0 * 11.4351); assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 11.4351); assert_eq!(orderbook.asks[0].price, 37980.0); assert_eq!(orderbook.asks[0].quantity_base, 0.2474); assert_eq!(orderbook.asks[0].quantity_quote, 37980.0 * 0.2474); assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 0.2474); assert_eq!(orderbook.asks[2].price, 37991.0); assert_eq!(orderbook.asks[2].quantity_base, 0.0005); assert_eq!(orderbook.asks[2].quantity_quote, 37991.0 * 0.0005); assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 0.0005); } #[test] fn linear_future_update() { let raw_msg = r#"{"channel": "orderbook", "market": "BTC-0625", "type": "update", "data": {"time": 1622669504.8437843, "checksum": 1584262478, "bids": [], "asks": [[37999.0, 0.0], [38440.0, 0.0026]], "action": "update"}}"#; let orderbook = &parse_l2(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg, None).unwrap()[0]; assert_eq!(orderbook.asks.len(), 2); assert_eq!(orderbook.bids.len(), 0); assert!(!orderbook.snapshot); crate::utils::check_orderbook_fields( EXCHANGE_NAME, MarketType::LinearFuture, MessageType::L2Event, "BTC/USD".to_string(), extract_symbol(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap(), orderbook, raw_msg, ); assert_eq!( 1622669504843, extract_timestamp(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap().unwrap() ); assert_eq!(orderbook.timestamp, 1622669504843); assert_eq!(orderbook.asks[0].price, 37999.0); assert_eq!(orderbook.asks[0].quantity_base, 0.0); assert_eq!(orderbook.asks[0].quantity_quote, 0.0); assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 0.0); assert_eq!(orderbook.asks[1].price, 38440.0); assert_eq!(orderbook.asks[1].quantity_base, 0.0026); assert_eq!(orderbook.asks[1].quantity_quote, round(38440.0 * 0.0026)); assert_eq!(orderbook.asks[1].quantity_contract.unwrap(), 0.0026); } #[test] fn linear_swap_snapshot() { let raw_msg = r#"{"channel": "orderbook", "market": "BTC-PERP", "type": "partial", "data": {"time": 1622660997.436228, "checksum": 1855139817, "bids": [[37955.0, 0.2212], [37954.0, 0.0025], [37953.0, 0.0025]], "asks": [[37956.0, 4.8852], [37957.0, 0.022], [37958.0, 0.4818]], "action": "partial"}}"#; let orderbook = &parse_l2(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, None).unwrap()[0]; assert_eq!(orderbook.asks.len(), 3); assert_eq!(orderbook.bids.len(), 3); assert!(orderbook.snapshot); crate::utils::check_orderbook_fields( EXCHANGE_NAME, MarketType::LinearSwap, MessageType::L2Event, "BTC/USD".to_string(), extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(), orderbook, raw_msg, ); assert_eq!( 1622660997436, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap() ); assert_eq!(orderbook.timestamp, 1622660997436); assert_eq!(orderbook.bids[0].price, 37955.0); assert_eq!(orderbook.bids[0].quantity_base, 0.2212); assert_eq!(orderbook.bids[0].quantity_quote, 37955.0 * 0.2212); assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 0.2212); assert_eq!(orderbook.bids[2].price, 37953.0); assert_eq!(orderbook.bids[2].quantity_base, 0.0025); assert_eq!(orderbook.bids[2].quantity_quote, round(37953.0 * 0.0025)); assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 0.0025); assert_eq!(orderbook.asks[0].price, 37956.0); assert_eq!(orderbook.asks[0].quantity_base, 4.8852); assert_eq!(orderbook.asks[0].quantity_quote, round(37956.0 * 4.8852)); assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 4.8852); assert_eq!(orderbook.asks[2].price, 37958.0); assert_eq!(orderbook.asks[2].quantity_base, 0.4818); assert_eq!(orderbook.asks[2].quantity_quote, 37958.0 * 0.4818); assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 0.4818); } #[test] fn linear_swap_update() { let raw_msg = r#"{"channel": "orderbook", "market": "BTC-PERP", "type": "update", "data": {"time": 1622660997.4591022, "checksum": 276300987, "bids": [], "asks": [[37965.0, 19.6097]], "action": "update"}}"#; 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/USD".to_string(), extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(), orderbook, raw_msg, ); assert_eq!( 1622660997459, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap() ); assert_eq!(orderbook.timestamp, 1622660997459); assert_eq!(orderbook.asks[0].price, 37965.0); assert_eq!(orderbook.asks[0].quantity_base, 19.6097); assert_eq!(orderbook.asks[0].quantity_quote, 37965.0 * 19.6097); assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 19.6097); } } #[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#"{"channel":"ticker","market":"BTC/USD","type":"update","data":{"bid":31679.0,"ask":31680.0,"bidSize":1.8434,"askSize":1.1266,"last":31679.0,"time":1654029182.6905813}}"#; assert_eq!( 1654029182690, extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap() ); assert_eq!("BTC/USD", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()); let bbo_msg = &parse_bbo(EXCHANGE_NAME, MarketType::Spot, raw_msg, None).unwrap()[0]; assert_eq!(MessageType::BBO, bbo_msg.msg_type); assert_eq!("BTC/USD", bbo_msg.symbol); assert_eq!(1654029182690, bbo_msg.timestamp); assert_eq!(None, bbo_msg.id); assert_eq!(31680.0, bbo_msg.ask_price); assert_eq!(1.1266, bbo_msg.ask_quantity_base); assert_eq!(31680.0 * 1.1266, bbo_msg.ask_quantity_quote); assert_eq!(None, bbo_msg.ask_quantity_contract); assert_eq!(31679.0, bbo_msg.bid_price); assert_eq!(1.8434, bbo_msg.bid_quantity_base); assert_eq!(31679.0 * 1.8434, bbo_msg.bid_quantity_quote); assert_eq!(None, bbo_msg.bid_quantity_contract); } #[test] fn linear_swap() { let raw_msg = r#"{"channel":"ticker","market":"BTC-PERP","type":"update","data":{"bid":31699.0,"ask":31700.0,"bidSize":14.9905,"askSize":4.6393,"last":31699.0,"time":1654029408.920583}}"#; assert_eq!( 1654029408920, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap() ); assert_eq!("BTC-PERP", extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()); let bbo_msg = &parse_bbo(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, None).unwrap()[0]; assert_eq!(MessageType::BBO, bbo_msg.msg_type); assert_eq!("BTC-PERP", bbo_msg.symbol); assert_eq!(1654029408920, bbo_msg.timestamp); assert_eq!(None, bbo_msg.id); assert_eq!(31700.0, bbo_msg.ask_price); assert_eq!(4.6393, bbo_msg.ask_quantity_base); assert_eq!(round(31700.0 * 4.6393), bbo_msg.ask_quantity_quote); assert_eq!(Some(4.6393), bbo_msg.ask_quantity_contract); assert_eq!(31699.0, bbo_msg.bid_price); assert_eq!(14.9905, bbo_msg.bid_quantity_base); assert_eq!(31699.0 * 14.9905, bbo_msg.bid_quantity_quote); assert_eq!(Some(14.9905), bbo_msg.bid_quantity_contract); } #[test] fn linear_future() { let raw_msg = r#"{"channel":"ticker","market":"BTC-0624","type":"update","data":{"bid":31746.0,"ask":31747.0,"bidSize":1.0727,"askSize":0.1,"last":31760.0,"time":1654029472.207374}}"#; assert_eq!( 1654029472207, extract_timestamp(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap().unwrap() ); assert_eq!( "BTC-0624", extract_symbol(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).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!("BTC-0624", bbo_msg.symbol); assert_eq!(1654029472207, bbo_msg.timestamp); assert_eq!(None, bbo_msg.id); assert_eq!(31747.0, bbo_msg.ask_price); assert_eq!(0.1, bbo_msg.ask_quantity_base); assert_eq!(round(31747.0 * 0.1), bbo_msg.ask_quantity_quote); assert_eq!(Some(0.1), bbo_msg.ask_quantity_contract); assert_eq!(31746.0, bbo_msg.bid_price); assert_eq!(1.0727, bbo_msg.bid_quantity_base); assert_eq!(round(31746.0 * 1.0727), bbo_msg.bid_quantity_quote); assert_eq!(Some(1.0727), bbo_msg.bid_quantity_contract); } } #[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#"{"success":true,"result":{"bids":[[1151.0,0.36],[1150.0,0.683],[1149.5,0.651],[1148.5,13.132],[1148.0,3.057]],"asks":[[1153.5,13.326],[1154.0,0.622],[1154.5,4.182],[1155.0,26.58],[1156.0,4.106]]}}"#; 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#"{"success":true,"result":{"bids":[[1151.0,0.36],[1150.0,0.683],[1149.5,0.651],[1148.5,13.132],[1148.0,3.057]],"asks":[[1153.5,13.326],[1154.0,0.622],[1154.5,4.182],[1155.0,26.58],[1156.0,4.106]]}}"#; assert_eq!("NONE", extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()); assert_eq!( None, extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap() ); } #[test] fn linear_future() { let raw_msg = r#"{"success":true,"result":{"bids":[[30215.0,0.0004],[30210.0,0.1287],[30209.0,0.9605],[30207.0,0.0824],[30206.0,0.1721]],"asks":[[30225.0,0.6408],[30226.0,0.8258],[30227.0,2.6539],[30228.0,0.3609],[30229.0,0.2078]]}}"#; assert_eq!( "NONE", extract_symbol(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap() ); assert_eq!( None, extract_timestamp(EXCHANGE_NAME, MarketType::LinearFuture, raw_msg).unwrap() ); } } #[cfg(test)] mod open_interest { use super::EXCHANGE_NAME; use crypto_market_type::MarketType; use crypto_msg_parser::{extract_symbol, extract_timestamp}; #[test] fn unknown() { let raw_msg = r#"{"success":true,"result":[{"name":"1INCH-PERP","underlying":"1INCH","description":"1INCH Token Perpetual Futures","type":"perpetual","expiry":null,"perpetual":true,"expired":false,"enabled":true,"postOnly":false,"priceIncrement":0.0001,"sizeIncrement":1.0,"last":0.8525,"bid":0.8526,"ask":0.853,"index":0.853847992062,"mark":0.8528,"imfFactor":0.0005,"lowerBound":0.8099,"upperBound":0.8965,"underlyingDescription":"1INCH Token","expiryDescription":"Perpetual","moveStart":null,"marginPrice":0.8528,"positionLimitWeight":20.0,"group":"perpetual","change1h":-0.009868802972251248,"change24h":-0.023474178403755867,"changeBod":-0.0217939894471209,"volumeUsd24h":6256487.5398,"volume":7237781.0,"openInterest":16277750.0,"openInterestUsd":13881665.2},{"name":"1INCH-0624","underlying":"1INCH","description":"1INCH Token June 2022 Futures","type":"future","expiry":"2022-06-24T03:00:00+00:00","perpetual":false,"expired":false,"enabled":true,"postOnly":false,"priceIncrement":0.0001,"sizeIncrement":1.0,"last":0.8292,"bid":0.8276,"ask":0.8292,"index":0.853847992062,"mark":0.8292,"imfFactor":0.0005,"lowerBound":0.7855,"upperBound":0.8965,"underlyingDescription":"1INCH Token","expiryDescription":"June 2022","moveStart":null,"marginPrice":0.8292,"positionLimitWeight":40.0,"group":"quarterly","change1h":-0.008133971291866028,"change24h":-0.01367907695967646,"changeBod":-0.011916110581506196,"volumeUsd24h":68694.8909,"volume":82273.0,"openInterest":849727.0,"openInterestUsd":704593.6284}]}"#; assert_eq!("ALL", extract_symbol(EXCHANGE_NAME, MarketType::Unknown, raw_msg).unwrap()); assert_eq!(None, extract_timestamp(EXCHANGE_NAME, MarketType::Unknown, raw_msg).unwrap()); } }