From c67932a2c9efee670b5aa6fd1c5cf218c51deffa Mon Sep 17 00:00:00 2001 From: boris Date: Tue, 21 Apr 2026 08:12:21 -0700 Subject: [PATCH] Tighten market order residual fill semantics --- crates/fidc-core/src/broker.rs | 75 -------------------------------- crates/fidc-core/src/strategy.rs | 29 ------------ 2 files changed, 104 deletions(-) diff --git a/crates/fidc-core/src/broker.rs b/crates/fidc-core/src/broker.rs index c49c7ff..3d2096f 100644 --- a/crates/fidc-core/src/broker.rs +++ b/crates/fidc-core/src/broker.rs @@ -716,7 +716,6 @@ where let mut filled_qty = 0_u32; let mut gross_amount = 0.0_f64; let mut last_timestamp = None; - let mut last_quote_price = None; for quote in quotes { if start_cursor.is_some_and(|cursor| quote.timestamp < cursor) { @@ -728,10 +727,6 @@ where } else { quote.buy_price() }; - if fallback_quote_price.is_some() { - last_quote_price = fallback_quote_price; - last_timestamp = Some(quote.timestamp); - } if quote.volume_delta == 0 { continue; @@ -784,35 +779,6 @@ where } } - if filled_qty < requested_qty { - let remaining_qty = requested_qty.saturating_sub(filled_qty); - let mut residual_qty = self.round_buy_quantity(remaining_qty, lot); - if residual_qty > 0 { - if let Some(residual_price) = last_quote_price { - if let Some(cash) = cash_limit { - while residual_qty > 0 { - let candidate_gross = - gross_amount + residual_price * residual_qty as f64; - if gross_limit.is_some_and(|limit| candidate_gross > limit + 1e-6) { - residual_qty = residual_qty.saturating_sub(lot); - continue; - } - let candidate_cost = - self.cost_model.calculate(OrderSide::Buy, candidate_gross); - if candidate_gross + candidate_cost.total() <= cash + 1e-6 { - break; - } - residual_qty = residual_qty.saturating_sub(lot); - } - } - if residual_qty > 0 { - gross_amount += residual_price * residual_qty as f64; - filled_qty += residual_qty; - } - } - } - } - if filled_qty == 0 { return None; } @@ -1177,22 +1143,12 @@ where let mut filled_qty = 0_u32; let mut gross_amount = 0.0_f64; let mut last_timestamp = None; - let mut last_quote_price = None; for quote in quotes { if start_cursor.is_some_and(|cursor| quote.timestamp < cursor) { continue; } - let fallback_quote_price = match side { - OrderSide::Buy => quote.buy_price(), - OrderSide::Sell => quote.sell_price(), - }; - if fallback_quote_price.is_some() { - last_quote_price = fallback_quote_price; - last_timestamp = Some(quote.timestamp); - } - // Approximate JoinQuant market-order fills with the evolving L1 book after // the decision time instead of trade VWAP. This keeps quantities/prices // closer to the observed 10:18 execution logs. @@ -1256,37 +1212,6 @@ where } } - if filled_qty < requested_qty { - let remaining_qty = requested_qty.saturating_sub(filled_qty); - let mut residual_qty = self.round_buy_quantity(remaining_qty, lot); - if residual_qty > 0 { - if let Some(residual_price) = last_quote_price { - if let Some(cash) = cash_limit { - while residual_qty > 0 { - let candidate_gross = - gross_amount + residual_price * residual_qty as f64; - if gross_limit.is_some_and(|limit| candidate_gross > limit + 1e-6) { - residual_qty = residual_qty.saturating_sub(lot); - continue; - } - if candidate_gross <= cash + 1e-6 { - break; - } - residual_qty = residual_qty.saturating_sub(lot); - } - } - if residual_qty > 0 { - let execution_price = match side { - OrderSide::Buy => residual_price, - OrderSide::Sell => residual_price, - }; - gross_amount += execution_price * residual_qty as f64; - filled_qty += residual_qty; - } - } - } - } - if filled_qty == 0 { return None; } diff --git a/crates/fidc-core/src/strategy.rs b/crates/fidc-core/src/strategy.rs index d4c5566..5687cc6 100644 --- a/crates/fidc-core/src/strategy.rs +++ b/crates/fidc-core/src/strategy.rs @@ -820,7 +820,6 @@ impl JqMicroCapStrategy { let mut filled_qty = 0_u32; let mut gross_amount = 0.0_f64; let mut last_timestamp = None; - let mut last_quote_price = None; for quote in quotes { if start_cursor.is_some_and(|cursor| quote.timestamp < cursor) { @@ -838,7 +837,6 @@ impl JqMicroCapStrategy { OrderSide::Sell => quote.sell_price(), }; if fallback_quote_price.is_some() { - last_quote_price = fallback_quote_price; last_timestamp = Some(quote.timestamp); } @@ -893,33 +891,6 @@ impl JqMicroCapStrategy { } } - if filled_qty < requested_qty { - let remaining_qty = requested_qty.saturating_sub(filled_qty); - let mut residual_qty = self.round_lot_quantity(remaining_qty, lot); - if residual_qty > 0 { - if let Some(residual_price) = last_quote_price { - if let Some(cash) = cash_limit { - while residual_qty > 0 { - let candidate_gross = - gross_amount + residual_price * residual_qty as f64; - if gross_limit.is_some_and(|limit| candidate_gross > limit + 1e-6) { - residual_qty = residual_qty.saturating_sub(lot); - continue; - } - if candidate_gross <= cash + 1e-6 { - break; - } - residual_qty = residual_qty.saturating_sub(lot); - } - } - if residual_qty > 0 { - gross_amount += residual_price * residual_qty as f64; - filled_qty += residual_qty; - } - } - } - } - if filled_qty == 0 { return None; }