From ca0471799b20ce4a7a7cefd26110b1ed795480a9 Mon Sep 17 00:00:00 2001 From: boris Date: Wed, 8 Jul 2026 02:38:19 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3ALV=E6=AE=8B=E4=BD=99?= =?UTF-8?q?=E6=B8=85=E4=BB=93=E9=87=8D=E5=88=A4=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fidc-core/src/platform_expr_strategy.rs | 60 ++++--------------- 1 file changed, 11 insertions(+), 49 deletions(-) diff --git a/crates/fidc-core/src/platform_expr_strategy.rs b/crates/fidc-core/src/platform_expr_strategy.rs index 84964fe..234f692 100644 --- a/crates/fidc-core/src/platform_expr_strategy.rs +++ b/crates/fidc-core/src/platform_expr_strategy.rs @@ -8337,7 +8337,7 @@ impl Strategy for PlatformExprStrategy { let mut slot_blocking_symbols = delayed_exit_slot_blocking_symbols.clone(); let should_block_released_slots_after_top_up = !delayed_exit_slot_blocking_symbols.is_empty(); - let mut interleaved_pending_full_close_symbols = BTreeSet::::new(); + let interleaved_pending_full_close_symbols = BTreeSet::::new(); let risk_level_forced_exit_time = self.risk_level_forced_exit_time(); self.pending_full_close_symbols.retain(|symbol| { ctx.portfolio @@ -8348,52 +8348,7 @@ impl Strategy for PlatformExprStrategy { .pending_full_close_symbols .iter() .cloned() - .collect::>(); - for symbol in carried_full_close_symbols { - if delayed_sold_symbols.contains(&symbol) - || self.pending_highlimit_holdings.contains(&symbol) - { - continue; - } - if self.regular_sell_should_wait_due_to_highlimit( - ctx, - projection_date, - &symbol, - self.intraday_execution_start_time(), - )? { - continue; - } - pending_full_close_symbols.insert(symbol.clone()); - if daily_top_up_active { - interleaved_pending_full_close_symbols.insert(symbol); - continue; - } - exit_symbols.insert(symbol.clone()); - order_intents.push(OrderIntent::TargetValue { - symbol: symbol.clone(), - target_value: 0.0, - reason: "pending_full_close_exit".to_string(), - }); - self.forget_position_entry_date(&symbol); - let can_sell = - defer_execution_risk || self.can_sell_position(ctx, execution_date, &symbol); - if can_sell - && self - .project_target_zero( - ctx, - &mut projected, - projection_date, - &symbol, - &mut projected_execution_state, - ) - .is_some() - && Self::projected_position_is_flat(&projected, &symbol) - { - same_day_sold_symbols.insert(symbol.clone()); - slot_working_symbols.remove(&symbol); - self.pending_full_close_symbols.remove(&symbol); - } - } + .collect::>(); if self.config.rotation_enabled && let Some(max_holding_days) = self.config.max_holding_days.filter(|value| *value > 0) { @@ -8753,6 +8708,9 @@ impl Strategy for PlatformExprStrategy { } let (stop_hit, profit_hit) = self.stop_take_action_for_position(ctx, signal_date, &day, projected_position)?; + if carried_full_close_symbols.contains(&position.symbol) && !stop_hit && !profit_hit { + self.pending_full_close_symbols.remove(&position.symbol); + } let can_sell = defer_execution_risk || self.can_sell_position(ctx, execution_date, &position.symbol); if stop_hit { @@ -8786,6 +8744,8 @@ impl Strategy for PlatformExprStrategy { } else { pending_full_close_symbols.insert(position.symbol.clone()); slot_blocking_symbols.insert(position.symbol.clone()); + self.pending_full_close_symbols + .insert(position.symbol.clone()); } } } else { @@ -8856,6 +8816,8 @@ impl Strategy for PlatformExprStrategy { } else { pending_full_close_symbols.insert(position.symbol.clone()); slot_blocking_symbols.insert(position.symbol.clone()); + self.pending_full_close_symbols + .insert(position.symbol.clone()); } } } @@ -13199,7 +13161,7 @@ mod tests { } #[test] - fn platform_stop_loss_does_not_carry_synthetic_pending_full_close() { + fn platform_stop_loss_residual_pending_rechecks_signal_next_day() { let prev_date = d(2025, 1, 6); let first_date = d(2025, 1, 7); let second_date = d(2025, 1, 8); @@ -13333,7 +13295,7 @@ mod tests { OrderIntent::TargetValue { symbol: intent_symbol, target_value, reason } if intent_symbol == symbol && *target_value == 0.0 && reason == "stop_loss_exit" ))); - assert!(!strategy.pending_full_close_symbols.contains(symbol)); + assert!(strategy.pending_full_close_symbols.contains(symbol)); let mut second_portfolio = PortfolioState::new(1_000_000.0); second_portfolio