From 5be836423a8581a1aa5605362fadf21bb0835e44 Mon Sep 17 00:00:00 2001 From: boris Date: Tue, 21 Apr 2026 18:35:02 -0700 Subject: [PATCH] Use snapshot last price for jq intraday execution --- crates/fidc-core/src/broker.rs | 40 +++++++++++++++----------------- crates/fidc-core/src/strategy.rs | 40 ++++++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/crates/fidc-core/src/broker.rs b/crates/fidc-core/src/broker.rs index 3d2096f..bc2e2f4 100644 --- a/crates/fidc-core/src/broker.rs +++ b/crates/fidc-core/src/broker.rs @@ -121,10 +121,8 @@ where if self.execution_price_field == PriceField::Last && self.intraday_execution_start_time.is_some() { - return match side { - OrderSide::Buy => self.buy_price(snapshot), - OrderSide::Sell => self.sell_price(snapshot), - }; + let _ = side; + return snapshot.price(PriceField::Last); } match side { @@ -1079,23 +1077,6 @@ where return None; } - let start_cursor = self - .intraday_execution_start_time - .map(|start_time| date.and_time(start_time)); - let quotes = data.execution_quotes_on(date, symbol); - - if let Some(fill) = self.select_execution_fill( - quotes, - side, - start_cursor, - requested_qty, - round_lot, - cash_limit, - gross_limit, - ) { - return Some(fill); - } - if self.intraday_execution_start_time.is_some() { let execution_price = self.snapshot_execution_price(snapshot, side); let quantity = match side { @@ -1122,6 +1103,23 @@ where }); } + let start_cursor = self + .intraday_execution_start_time + .map(|start_time| date.and_time(start_time)); + let quotes = data.execution_quotes_on(date, symbol); + + if let Some(fill) = self.select_execution_fill( + quotes, + side, + start_cursor, + requested_qty, + round_lot, + cash_limit, + gross_limit, + ) { + return Some(fill); + } + None } diff --git a/crates/fidc-core/src/strategy.rs b/crates/fidc-core/src/strategy.rs index 5687cc6..c7945b8 100644 --- a/crates/fidc-core/src/strategy.rs +++ b/crates/fidc-core/src/strategy.rs @@ -593,10 +593,8 @@ impl JqMicroCapStrategy { market: &crate::data::DailyMarketSnapshot, side: OrderSide, ) -> f64 { - match side { - OrderSide::Buy => market.buy_price(PriceField::Last), - OrderSide::Sell => market.sell_price(PriceField::Last), - } + let _ = side; + market.price(PriceField::Last) } fn project_order_value( @@ -814,6 +812,40 @@ impl JqMicroCapStrategy { return None; } + if let Some(market) = ctx.data.market(date, symbol) { + let execution_price = self.projected_execution_price(market, side); + if execution_price.is_finite() && execution_price > 0.0 { + let quantity = match side { + OrderSide::Buy => { + let cash = cash_limit.unwrap_or(f64::INFINITY); + let mut take_qty = self.round_lot_quantity(requested_qty, round_lot.max(1)); + while take_qty > 0 { + let candidate_gross = execution_price * take_qty as f64; + if gross_limit.is_some_and(|limit| candidate_gross > limit + 1e-6) { + take_qty = take_qty.saturating_sub(round_lot.max(1)); + continue; + } + if candidate_gross <= cash + 1e-6 { + break; + } + take_qty = take_qty.saturating_sub(round_lot.max(1)); + } + take_qty + } + OrderSide::Sell => requested_qty, + }; + if quantity > 0 { + let next_cursor = date.and_time(self.intraday_execution_start_time()) + + Duration::seconds(1); + return Some(ProjectedExecutionFill { + price: execution_price, + quantity, + next_cursor, + }); + } + } + } + let lot = round_lot.max(1); let start_cursor = self.projected_execution_start_cursor(date, symbol, execution_state); let quotes = ctx.data.execution_quotes_on(date, symbol);