mod utils;
const EXCHANGE_NAME: &str = "deribit";
#[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};
#[test]
fn inverse_future() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"trades.BTC-26MAR21.raw","data":[{"trade_seq":5326971,"trade_id":"137486952","timestamp":1616321287195,"tick_direction":0,"price":56273.5,"mark_price":56243.86,"instrument_name":"BTC-26MAR21","index_price":56127.59,"direction":"buy","amount":6000.0}]}}"#;
let trades = &parse_trade(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap();
assert_eq!(trades.len(), 1);
for trade in trades.iter() {
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!(
1616321287195,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(trades[0].quantity_base, 10.0 * 6000.0 / 56273.5);
assert_eq!(trades[0].quantity_quote, 10.0 * 6000.0);
assert_eq!(trades[0].quantity_contract, Some(6000.0));
assert_eq!(trades[0].side, TradeSide::Buy);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"trades.BTC-PERPETUAL.raw","data":[{"trade_seq":92836831,"trade_id":"137487241","timestamp":1616321478553,"tick_direction":1,"price":56168.0,"mark_price":56172.08,"instrument_name":"BTC-PERPETUAL","index_price":56173.74,"direction":"buy","amount":5580.0},{"trade_seq":92836832,"trade_id":"137487242","timestamp":1616321478553,"tick_direction":1,"price":56168.0,"mark_price":56172.08,"instrument_name":"BTC-PERPETUAL","index_price":56173.74,"direction":"buy","amount":60.0}]}}"#;
let trades = &parse_trade(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap();
assert_eq!(trades.len(), 2);
for trade in trades.iter() {
crate::utils::check_trade_fields(
EXCHANGE_NAME,
MarketType::InverseSwap,
"BTC/USD".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap(),
trade,
raw_msg,
);
assert_eq!(trade.side, TradeSide::Buy);
}
assert_eq!(
1616321478553,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(trades[0].price, 56168.0);
assert_eq!(trades[0].quantity_base, 10.0 * 5580.0 / 56168.0);
assert_eq!(trades[0].quantity_quote, 10.0 * 5580.0);
assert_eq!(trades[0].quantity_contract, Some(5580.0));
assert_eq!(trades[0].side, TradeSide::Buy);
// volume == amount
assert_eq!(trades[0].quantity_quote, 10.0 * 5580.0);
assert_eq!(trades[1].quantity_quote, 10.0 * 60.0);
}
#[test]
fn option() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"trades.option.any.raw","data":[{"trade_seq":1706,"trade_id":"137488100","timestamp":1616321732986,"tick_direction":0,"price":0.007,"mark_price":0.00670817,"iv":78.44,"instrument_name":"BTC-26MAR21-62000-C","index_price":56151.63,"direction":"buy","amount":0.1}]}}"#;
let trades = &parse_trade(EXCHANGE_NAME, MarketType::EuropeanOption, raw_msg).unwrap();
assert_eq!(trades.len(), 1);
for trade in trades.iter() {
crate::utils::check_trade_fields(
EXCHANGE_NAME,
MarketType::EuropeanOption,
"BTC/BTC".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::EuropeanOption, raw_msg).unwrap(),
trade,
raw_msg,
);
assert_eq!(trade.side, TradeSide::Buy);
}
assert_eq!(
1616321732986,
extract_timestamp(EXCHANGE_NAME, MarketType::EuropeanOption, raw_msg).unwrap().unwrap()
);
assert_eq!(trades[0].quantity_base, 0.1);
assert_eq!(trades[0].quantity_quote, 0.007 * 0.1);
assert_eq!(trades[0].quantity_contract, Some(0.1));
}
}
#[cfg(test)]
mod l2_event {
use super::EXCHANGE_NAME;
use crypto_market_type::MarketType;
use crypto_msg_parser::{extract_symbol, extract_timestamp, parse_l2};
use crypto_msg_type::MessageType;
#[test]
fn inverse_future_snapshot() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"book.BTC-25JUN21.100ms","data":{"type":"snapshot","timestamp":1622626472678,"instrument_name":"BTC-25JUN21","change_id":31479219781,"bids":[["new",37317.0,2960.0],["new",37311.5,530.0],["new",37311.0,45170.0]],"asks":[["new",37327.0,10.0],["new",37327.5,20000.0],["new",37328.0,3000.0]]}}}"#;
let orderbook =
&parse_l2(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 3);
assert_eq!(orderbook.bids.len(), 3);
assert!(orderbook.snapshot);
crate::utils::check_orderbook_fields(
EXCHANGE_NAME,
MarketType::InverseFuture,
MessageType::L2Event,
"BTC/USD".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1622626472678,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1622626472678);
assert_eq!(orderbook.seq_id, Some(31479219781));
assert_eq!(orderbook.prev_seq_id, None);
assert_eq!(orderbook.bids[0].price, 37317.0);
assert_eq!(orderbook.bids[0].quantity_base, 10.0 * 2960.0 / 37317.0);
assert_eq!(orderbook.bids[0].quantity_quote, 10.0 * 2960.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 2960.0);
assert_eq!(orderbook.bids[2].price, 37311.0);
assert_eq!(orderbook.bids[2].quantity_base, 10.0 * 45170.0 / 37311.0);
assert_eq!(orderbook.bids[2].quantity_quote, 10.0 * 45170.0);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 45170.0);
assert_eq!(orderbook.asks[0].price, 37327.0);
assert_eq!(orderbook.asks[0].quantity_base, 10.0 * 10.0 / 37327.0);
assert_eq!(orderbook.asks[0].quantity_quote, 10.0 * 10.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 10.0);
assert_eq!(orderbook.asks[2].price, 37328.0);
assert_eq!(orderbook.asks[2].quantity_base, 10.0 * 3000.0 / 37328.0);
assert_eq!(orderbook.asks[2].quantity_quote, 10.0 * 3000.0);
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 3000.0);
}
#[test]
fn inverse_future_update() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"book.BTC-25JUN21.100ms","data":{"type":"change","timestamp":1622626784890,"prev_change_id":31479339296,"instrument_name":"BTC-25JUN21","change_id":31479339507,"bids":[["new",37392.5,3000.0],["change",37399.0,6530.0]],"asks":[["new",37850.0,8850.0],["delete",37848.5,0.0]]}}}"#;
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!(
1622626784890,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1622626784890);
assert_eq!(orderbook.seq_id, Some(31479339507));
assert_eq!(orderbook.prev_seq_id, Some(31479339296));
assert_eq!(orderbook.bids[0].price, 37392.5);
assert_eq!(orderbook.bids[0].quantity_base, 10.0 * 3000.0 / 37392.5);
assert_eq!(orderbook.bids[0].quantity_quote, 10.0 * 3000.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 3000.0);
assert_eq!(orderbook.bids[1].price, 37399.0);
assert_eq!(orderbook.bids[1].quantity_base, 10.0 * 6530.0 / 37399.0);
assert_eq!(orderbook.bids[1].quantity_quote, 10.0 * 6530.0);
assert_eq!(orderbook.bids[1].quantity_contract.unwrap(), 6530.0);
assert_eq!(orderbook.asks[0].price, 37850.0);
assert_eq!(orderbook.asks[0].quantity_base, 10.0 * 8850.0 / 37850.0);
assert_eq!(orderbook.asks[0].quantity_quote, 10.0 * 8850.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 8850.0);
assert_eq!(orderbook.asks[1].price, 37848.5);
assert_eq!(orderbook.asks[1].quantity_base, 0.0 / 37848.5);
assert_eq!(orderbook.asks[1].quantity_quote, 0.0);
assert_eq!(orderbook.asks[1].quantity_contract.unwrap(), 0.0);
}
#[test]
fn inverse_swap_snapshot() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"book.BTC-PERPETUAL.100ms","data":{"type":"snapshot","timestamp":1622627433440,"instrument_name":"BTC-PERPETUAL","change_id":31479596557,"bids":[["new",37240.0,20.0],["new",37237.0,14270.0],["new",37233.0,50.0]],"asks":[["new",37240.5,14240.0],["new",37248.5,15690.0],["new",37251.0,650.0]]}}}"#;
let orderbook =
&parse_l2(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg, None).unwrap()[0];
assert_eq!(orderbook.asks.len(), 3);
assert_eq!(orderbook.bids.len(), 3);
assert!(orderbook.snapshot);
assert_eq!(orderbook.timestamp, 1622627433440);
assert_eq!(orderbook.seq_id, Some(31479596557));
assert_eq!(orderbook.prev_seq_id, None);
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!(
1622627433440,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.bids[0].price, 37240.0);
assert_eq!(orderbook.bids[0].quantity_base, 10.0 * 20.0 / 37240.0);
assert_eq!(orderbook.bids[0].quantity_quote, 10.0 * 20.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 20.0);
assert_eq!(orderbook.bids[2].price, 37233.0);
assert_eq!(orderbook.bids[2].quantity_base, 10.0 * 50.0 / 37233.0);
assert_eq!(orderbook.bids[2].quantity_quote, 10.0 * 50.0);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 50.0);
assert_eq!(orderbook.asks[0].price, 37240.5);
assert_eq!(orderbook.asks[0].quantity_base, 10.0 * 14240.0 / 37240.5);
assert_eq!(orderbook.asks[0].quantity_quote, 10.0 * 14240.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 14240.0);
assert_eq!(orderbook.asks[2].price, 37251.0);
assert_eq!(orderbook.asks[2].quantity_base, 10.0 * 650.0 / 37251.0);
assert_eq!(orderbook.asks[2].quantity_quote, 10.0 * 650.0);
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 650.0);
}
#[test]
fn inverse_swap_update() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"book.BTC-PERPETUAL.100ms","data":{"type":"change","timestamp":1622627435737,"prev_change_id":31479598064,"instrument_name":"BTC-PERPETUAL","change_id":31479598217,"bids":[["delete",36779.0,0.0],["new",36809.5,254870.0]],"asks":[["delete",37462.5,0.0],["change",37394.0,42670.0]]}}}"#;
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);
assert_eq!(orderbook.timestamp, 1622627435737);
assert_eq!(orderbook.seq_id, Some(31479598217));
assert_eq!(orderbook.prev_seq_id, Some(31479598064));
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!(
1622627435737,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.bids[0].price, 36779.0);
assert_eq!(orderbook.bids[0].quantity_base, 0.0 / 36779.0);
assert_eq!(orderbook.bids[0].quantity_quote, 0.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 0.0);
assert_eq!(orderbook.bids[1].price, 36809.5);
assert_eq!(orderbook.bids[1].quantity_base, 10.0 * 254870.0 / 36809.5);
assert_eq!(orderbook.bids[1].quantity_quote, 10.0 * 254870.0);
assert_eq!(orderbook.bids[1].quantity_contract.unwrap(), 254870.0);
assert_eq!(orderbook.asks[0].price, 37462.5);
assert_eq!(orderbook.asks[0].quantity_base, 0.0 / 37462.5);
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, 37394.0);
assert_eq!(orderbook.asks[1].quantity_base, 10.0 * 42670.0 / 37394.0);
assert_eq!(orderbook.asks[1].quantity_quote, 10.0 * 42670.0);
assert_eq!(orderbook.asks[1].quantity_contract.unwrap(), 42670.0);
}
#[test]
fn option_snapshot() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"book.BTC-11JUN21-25000-P.100ms","data":{"type":"snapshot","timestamp":1622627851747,"instrument_name":"BTC-11JUN21-25000-P","change_id":31479771122,"bids":[["new",0.005,13.7],["new",0.0045,5.7],["new",0.004,61.6]],"asks":[["new",0.006,64.5],["new",0.0065,48.0],["new",0.0085,0.5]]}}}"#;
let orderbook =
&parse_l2(EXCHANGE_NAME, MarketType::EuropeanOption, 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::EuropeanOption,
MessageType::L2Event,
"BTC/BTC".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::EuropeanOption, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1622627851747,
extract_timestamp(EXCHANGE_NAME, MarketType::EuropeanOption, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1622627851747);
assert_eq!(orderbook.seq_id, Some(31479771122));
assert_eq!(orderbook.prev_seq_id, None);
assert_eq!(orderbook.bids[0].price, 0.005);
assert_eq!(orderbook.bids[0].quantity_base, 13.7);
assert_eq!(orderbook.bids[0].quantity_quote, 0.005 * 13.7);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 13.7);
assert_eq!(orderbook.bids[2].price, 0.004);
assert_eq!(orderbook.bids[2].quantity_base, 61.6);
assert_eq!(orderbook.bids[2].quantity_quote, 0.004 * 61.6);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 61.6);
assert_eq!(orderbook.asks[0].price, 0.006);
assert_eq!(orderbook.asks[0].quantity_base, 64.5);
assert_eq!(orderbook.asks[0].quantity_quote, 0.006 * 64.5);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 64.5);
assert_eq!(orderbook.asks[2].price, 0.0085);
assert_eq!(orderbook.asks[2].quantity_base, 0.5);
assert_eq!(orderbook.asks[2].quantity_quote, 0.0085 * 0.5);
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 0.5);
}
}
#[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};
use crypto_msg_type::MessageType;
#[test]
fn inverse_future() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"book.BTC-30SEP22.none.20.100ms","data":{"timestamp":1653982973195,"instrument_name":"BTC-30SEP22","change_id":45176371821,"bids":[[31975.0,1370.0],[31966.0,2200.0],[31961.0,300.0]],"asks":[[31976.5,2500.0],[31979.0,60.0],[31982.0,2200.0]]}}}"#;
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!(
1653982973195,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1653982973195);
assert_eq!(orderbook.seq_id, Some(45176371821));
assert_eq!(orderbook.prev_seq_id, None);
assert_eq!(orderbook.bids[0].price, 31975.0);
assert_eq!(orderbook.bids[0].quantity_base, 10.0 * 1370.0 / 31975.0);
assert_eq!(orderbook.bids[0].quantity_quote, 10.0 * 1370.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 1370.0);
assert_eq!(orderbook.bids[2].price, 31961.0);
assert_eq!(orderbook.bids[2].quantity_base, 10.0 * 300.0 / 31961.0);
assert_eq!(orderbook.bids[2].quantity_quote, 10.0 * 300.0);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 300.0);
assert_eq!(orderbook.asks[0].price, 31976.5);
assert_eq!(orderbook.asks[0].quantity_base, 10.0 * 2500.0 / 31976.5);
assert_eq!(orderbook.asks[0].quantity_quote, 10.0 * 2500.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 2500.0);
assert_eq!(orderbook.asks[2].price, 31982.0);
assert_eq!(orderbook.asks[2].quantity_base, 10.0 * 2200.0 / 31982.0);
assert_eq!(orderbook.asks[2].quantity_quote, 10.0 * 2200.0);
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 2200.0);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"book.BTC-PERPETUAL.none.20.100ms","data":{"timestamp":1653983481909,"instrument_name":"BTC-PERPETUAL","change_id":45176552517,"bids":[[31523.5,128780.0],[31523.0,190.0],[31521.5,14500.0]],"asks":[[31524.0,30.0],[31525.0,30.0],[31525.5,6010.0]]}}}"#;
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!(
1653983481909,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1653983481909);
assert_eq!(orderbook.seq_id, Some(45176552517));
assert_eq!(orderbook.prev_seq_id, None);
assert_eq!(orderbook.bids[0].price, 31523.5);
assert_eq!(orderbook.bids[0].quantity_base, 10.0 * 128780.0 / 31523.5);
assert_eq!(orderbook.bids[0].quantity_quote, 10.0 * 128780.0);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 128780.0);
assert_eq!(orderbook.bids[2].price, 31521.5);
assert_eq!(orderbook.bids[2].quantity_base, 10.0 * 14500.0 / 31521.5);
assert_eq!(orderbook.bids[2].quantity_quote, 10.0 * 14500.0);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 14500.0);
assert_eq!(orderbook.asks[0].price, 31524.0);
assert_eq!(orderbook.asks[0].quantity_base, 10.0 * 30.0 / 31524.0);
assert_eq!(orderbook.asks[0].quantity_quote, 10.0 * 30.0);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 30.0);
assert_eq!(orderbook.asks[2].price, 31525.5);
assert_eq!(orderbook.asks[2].quantity_base, 10.0 * 6010.0 / 31525.5);
assert_eq!(orderbook.asks[2].quantity_quote, 10.0 * 6010.0);
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 6010.0);
}
#[test]
fn option() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"book.BTC-30SEP22-60000-C.none.20.100ms","data":{"timestamp":1653983742265,"instrument_name":"BTC-30SEP22-60000-C","change_id":45176637818,"bids":[[0.011,15.4],[0.0105,42.2],[0.01,4.1]],"asks":[[0.012,10.2],[0.0125,16.6],[0.013,44.4]]}}}"#;
let orderbook =
&parse_l2_topk(EXCHANGE_NAME, MarketType::EuropeanOption, 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::EuropeanOption,
MessageType::L2TopK,
"BTC/BTC".to_string(),
extract_symbol(EXCHANGE_NAME, MarketType::EuropeanOption, raw_msg).unwrap(),
orderbook,
raw_msg,
);
assert_eq!(
1653983742265,
extract_timestamp(EXCHANGE_NAME, MarketType::EuropeanOption, raw_msg).unwrap().unwrap()
);
assert_eq!(orderbook.timestamp, 1653983742265);
assert_eq!(orderbook.seq_id, Some(45176637818));
assert_eq!(orderbook.prev_seq_id, None);
assert_eq!(orderbook.bids[0].price, 0.011);
assert_eq!(orderbook.bids[0].quantity_base, 15.4);
assert_eq!(orderbook.bids[0].quantity_quote, 0.011 * 15.4);
assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 15.4);
assert_eq!(orderbook.bids[2].price, 0.01);
assert_eq!(orderbook.bids[2].quantity_base, 4.1);
assert_eq!(orderbook.bids[2].quantity_quote, 0.01 * 4.1);
assert_eq!(orderbook.bids[2].quantity_contract.unwrap(), 4.1);
assert_eq!(orderbook.asks[0].price, 0.012);
assert_eq!(orderbook.asks[0].quantity_base, 10.2);
assert_eq!(orderbook.asks[0].quantity_quote, 0.012 * 10.2);
assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 10.2);
assert_eq!(orderbook.asks[2].price, 0.013);
assert_eq!(orderbook.asks[2].quantity_base, 44.4);
assert_eq!(orderbook.asks[2].quantity_quote, 0.013 * 44.4);
assert_eq!(orderbook.asks[2].quantity_contract.unwrap(), 44.4);
}
}
#[cfg(test)]
mod bbo {
use super::EXCHANGE_NAME;
use crypto_market_type::MarketType;
use crypto_msg_parser::{extract_symbol, extract_timestamp, parse_bbo};
use crypto_msg_type::MessageType;
#[test]
fn inverse_future() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"quote.BTC-30SEP22","data":{"timestamp":1654012570801,"instrument_name":"BTC-30SEP22","best_bid_price":32499.0,"best_bid_amount":2370.0,"best_ask_price":32503.5,"best_ask_amount":2400.0}}}"#;
assert_eq!(
1654012570801,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-30SEP22",
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap()
);
let bbo_msg =
&parse_bbo(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg, None).unwrap()[0];
assert_eq!(MessageType::BBO, bbo_msg.msg_type);
assert_eq!("BTC-30SEP22", bbo_msg.symbol);
assert_eq!(1654012570801, bbo_msg.timestamp);
assert_eq!(None, bbo_msg.id);
assert_eq!(32503.5, bbo_msg.ask_price);
assert_eq!(0.7383820203978033, bbo_msg.ask_quantity_base);
assert_eq!(24000.0, bbo_msg.ask_quantity_quote);
assert_eq!(Some(2400.0), bbo_msg.ask_quantity_contract);
assert_eq!(32499.0, bbo_msg.bid_price);
assert_eq!(0.729253207791009, bbo_msg.bid_quantity_base);
assert_eq!(23700.0, bbo_msg.bid_quantity_quote);
assert_eq!(Some(2370.0), bbo_msg.bid_quantity_contract);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"quote.BTC-PERPETUAL","data":{"timestamp":1654012882984,"instrument_name":"BTC-PERPETUAL","best_bid_price":32143.0,"best_bid_amount":179960.0,"best_ask_price":32143.5,"best_ask_amount":20.0}}}"#;
assert_eq!(
1654012882984,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-PERPETUAL",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
let bbo_msg = &parse_bbo(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg, None).unwrap()[0];
assert_eq!(MessageType::BBO, bbo_msg.msg_type);
assert_eq!("BTC-PERPETUAL", bbo_msg.symbol);
assert_eq!(1654012882984, bbo_msg.timestamp);
assert_eq!(None, bbo_msg.id);
assert_eq!(32143.5, bbo_msg.ask_price);
assert_eq!(0.006222097780266617, bbo_msg.ask_quantity_base);
assert_eq!(200.0, bbo_msg.ask_quantity_quote);
assert_eq!(Some(20.0), bbo_msg.ask_quantity_contract);
assert_eq!(32143.0, bbo_msg.bid_price);
assert_eq!(55.98730672308123, bbo_msg.bid_quantity_base);
assert_eq!(1799600.0, bbo_msg.bid_quantity_quote);
assert_eq!(Some(179960.0), bbo_msg.bid_quantity_contract);
}
}
#[cfg(test)]
mod candlestick {
use super::EXCHANGE_NAME;
use crypto_market_type::MarketType;
use crypto_msg_parser::{extract_symbol, extract_timestamp, parse_candlestick};
#[test]
fn inverse_future() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"chart.trades.BTC-31MAR23.1","data":{"volume":0.00172302,"tick":1677628800000,"open":23215.0,"low":23215.0,"high":23215.0,"cost":40.0,"close":23215.0}}}"#;
let arr =
parse_candlestick(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg, None).unwrap();
assert_eq!(
1677628800000,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-31MAR23",
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap()
);
assert_eq!(1, arr.len());
let candlestick_msg = &arr[0];
assert_eq!("BTC-31MAR23", candlestick_msg.symbol);
assert_eq!("BTC/USD", candlestick_msg.pair);
assert_eq!(1677628800000, candlestick_msg.timestamp);
assert_eq!(1677628740000, candlestick_msg.begin_time);
assert_eq!("1", candlestick_msg.period);
assert_eq!(23215.0, candlestick_msg.open);
assert_eq!(23215.0, candlestick_msg.high);
assert_eq!(23215.0, candlestick_msg.low);
assert_eq!(23215.0, candlestick_msg.close);
assert_eq!(0.00172302, candlestick_msg.volume);
assert_eq!(Some(40.0), candlestick_msg.quote_volume);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"chart.trades.BTC-PERPETUAL.1","data":{"volume":0.02120555,"tick":1654079340000,"open":31595.5,"low":31595.5,"high":31595.5,"cost":670.0,"close":31595.5}}}"#;
let arr =
parse_candlestick(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg, None).unwrap();
assert_eq!(
1654079340000,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-PERPETUAL",
extract_symbol(EXCHANGE_NAME, MarketType::InverseSwap, raw_msg).unwrap()
);
let candlestick_msg = &arr[0];
assert_eq!("BTC-PERPETUAL", candlestick_msg.symbol);
assert_eq!("BTC/USD", candlestick_msg.pair);
assert_eq!(1654079340000, candlestick_msg.timestamp);
assert_eq!(1654079280000, candlestick_msg.begin_time);
assert_eq!("1", candlestick_msg.period);
assert_eq!(31595.5, candlestick_msg.open);
assert_eq!(31595.5, candlestick_msg.high);
assert_eq!(31595.5, candlestick_msg.low);
assert_eq!(31595.5, candlestick_msg.close);
assert_eq!(0.02120555, candlestick_msg.volume);
assert_eq!(Some(670.0), candlestick_msg.quote_volume);
}
#[test]
fn option() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"chart.trades.BTC-25MAR23-26500-P.3","data":{"volume":0.1,"tick":1679559480000,"open":0.003,"low":0.003,"high":0.003,"cost":0.0003,"close":0.003}}}"#;
let arr =
parse_candlestick(EXCHANGE_NAME, MarketType::EuropeanOption, raw_msg, None).unwrap();
assert_eq!(
1679559480000,
extract_timestamp(EXCHANGE_NAME, MarketType::EuropeanOption, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-25MAR23-26500-P",
extract_symbol(EXCHANGE_NAME, MarketType::EuropeanOption, raw_msg).unwrap()
);
let candlestick_msg = &arr[0];
assert_eq!("BTC-25MAR23-26500-P", candlestick_msg.symbol);
assert_eq!("BTC/BTC", candlestick_msg.pair);
assert_eq!(1679559480000, candlestick_msg.timestamp);
assert_eq!(1679559300000, candlestick_msg.begin_time);
assert_eq!("3", candlestick_msg.period);
assert_eq!(0.003, candlestick_msg.open);
assert_eq!(0.003, candlestick_msg.high);
assert_eq!(0.003, candlestick_msg.low);
assert_eq!(0.003, candlestick_msg.close);
assert_eq!(0.1, candlestick_msg.volume);
assert_eq!(Some(0.0003), 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_future() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"ticker.BTC-30SEP22.100ms","data":{"timestamp":1654161740658,"stats":{"volume_usd":23223070.0,"volume":754.95506101,"price_change":-5.5392,"low":29592.5,"high":32248.0},"state":"open","settlement_price":30225.47,"open_interest":230733270,"min_price":29766.5,"max_price":30673.5,"mark_price":30218.9,"last_price":30218.0,"instrument_name":"BTC-30SEP22","index_price":29939.87,"estimated_delivery_price":29939.87,"best_bid_price":30220.0,"best_bid_amount":2300.0,"best_ask_price":30222.0,"best_ask_amount":4370.0}}}"#;
assert_eq!(
1654161740658,
extract_timestamp(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-30SEP22",
extract_symbol(EXCHANGE_NAME, MarketType::Spot, raw_msg).unwrap()
);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"ticker.BTC-PERPETUAL.100ms","data":{"timestamp":1654161785818,"stats":{"volume_usd":545442610.0,"volume":17945.19644566,"price_change":-5.4014,"low":29265.5,"high":31903.5},"state":"open","settlement_price":29945.69,"open_interest":559791310,"min_price":29485.31,"max_price":30383.34,"mark_price":29932.79,"last_price":29931.0,"instrument_name":"BTC-PERPETUAL","index_price":29930.44,"funding_8h":0.00000255,"estimated_delivery_price":29930.44,"current_funding":0.0,"best_bid_price":29930.5,"best_bid_amount":149910.0,"best_ask_price":29931.0,"best_ask_amount":62850.0}}}"#;
assert_eq!(
1654161785818,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-PERPETUAL",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
}
#[test]
fn option() {
let raw_msg = r#"{"jsonrpc":"2.0","method":"subscription","params":{"channel":"ticker.BTC-30SEP22-60000-C.100ms","data":{"underlying_price":30220.5,"underlying_index":"BTC-30SEP22","timestamp":1654161839367,"stats":{"volume":16.7,"price_change":-18.1818,"low":0.009,"high":0.011},"state":"open","settlement_price":0.01,"open_interest":1767.5,"min_price":0.0001,"max_price":0.038,"mark_price":0.0084,"mark_iv":67.7,"last_price":0.009,"interest_rate":0.0,"instrument_name":"BTC-30SEP22-60000-C","index_price":29939.43,"greeks":{"vega":20.05335,"theta":-5.65962,"rho":4.91491,"gamma":0.00001,"delta":0.05785},"estimated_delivery_price":29939.43,"bid_iv":67.16,"best_bid_price":0.008,"best_bid_amount":2.8,"best_ask_price":0.009,"best_ask_amount":18.5,"ask_iv":68.65}}}"#;
assert_eq!(
1654161839367,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"BTC-30SEP22-60000-C",
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 inverse_future() {
let raw_msg = r#"{"jsonrpc":"2.0","result":{"timestamp":1654245922403,"stats":{"volume_usd":10190920.0,"volume":335.62468116,"price_change":1.6501,"low":29846.0,"high":30976.5},"state":"open","settlement_price":30749.45,"open_interest":232318090,"min_price":30256.0,"max_price":31178.0,"mark_price":30717.33,"last_price":30709.5,"instrument_name":"BTC-30SEP22","index_price":30410.37,"estimated_delivery_price":30410.37,"change_id":45305026640,"bids":[[30718.5,2290.0],[30718.0,3000.0],[30714.0,5000.0]],"best_bid_price":30718.5,"best_bid_amount":2290.0,"best_ask_price":30723.0,"best_ask_amount":3000.0,"asks":[[30723.0,3000.0],[30723.5,29470.0],[30725.0,1380.0]]},"usIn":1654245922540414,"usOut":1654245922540910,"usDiff":496,"testnet":false}"#;
assert_eq!(
"BTC-30SEP22",
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap()
);
assert_eq!(
1654245922403,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"jsonrpc":"2.0","result":{"timestamp":1654246806027,"stats":{"volume_usd":278922050.0,"volume":9229.89241729,"price_change":1.721,"low":29583.5,"high":30729.0},"state":"open","settlement_price":30458.76,"open_interest":560520540,"min_price":29980.5,"max_price":30893.61,"mark_price":30436.94,"last_price":30439.5,"instrument_name":"BTC-PERPETUAL","index_price":30418.45,"funding_8h":0.00002085,"estimated_delivery_price":30418.45,"current_funding":0.00010785,"change_id":45305261539,"bids":[[30434.5,600.0],[30433.0,15000.0],[30431.0,15010.0]],"best_bid_price":30434.5,"best_bid_amount":600.0,"best_ask_price":30435.0,"best_ask_amount":198440.0,"asks":[[30435.0,198440.0],[30438.5,1000.0],[30439.5,188330.0]]},"usIn":1654246806051360,"usOut":1654246806055238,"usDiff":3878,"testnet":false}"#;
assert_eq!(
"BTC-PERPETUAL",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
assert_eq!(
1654246806027,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
}
#[test]
fn option() {
let raw_msg = r#"{"jsonrpc":"2.0","result":{"underlying_price":1806.5,"underlying_index":"ETH-24JUN22","timestamp":1654247489923,"stats":{"volume":1117.0,"price_change":-8.4507,"low":0.031,"high":0.036},"state":"open","settlement_price":0.03,"open_interest":15009.0,"min_price":0.009,"max_price":0.0795,"mark_price":0.0336,"mark_iv":86.54,"last_price":0.0325,"interest_rate":0.0,"instrument_name":"ETH-24JUN22-1600-P","index_price":1804.41,"greeks":{"vega":1.36169,"theta":-2.81237,"rho":-0.28927,"gamma":0.00084,"delta":-0.24537},"estimated_delivery_price":1804.41,"change_id":24460060432,"bids":[[0.033,226.0],[0.0325,797.0],[0.032,355.0]],"bid_iv":85.74,"best_bid_price":0.033,"best_bid_amount":226.0,"best_ask_price":0.034,"best_ask_amount":595.0,"asks":[[0.034,595.0],[0.0345,779.0],[0.035,186.0]],"ask_iv":87.07},"usIn":1654247489999588,"usOut":1654247489999885,"usDiff":297,"testnet":false}"#;
assert_eq!(
1654247489923,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"ETH-24JUN22-1600-P",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
}
}
#[cfg(test)]
mod open_interest {
use super::EXCHANGE_NAME;
use crypto_market_type::MarketType;
use crypto_msg_parser::{extract_symbol, extract_timestamp};
#[test]
fn inverse_future() {
let raw_msg = r#"{"jsonrpc":"2.0","result":[{"volume_usd":12498220.0,"volume_notional":12498220.0,"volume":422.01,"quote_currency":"USD","price_change":-0.2148,"open_interest":272308070,"mid_price":29730.25,"mark_price":29727.97,"low":29280.5,"last":29724.5,"instrument_name":"BTC-24JUN22","high":29973.0,"estimated_delivery_price":29695.94,"creation_timestamp":1654341687529,"bid_price":29729.5,"base_currency":"BTC","ask_price":29731.0}],"usIn":1654341687528897,"usOut":1654341687529042,"usDiff":145,"testnet":false}"#;
assert_eq!(
"BTC-24JUN22",
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap()
);
assert_eq!(
1654341687529,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
}
#[test]
fn inverse_future_all() {
let raw_msg = r#"{"jsonrpc":"2.0","result":[{"volume":175.6,"underlying_price":29755.49,"underlying_index":"BTC-24JUN22","quote_currency":"BTC","price_change":-13.2231,"open_interest":1124.7,"mid_price":0.053,"mark_price":0.05317014,"low":0.0515,"last":0.0525,"interest_rate":0.0,"instrument_name":"BTC-24JUN22-30000-C","high":0.0605,"estimated_delivery_price":29716.47,"creation_timestamp":1654338604906,"bid_price":0.0525,"base_currency":"BTC","ask_price":0.0535},{"volume":0.0,"underlying_price":30236.72,"underlying_index":"BTC-30DEC22","quote_currency":"BTC","price_change":null,"open_interest":8.1,"mid_price":null,"mark_price":1.98432769,"low":null,"last":1.099,"interest_rate":0.0,"instrument_name":"BTC-30DEC22-90000-P","high":null,"estimated_delivery_price":29716.47,"creation_timestamp":1654338604906,"bid_price":null,"base_currency":"BTC","ask_price":null}],"usIn":1654338604904465,"usOut":1654338604920779,"usDiff":16314,"testnet":false}"#;
assert_eq!(
"ALL",
extract_symbol(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap()
);
assert_eq!(
1654338604906,
extract_timestamp(EXCHANGE_NAME, MarketType::InverseFuture, raw_msg).unwrap().unwrap()
);
}
#[test]
fn inverse_swap() {
let raw_msg = r#"{"jsonrpc":"2.0","result":[{"volume_usd":223275080.0,"volume_notional":223275080.0,"volume":7539.21,"quote_currency":"USD","price_change":-0.369,"open_interest":560105870,"mid_price":29700.75,"mark_price":29700.53,"low":29266.5,"last":29698.0,"instrument_name":"BTC-PERPETUAL","high":29934.0,"funding_8h":0.00000214,"estimated_delivery_price":29695.49,"current_funding":0.0,"creation_timestamp":1654340303741,"bid_price":29700.5,"base_currency":"BTC","ask_price":29701.0}],"usIn":1654340303741682,"usOut":1654340303741855,"usDiff":173,"testnet":false}"#;
assert_eq!(
"BTC-PERPETUAL",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
assert_eq!(
1654340303741,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
}
#[test]
fn option() {
let raw_msg = r#"{"jsonrpc":"2.0","result":[{"volume":786.0,"underlying_price":1770.45,"underlying_index":"ETH-24JUN22","quote_currency":"ETH","price_change":-12.178,"open_interest":15135.0,"mid_price":0.037,"mark_price":0.037071,"low":0.0375,"last":0.0375,"interest_rate":0.0,"instrument_name":"ETH-24JUN22-1600-P","high":0.044,"estimated_delivery_price":1768.89,"creation_timestamp":1654341866165,"bid_price":0.0365,"base_currency":"ETH","ask_price":0.0375}],"usIn":1654341866165387,"usOut":1654341866165540,"usDiff":153,"testnet":false}"#;
assert_eq!(
1654341866165,
extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
);
assert_eq!(
"ETH-24JUN22-1600-P",
extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
);
}
}