#[cfg(test)]
mod tests {
use crate::OrderBook;
use pricelevel::{Id, Side, TimeInForce};
#[test]
fn test_spread_absolute() {
let book: OrderBook<()> = OrderBook::new("TEST");
assert_eq!(book.spread_absolute(), None);
let _ = book.add_limit_order(Id::new(), 100, 10, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 105, 10, Side::Sell, TimeInForce::Gtc, None);
assert_eq!(book.spread_absolute(), Some(5));
}
#[test]
fn test_spread_bps() {
let book: OrderBook<()> = OrderBook::new("TEST");
assert_eq!(book.spread_bps(None), None);
let _ = book.add_limit_order(Id::new(), 10000, 10, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 10010, 10, Side::Sell, TimeInForce::Gtc, None);
let spread_bps = book.spread_bps(None).unwrap();
assert!((spread_bps - 9.995).abs() < 0.01);
}
#[test]
fn test_spread_bps_custom_multiplier() {
let book: OrderBook<()> = OrderBook::new("TEST");
let _ = book.add_limit_order(Id::new(), 10000, 10, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 10010, 10, Side::Sell, TimeInForce::Gtc, None);
let spread_pct = book.spread_bps(Some(100.0)).unwrap();
assert!((spread_pct - 0.0999).abs() < 0.001);
let spread_bps_default = book.spread_bps(None).unwrap();
let spread_bps_explicit = book.spread_bps(Some(10_000.0)).unwrap();
assert_eq!(spread_bps_default, spread_bps_explicit);
}
#[test]
fn test_vwap_buy_side() {
let book: OrderBook<()> = OrderBook::new("TEST");
let _ = book.add_limit_order(Id::new(), 100, 10, Side::Sell, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 105, 15, Side::Sell, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 110, 20, Side::Sell, TimeInForce::Gtc, None);
let vwap = book.vwap(10, Side::Buy).unwrap();
assert_eq!(vwap, 100.0);
let vwap = book.vwap(20, Side::Buy).unwrap();
assert_eq!(vwap, 102.5);
let vwap = book.vwap(25, Side::Buy).unwrap();
assert_eq!(vwap, 103.0);
assert_eq!(book.vwap(50, Side::Buy), None);
}
#[test]
fn test_vwap_sell_side() {
let book: OrderBook<()> = OrderBook::new("TEST");
let _ = book.add_limit_order(Id::new(), 100, 10, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 95, 15, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 90, 20, Side::Buy, TimeInForce::Gtc, None);
let vwap = book.vwap(10, Side::Sell).unwrap();
assert_eq!(vwap, 100.0);
let vwap = book.vwap(20, Side::Sell).unwrap();
assert_eq!(vwap, 97.5);
let vwap = book.vwap(25, Side::Sell).unwrap();
assert_eq!(vwap, 97.0);
assert_eq!(book.vwap(50, Side::Sell), None);
}
#[test]
fn test_vwap_empty_book() {
let book: OrderBook<()> = OrderBook::new("TEST");
assert_eq!(book.vwap(10, Side::Buy), None);
assert_eq!(book.vwap(10, Side::Sell), None);
}
#[test]
fn test_vwap_zero_quantity() {
let book: OrderBook<()> = OrderBook::new("TEST");
let _ = book.add_limit_order(Id::new(), 100, 10, Side::Sell, TimeInForce::Gtc, None);
assert_eq!(book.vwap(0, Side::Buy), None);
}
#[test]
fn test_micro_price() {
let book: OrderBook<()> = OrderBook::new("TEST");
assert_eq!(book.micro_price(), None);
let _ = book.add_limit_order(Id::new(), 100, 50, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 105, 50, Side::Sell, TimeInForce::Gtc, None);
let micro = book.micro_price().unwrap();
assert_eq!(micro, 102.5);
let mid = book.mid_price().unwrap();
assert_eq!(mid, 102.5);
}
#[test]
fn test_micro_price_imbalanced() {
let book: OrderBook<()> = OrderBook::new("TEST");
let _ = book.add_limit_order(Id::new(), 100, 70, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 105, 30, Side::Sell, TimeInForce::Gtc, None);
let micro = book.micro_price().unwrap();
assert_eq!(micro, 103.5);
let mid = book.mid_price().unwrap();
assert_eq!(mid, 102.5);
assert!(micro > mid);
}
#[test]
fn test_micro_price_zero_volumes() {
let book: OrderBook<()> = OrderBook::new("TEST");
assert_eq!(book.micro_price(), None);
}
#[test]
fn test_order_book_imbalance_balanced() {
let book: OrderBook<()> = OrderBook::new("TEST");
let _ = book.add_limit_order(Id::new(), 100, 50, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 105, 50, Side::Sell, TimeInForce::Gtc, None);
let imbalance = book.order_book_imbalance(5);
assert_eq!(imbalance, 0.0);
}
#[test]
fn test_order_book_imbalance_buy_pressure() {
let book: OrderBook<()> = OrderBook::new("TEST");
let _ = book.add_limit_order(Id::new(), 100, 60, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 105, 40, Side::Sell, TimeInForce::Gtc, None);
let imbalance = book.order_book_imbalance(5);
assert_eq!(imbalance, 0.2);
}
#[test]
fn test_order_book_imbalance_sell_pressure() {
let book: OrderBook<()> = OrderBook::new("TEST");
let _ = book.add_limit_order(Id::new(), 100, 30, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 105, 70, Side::Sell, TimeInForce::Gtc, None);
let imbalance = book.order_book_imbalance(5);
assert_eq!(imbalance, -0.4);
}
#[test]
fn test_order_book_imbalance_multiple_levels() {
let book: OrderBook<()> = OrderBook::new("TEST");
let _ = book.add_limit_order(Id::new(), 100, 10, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 99, 20, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 98, 30, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 101, 15, Side::Sell, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 102, 25, Side::Sell, TimeInForce::Gtc, None);
let imbalance = book.order_book_imbalance(2);
assert!((imbalance - (-10.0 / 70.0)).abs() < 0.0001);
let imbalance = book.order_book_imbalance(3);
assert_eq!(imbalance, 0.2);
}
#[test]
fn test_order_book_imbalance_empty_book() {
let book: OrderBook<()> = OrderBook::new("TEST");
assert_eq!(book.order_book_imbalance(5), 0.0);
}
#[test]
fn test_order_book_imbalance_zero_levels() {
let book: OrderBook<()> = OrderBook::new("TEST");
let _ = book.add_limit_order(Id::new(), 100, 50, Side::Buy, TimeInForce::Gtc, None);
assert_eq!(book.order_book_imbalance(0), 0.0);
}
#[test]
fn test_all_metrics_together() {
let book: OrderBook<()> = OrderBook::new("TEST");
let _ = book.add_limit_order(Id::new(), 99, 20, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 100, 50, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 101, 30, Side::Sell, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 102, 40, Side::Sell, TimeInForce::Gtc, None);
assert_eq!(book.mid_price(), Some(100.5));
assert_eq!(book.spread_absolute(), Some(1));
assert!(book.spread_bps(None).is_some());
assert!(book.vwap(50, Side::Buy).is_some());
assert!(book.micro_price().is_some());
let imbalance = book.order_book_imbalance(1);
assert_eq!(imbalance, 0.25);
}
}