From 51ee4a3f548ab5dcbb5c1a8f9cd1bd728810e109 Mon Sep 17 00:00:00 2001 From: boris Date: Wed, 8 Jul 2026 01:53:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8C=89=E6=8C=81=E4=BB=93=E9=A1=BA=E5=BA=8F?= =?UTF-8?q?=E5=A4=84=E7=90=86=E6=9C=AA=E5=AE=8C=E6=88=90=E6=B8=85=E4=BB=93?= =?UTF-8?q?=E8=A1=A5=E4=BB=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fidc-core/src/platform_expr_strategy.rs | 92 ++++++++++++++++--- 1 file changed, 81 insertions(+), 11 deletions(-) diff --git a/crates/fidc-core/src/platform_expr_strategy.rs b/crates/fidc-core/src/platform_expr_strategy.rs index bcc6749..f29590e 100644 --- a/crates/fidc-core/src/platform_expr_strategy.rs +++ b/crates/fidc-core/src/platform_expr_strategy.rs @@ -8323,7 +8323,15 @@ impl Strategy for PlatformExprStrategy { .filter(|symbol| !delayed_sold_symbols.contains(*symbol)) .cloned() .collect::>(); + let daily_top_up_active = self.config.daily_top_up_enabled + && self.config.rotation_enabled + && !periodic_rebalance + && trading_ratio > 0.0 + && selection_limit > 0; + let daily_top_up_target_budget = aiquant_total_value * trading_ratio; + let mut daily_top_up_pending_buy_value = 0.0_f64; let mut pending_full_close_symbols = BTreeSet::::new(); + let mut 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 @@ -8350,6 +8358,10 @@ impl Strategy for PlatformExprStrategy { 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(), @@ -8640,18 +8652,76 @@ impl Strategy for PlatformExprStrategy { } } - let daily_top_up_active = self.config.daily_top_up_enabled - && self.config.rotation_enabled - && !periodic_rebalance - && trading_ratio > 0.0 - && selection_limit > 0; - let daily_top_up_target_budget = aiquant_total_value * trading_ratio; - let mut daily_top_up_pending_buy_value = 0.0_f64; - for position in ctx.portfolio.positions().values() { - if delayed_sold_symbols.contains(&position.symbol) - || pending_full_close_symbols.contains(&position.symbol) - { + if delayed_sold_symbols.contains(&position.symbol) { + continue; + } + if interleaved_pending_full_close_symbols.contains(&position.symbol) { + exit_symbols.insert(position.symbol.clone()); + order_intents.push(OrderIntent::TargetValue { + symbol: position.symbol.clone(), + target_value: 0.0, + reason: "pending_full_close_exit".to_string(), + }); + self.forget_position_entry_date(&position.symbol); + slot_working_symbols.remove(&position.symbol); + let can_sell = defer_execution_risk + || self.can_sell_position(ctx, execution_date, &position.symbol); + if can_sell { + let close_submitted = self + .project_target_zero( + ctx, + &mut projected, + projection_date, + &position.symbol, + &mut projected_execution_state, + ) + .is_some(); + if close_submitted { + if Self::projected_position_is_flat(&projected, &position.symbol) { + same_day_sold_symbols.insert(position.symbol.clone()); + pending_full_close_symbols.remove(&position.symbol); + self.pending_full_close_symbols.remove(&position.symbol); + } else { + pending_full_close_symbols.insert(position.symbol.clone()); + self.pending_full_close_symbols + .insert(position.symbol.clone()); + } + } + } + if daily_top_up_active { + self.try_daily_top_up_at_position( + ctx, + &day, + &stock_list, + decision_date, + execution_date, + projection_date, + selection_factor_date, + signal_date, + daily_top_up_target_budget, + selection_limit, + defer_execution_risk, + Some(position.symbol.as_str()), + &mut projected, + &mut projected_execution_state, + &mut order_intents, + &mut aiquant_available_cash, + &mut slot_working_symbols, + &mut same_bar_buy_symbols, + &pending_full_close_symbols, + &same_day_sold_symbols, + &exit_symbols, + &delayed_sold_symbols, + &mut intraday_attempted_buys, + &mut daily_top_up_pending_buy_value, + debug_daily_top_up, + &mut daily_top_up_debug_notes, + )?; + } + continue; + } + if pending_full_close_symbols.contains(&position.symbol) { continue; } let projected_position = projected.position(&position.symbol).unwrap_or(position);