use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct MarketImpact {
pub avg_price: f64,
pub worst_price: u128,
pub slippage: u128,
pub slippage_bps: f64,
pub levels_consumed: usize,
pub total_quantity_available: u64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct OrderSimulation {
pub fills: Vec<(u128, u64)>,
pub avg_price: f64,
pub total_filled: u64,
pub remaining_quantity: u64,
}
impl MarketImpact {
#[must_use]
pub fn empty() -> Self {
Self {
avg_price: 0.0,
worst_price: 0,
slippage: 0,
slippage_bps: 0.0,
levels_consumed: 0,
total_quantity_available: 0,
}
}
#[must_use]
pub fn can_fill(&self, requested_quantity: u64) -> bool {
self.total_quantity_available >= requested_quantity
}
#[must_use]
pub fn fill_ratio(&self, requested_quantity: u64) -> f64 {
if requested_quantity == 0 {
return 0.0;
}
(self.total_quantity_available as f64) / (requested_quantity as f64)
}
}
impl OrderSimulation {
#[must_use]
pub fn empty() -> Self {
Self {
fills: Vec::new(),
avg_price: 0.0,
total_filled: 0,
remaining_quantity: 0,
}
}
#[must_use]
pub fn is_fully_filled(&self) -> bool {
self.remaining_quantity == 0
}
#[must_use]
pub fn levels_count(&self) -> usize {
self.fills.len()
}
#[must_use]
pub fn total_cost(&self) -> u128 {
self.fills
.iter()
.map(|(price, qty)| *price * (*qty as u128))
.sum()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_market_impact_empty() {
let impact = MarketImpact::empty();
assert_eq!(impact.avg_price, 0.0);
assert_eq!(impact.worst_price, 0);
assert_eq!(impact.levels_consumed, 0);
}
#[test]
fn test_market_impact_can_fill() {
let impact = MarketImpact {
avg_price: 100.0,
worst_price: 105,
slippage: 5,
slippage_bps: 50.0,
levels_consumed: 3,
total_quantity_available: 100,
};
assert!(impact.can_fill(100));
assert!(impact.can_fill(50));
assert!(!impact.can_fill(101));
}
#[test]
fn test_market_impact_fill_ratio() {
let impact = MarketImpact {
avg_price: 100.0,
worst_price: 105,
slippage: 5,
slippage_bps: 50.0,
levels_consumed: 3,
total_quantity_available: 75,
};
assert_eq!(impact.fill_ratio(100), 0.75);
assert_eq!(impact.fill_ratio(75), 1.0);
assert_eq!(impact.fill_ratio(0), 0.0);
}
#[test]
fn test_order_simulation_empty() {
let sim = OrderSimulation::empty();
assert!(sim.fills.is_empty());
assert_eq!(sim.total_filled, 0);
assert!(sim.is_fully_filled());
}
#[test]
fn test_order_simulation_is_fully_filled() {
let sim = OrderSimulation {
fills: vec![(100, 50), (105, 50)],
avg_price: 102.5,
total_filled: 100,
remaining_quantity: 0,
};
assert!(sim.is_fully_filled());
let sim_partial = OrderSimulation {
fills: vec![(100, 50)],
avg_price: 100.0,
total_filled: 50,
remaining_quantity: 50,
};
assert!(!sim_partial.is_fully_filled());
}
#[test]
fn test_order_simulation_levels_count() {
let sim = OrderSimulation {
fills: vec![(100, 30), (105, 40), (110, 30)],
avg_price: 105.0,
total_filled: 100,
remaining_quantity: 0,
};
assert_eq!(sim.levels_count(), 3);
}
#[test]
fn test_order_simulation_total_cost() {
let sim = OrderSimulation {
fills: vec![(100, 10), (105, 10)],
avg_price: 102.5,
total_filled: 20,
remaining_quantity: 0,
};
assert_eq!(sim.total_cost(), 2050);
}
}