pub struct FillSimulator { /* private fields */ }Expand description
Simulates order fills based on quote price crossing.
Shared logic used by both MockExchange and PaperExchange.
§Optimization
Orders are stored in sorted VecDeques by price (per instrument+side).
- BUY orders: sorted descending by price (highest first)
- SELL orders: sorted ascending by price (lowest first)
Using VecDeque allows O(1) pop_front for filling orders, avoiding O(n) shifts.
Implementations§
Source§impl FillSimulator
impl FillSimulator
Sourcepub fn new(initial_balances: HashMap<AssetId, Decimal>) -> Self
pub fn new(initial_balances: HashMap<AssetId, Decimal>) -> Self
Create a simulator with initial balances and no fees.
Sourcepub fn new_with_fee(
initial_balances: HashMap<AssetId, Decimal>,
fee_rate: Decimal,
) -> Self
pub fn new_with_fee( initial_balances: HashMap<AssetId, Decimal>, fee_rate: Decimal, ) -> Self
Create a new fill simulator with a specific fee rate
Sourcepub fn set_fee_rate(&mut self, fee_rate: Decimal)
pub fn set_fee_rate(&mut self, fee_rate: Decimal)
Set the fee rate (0.0004 = 0.04%)
Sourcepub fn register_instrument_meta(&mut self, meta: &InstrumentMeta)
pub fn register_instrument_meta(&mut self, meta: &InstrumentMeta)
Register market metadata so paper/backtest accounting can use the right base/quote assets. Outcome markets quote in USDH, not USDC.
Sourcepub fn instrument_is_perp(&self, instrument: &InstrumentId) -> bool
pub fn instrument_is_perp(&self, instrument: &InstrumentId) -> bool
Return true when the instrument is configured or inferred as a perp.
Sourcepub fn next_exchange_order_id(&mut self, prefix: &str) -> ExchangeOrderId
pub fn next_exchange_order_id(&mut self, prefix: &str) -> ExchangeOrderId
Generate next exchange order ID
Sourcepub fn add_pending_order(&mut self, order: PendingOrder)
pub fn add_pending_order(&mut self, order: PendingOrder)
Add a pending order (maintains sorted order for O(log n) lookups)
Sourcepub fn remove_order(
&mut self,
client_id: &ClientOrderId,
) -> Option<PendingOrder>
pub fn remove_order( &mut self, client_id: &ClientOrderId, ) -> Option<PendingOrder>
Remove pending order by client ID
Sourcepub fn remove_orders_for_instrument(
&mut self,
instrument: &InstrumentId,
) -> Vec<PendingOrder>
pub fn remove_orders_for_instrument( &mut self, instrument: &InstrumentId, ) -> Vec<PendingOrder>
Remove all pending orders for an instrument
Sourcepub fn set_balance(&mut self, asset: AssetId, amount: Decimal)
pub fn set_balance(&mut self, asset: AssetId, amount: Decimal)
Set balance directly
Sourcepub fn check_fills(
&mut self,
quotes: &HashMap<InstrumentId, Quote>,
time_ms: i64,
) -> Vec<SimulatedFill>
pub fn check_fills( &mut self, quotes: &HashMap<InstrumentId, Quote>, time_ms: i64, ) -> Vec<SimulatedFill>
Check pending orders against quotes and generate fills.
§Optimization
Orders are grouped by (instrument, side) and sorted by price. For each quote, we use binary search to find orders that could fill:
- BUY orders fill when ask <= order.price (scan from highest price down)
- SELL orders fill when bid >= order.price (scan from lowest price up)
This reduces complexity from O(orders) to O(fillable_orders).
Sourcepub fn check_balance(
&self,
instrument: &InstrumentId,
side: OrderSide,
price: Decimal,
qty: Decimal,
) -> Result<(), String>
pub fn check_balance( &self, instrument: &InstrumentId, side: OrderSide, price: Decimal, qty: Decimal, ) -> Result<(), String>
Check if balance is sufficient for an order
Sourcepub fn apply_fill(&mut self, fill: &Fill)
pub fn apply_fill(&mut self, fill: &Fill)
Apply a known fill to simulated spot-like balances.
IOC fills are constructed by PaperExchange directly, while resting fills
come through check_fills.
Sourcepub fn pending_orders_count(&self) -> usize
pub fn pending_orders_count(&self) -> usize
Get pending orders count (sum across all groups)
Sourcepub fn pending_orders(&self) -> Vec<&PendingOrder>
pub fn pending_orders(&self) -> Vec<&PendingOrder>
Get all pending orders (for inspection) - flattened from all groups