diff --git a/crates/fidc-core/src/platform_expr_strategy.rs b/crates/fidc-core/src/platform_expr_strategy.rs index 1fad2c3..f2704cf 100644 --- a/crates/fidc-core/src/platform_expr_strategy.rs +++ b/crates/fidc-core/src/platform_expr_strategy.rs @@ -684,6 +684,14 @@ impl PlatformExprStrategy { selection_limit.max((selection_limit as f64 * multiple) as usize) } + fn should_emit_rebalance_target_value( + defer_execution: bool, + before_qty: u32, + projected_after_qty: u32, + ) -> bool { + defer_execution || projected_after_qty != before_qty + } + fn buffered_selection( ranked_symbols: &[String], held_symbols: &BTreeSet, @@ -9453,6 +9461,12 @@ impl Strategy for PlatformExprStrategy { if after_qty != before_qty { projected = trial_projected; projected_execution_state = trial_execution_state; + } + if Self::should_emit_rebalance_target_value( + defer_execution_risk, + before_qty, + after_qty, + ) { order_intents.push(OrderIntent::TargetValue { symbol: symbol.clone(), target_value, @@ -9461,8 +9475,8 @@ impl Strategy for PlatformExprStrategy { if after_qty > before_qty { intraday_attempted_buys.insert(symbol.clone()); } - aiquant_available_cash = projected.cash().max(0.0); } + aiquant_available_cash = projected.cash().max(0.0); continue; } if same_day_sold_symbols.contains(symbol) @@ -29750,4 +29764,17 @@ mod tests { vec!["000005.SZ", "000006.SZ", "000001.SZ", "000002.SZ"] ); } + + #[test] + fn lagged_rebalance_emits_target_value_even_when_projection_is_unchanged() { + assert!(PlatformExprStrategy::should_emit_rebalance_target_value( + true, 10_000, 10_000 + )); + assert!(!PlatformExprStrategy::should_emit_rebalance_target_value( + false, 10_000, 10_000 + )); + assert!(PlatformExprStrategy::should_emit_rebalance_target_value( + false, 10_000, 10_100 + )); + } }