From c3a5161db1e771a6d9d77c4f361b301de48ecef8 Mon Sep 17 00:00:00 2001 From: boris Date: Fri, 19 Jun 2026 14:25:10 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E8=B7=8C=E5=81=9C=E5=8D=96?= =?UTF-8?q?=E5=87=BA=E6=9C=AA=E6=88=90=E4=BA=A4=E4=BB=93=E4=BD=8D=E9=87=8A?= =?UTF-8?q?=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fidc-core/src/platform_expr_strategy.rs | 144 +++++++----------- 1 file changed, 58 insertions(+), 86 deletions(-) diff --git a/crates/fidc-core/src/platform_expr_strategy.rs b/crates/fidc-core/src/platform_expr_strategy.rs index 30984ce..84ec96b 100644 --- a/crates/fidc-core/src/platform_expr_strategy.rs +++ b/crates/fidc-core/src/platform_expr_strategy.rs @@ -1671,27 +1671,6 @@ impl PlatformExprStrategy { .unwrap_or(true) } - fn projected_target_zero_would_fill( - &self, - ctx: &StrategyContext<'_>, - projected: &PortfolioState, - date: NaiveDate, - symbol: &str, - execution_state: &ProjectedExecutionState, - ) -> bool { - let mut trial_projected = projected.clone(); - let mut trial_execution_state = execution_state.clone(); - self.project_target_zero( - ctx, - &mut trial_projected, - date, - symbol, - &mut trial_execution_state, - ) - .is_some() - && Self::projected_position_is_flat(&trial_projected, symbol) - } - fn projected_position_value_at_execution_price( &self, ctx: &StrategyContext<'_>, @@ -6693,15 +6672,11 @@ impl Strategy for PlatformExprStrategy { let (stop_hit, profit_hit) = self.stop_take_action_for_position(ctx, execution_date, &day, position)?; if stop_hit { - if self.projected_target_zero_would_fill( - ctx, - &projected, - execution_date, - &position.symbol, - &projected_execution_state, - ) { - pending_full_close_symbols.insert(position.symbol.clone()); - } + pending_full_close_symbols.insert(position.symbol.clone()); + continue; + } + if profit_hit { + pending_full_close_symbols.insert(position.symbol.clone()); continue; } let can_sell = self.can_sell_position(ctx, execution_date, &position.symbol); @@ -6725,17 +6700,6 @@ impl Strategy for PlatformExprStrategy { continue; } } - if profit_hit { - if self.projected_target_zero_would_fill( - ctx, - &projected, - execution_date, - &position.symbol, - &projected_execution_state, - ) { - pending_full_close_symbols.insert(position.symbol.clone()); - } - } } } @@ -6834,9 +6798,6 @@ impl Strategy for PlatformExprStrategy { target_value: 0.0, reason: "stop_loss_exit".to_string(), }); - if self.config.release_slot_on_exit_signal { - same_day_sold_symbols.insert(position.symbol.clone()); - } if can_sell { if self .project_target_zero( @@ -6885,9 +6846,6 @@ impl Strategy for PlatformExprStrategy { target_value: 0.0, reason: "take_profit_exit".to_string(), }); - if self.config.release_slot_on_exit_signal { - same_day_sold_symbols.insert(position.symbol.clone()); - } if can_sell && self .project_target_zero( @@ -14196,7 +14154,7 @@ mod tests { } #[test] - fn platform_weak_market_keeps_positive_adjust_when_stop_loss_sell_blocked() { + fn platform_weak_market_skips_positive_adjust_when_stop_loss_sell_blocked() { let prev_date = d(2025, 2, 2); let date = d(2025, 2, 3); let symbols = ["000001.SZ", "000002.SZ"]; @@ -14319,16 +14277,20 @@ mod tests { let decision = strategy.on_day(&ctx).expect("platform decision"); - assert!(decision.order_intents.iter().any(|intent| matches!( - intent, - OrderIntent::Shares { - symbol, - quantity, - reason, - } if symbol == "000001.SZ" - && reason == "daily_position_target_adjust" - && *quantity > 0 - ))); + assert!( + !decision.order_intents.iter().any(|intent| matches!( + intent, + OrderIntent::Shares { + symbol, + quantity, + reason, + } if symbol == "000001.SZ" + && reason == "daily_position_target_adjust" + && *quantity > 0 + )), + "{:?}", + decision.order_intents + ); assert!(decision.order_intents.iter().any(|intent| matches!( intent, OrderIntent::TargetValue { @@ -14340,7 +14302,7 @@ mod tests { } #[test] - fn platform_weak_market_keeps_positive_adjust_when_intraday_stop_loss_sell_blocked() { + fn platform_weak_market_skips_positive_adjust_when_intraday_stop_loss_sell_blocked() { let prev_date = d(2025, 2, 2); let date = d(2025, 2, 3); let symbols = ["000001.SZ", "000002.SZ"]; @@ -14482,16 +14444,20 @@ mod tests { let decision = strategy.on_day(&ctx).expect("platform decision"); - assert!(decision.order_intents.iter().any(|intent| matches!( - intent, - OrderIntent::Shares { - symbol, - quantity, - reason, - } if symbol == "000001.SZ" - && reason == "daily_position_target_adjust" - && *quantity > 0 - ))); + assert!( + !decision.order_intents.iter().any(|intent| matches!( + intent, + OrderIntent::Shares { + symbol, + quantity, + reason, + } if symbol == "000001.SZ" + && reason == "daily_position_target_adjust" + && *quantity > 0 + )), + "{:?}", + decision.order_intents + ); assert!(decision.order_intents.iter().any(|intent| matches!( intent, OrderIntent::TargetValue { @@ -15547,7 +15513,7 @@ mod tests { } #[test] - fn platform_daily_top_up_can_release_unsellable_exit_signal_slot() { + fn platform_daily_top_up_does_not_release_unsellable_exit_signal_slot() { let prev_date = d(2026, 3, 31); let date = d(2026, 4, 1); let symbols = ["000001.SZ", "000002.SZ", "000003.SZ"]; @@ -15687,14 +15653,10 @@ mod tests { decision.order_intents ); assert!( - decision.order_intents.iter().any(|intent| matches!( - intent, - OrderIntent::Value { - symbol, - reason, - .. - } if symbol == "000003.SZ" && reason == "daily_top_up_buy" - )), + !decision + .order_intents + .iter() + .any(|intent| matches!(intent, OrderIntent::Value { .. })), "{:?}", decision.order_intents ); @@ -16695,10 +16657,15 @@ mod tests { "{:?}", decision.diagnostics ); - assert!(matches!( - decision.order_intents.first(), - Some(crate::strategy::OrderIntent::Value { symbol, .. }) if symbol == "300002.SZ" - )); + assert!( + matches!( + decision.order_intents.first(), + Some(crate::strategy::OrderIntent::Value { symbol, .. }) if symbol == "300002.SZ" + ), + "intents={:?} diagnostics={:?}", + decision.order_intents, + decision.diagnostics + ); } #[test] @@ -16870,10 +16837,15 @@ mod tests { "{:?}", decision.diagnostics ); - assert!(matches!( - decision.order_intents.first(), - Some(crate::strategy::OrderIntent::Value { symbol, .. }) if symbol == "300002.SZ" - )); + assert!( + matches!( + decision.order_intents.first(), + Some(crate::strategy::OrderIntent::Value { symbol, .. }) if symbol == "300001.SZ" + ), + "intents={:?} diagnostics={:?}", + decision.order_intents, + decision.diagnostics + ); } #[test]