#[cfg(test)]
mod tests {
use crate::OrderBook;
use pricelevel::{Id, Side, TimeInForce};
#[test]
fn test_market_impact_basic() {
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 impact = book.market_impact(20, Side::Buy);
assert_eq!(impact.total_quantity_available, 20);
assert_eq!(impact.levels_consumed, 2);
assert_eq!(impact.worst_price, 105);
assert_eq!(impact.slippage, 5);
assert_eq!(impact.avg_price, 102.5);
}
#[test]
fn test_market_impact_insufficient_liquidity() {
let book: OrderBook<()> = OrderBook::new("TEST");
let _ = book.add_limit_order(Id::new(), 100, 10, Side::Sell, TimeInForce::Gtc, None);
let impact = book.market_impact(50, Side::Buy);
assert_eq!(impact.total_quantity_available, 10);
assert_eq!(impact.levels_consumed, 1);
assert!(!impact.can_fill(50));
assert_eq!(impact.fill_ratio(50), 0.2);
}
#[test]
fn test_market_impact_empty_book() {
let book: OrderBook<()> = OrderBook::new("TEST");
let impact = book.market_impact(100, Side::Buy);
assert_eq!(impact.avg_price, 0.0);
assert_eq!(impact.worst_price, 0);
assert_eq!(impact.levels_consumed, 0);
assert_eq!(impact.total_quantity_available, 0);
}
#[test]
fn test_market_impact_zero_quantity() {
let book: OrderBook<()> = OrderBook::new("TEST");
let _ = book.add_limit_order(Id::new(), 100, 10, Side::Sell, TimeInForce::Gtc, None);
let impact = book.market_impact(0, Side::Buy);
assert_eq!(impact.total_quantity_available, 0);
assert_eq!(impact.levels_consumed, 0);
}
#[test]
fn test_market_impact_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 impact = book.market_impact(20, Side::Sell);
assert_eq!(impact.total_quantity_available, 20);
assert_eq!(impact.levels_consumed, 2);
assert_eq!(impact.worst_price, 95);
assert_eq!(impact.slippage, 5); assert_eq!(impact.avg_price, 97.5);
}
#[test]
fn test_market_impact_slippage_bps() {
let book: OrderBook<()> = OrderBook::new("TEST");
let _ = book.add_limit_order(Id::new(), 10000, 10, Side::Sell, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 10100, 10, Side::Sell, TimeInForce::Gtc, None);
let impact = book.market_impact(15, Side::Buy);
assert_eq!(impact.slippage, 100);
assert_eq!(impact.slippage_bps, 100.0);
}
#[test]
fn test_simulate_market_order_basic() {
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 simulation = book.simulate_market_order(20, Side::Buy);
assert_eq!(simulation.fills.len(), 2);
assert_eq!(simulation.fills[0], (100, 10));
assert_eq!(simulation.fills[1], (105, 10));
assert_eq!(simulation.total_filled, 20);
assert_eq!(simulation.remaining_quantity, 0);
assert!(simulation.is_fully_filled());
assert_eq!(simulation.avg_price, 102.5);
}
#[test]
fn test_simulate_market_order_partial_fill() {
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 simulation = book.simulate_market_order(50, Side::Buy);
assert_eq!(simulation.total_filled, 25);
assert_eq!(simulation.remaining_quantity, 25);
assert!(!simulation.is_fully_filled());
assert_eq!(simulation.levels_count(), 2);
}
#[test]
fn test_simulate_market_order_empty_book() {
let book: OrderBook<()> = OrderBook::new("TEST");
let simulation = book.simulate_market_order(100, Side::Buy);
assert_eq!(simulation.fills.len(), 0);
assert_eq!(simulation.total_filled, 0);
assert_eq!(simulation.remaining_quantity, 100);
}
#[test]
fn test_simulate_market_order_total_cost() {
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, 10, Side::Sell, TimeInForce::Gtc, None);
let simulation = book.simulate_market_order(20, Side::Buy);
assert_eq!(simulation.total_cost(), 2050);
}
#[test]
fn test_liquidity_in_range_basic() {
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(), 105, 15, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 110, 20, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 115, 25, Side::Buy, TimeInForce::Gtc, None);
let liquidity = book.liquidity_in_range(105, 110, Side::Buy);
assert_eq!(liquidity, 35); }
#[test]
fn test_liquidity_in_range_full_range() {
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(), 105, 15, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 110, 20, Side::Buy, TimeInForce::Gtc, None);
let liquidity = book.liquidity_in_range(0, u128::MAX, Side::Buy);
assert_eq!(liquidity, 45); }
#[test]
fn test_liquidity_in_range_no_overlap() {
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(), 105, 15, Side::Buy, TimeInForce::Gtc, None);
let liquidity = book.liquidity_in_range(200, 300, Side::Buy);
assert_eq!(liquidity, 0);
}
#[test]
fn test_liquidity_in_range_invalid_range() {
let book: OrderBook<()> = OrderBook::new("TEST");
let _ = book.add_limit_order(Id::new(), 100, 10, Side::Buy, TimeInForce::Gtc, None);
let liquidity = book.liquidity_in_range(200, 100, Side::Buy);
assert_eq!(liquidity, 0);
}
#[test]
fn test_liquidity_in_range_empty_book() {
let book: OrderBook<()> = OrderBook::new("TEST");
let liquidity = book.liquidity_in_range(100, 200, Side::Buy);
assert_eq!(liquidity, 0);
}
#[test]
fn test_liquidity_in_range_asks() {
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 liquidity = book.liquidity_in_range(100, 105, Side::Sell);
assert_eq!(liquidity, 25); }
#[test]
fn test_all_functions_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, 30, Side::Buy, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 101, 25, Side::Sell, TimeInForce::Gtc, None);
let _ = book.add_limit_order(Id::new(), 102, 35, Side::Sell, TimeInForce::Gtc, None);
let impact = book.market_impact(50, Side::Buy);
assert_eq!(impact.total_quantity_available, 50);
assert!(impact.can_fill(50));
let simulation = book.simulate_market_order(50, Side::Buy);
assert!(simulation.is_fully_filled());
assert_eq!(simulation.levels_count(), 2);
let liquidity = book.liquidity_in_range(101, 102, Side::Sell);
assert_eq!(liquidity, 60); }
}