diff --git a/crates/fidc-core/src/platform_expr_strategy.rs b/crates/fidc-core/src/platform_expr_strategy.rs index 0d1426d..ea2de6e 100644 --- a/crates/fidc-core/src/platform_expr_strategy.rs +++ b/crates/fidc-core/src/platform_expr_strategy.rs @@ -2319,6 +2319,27 @@ impl PlatformExprStrategy { } } + fn mark_highlimit_for_delayed_exit_at_time( + &mut self, + ctx: &StrategyContext<'_>, + date: NaiveDate, + symbol: &str, + execution_time: NaiveTime, + ) -> Result<(), BacktestError> { + if !self.config.delayed_limit_open_exit_enabled + || self.pending_highlimit_holdings.contains(symbol) + { + return Ok(()); + } + if matches!( + self.stock_is_at_upper_limit_at_time(ctx, date, symbol, execution_time)?, + Some(true) + ) { + self.pending_highlimit_holdings.insert(symbol.to_string()); + } + Ok(()) + } + fn stock_state_with_factor_date_and_time( &self, ctx: &StrategyContext<'_>, @@ -7463,14 +7484,12 @@ impl Strategy for PlatformExprStrategy { if position.quantity == 0 || delayed_sold_symbols.contains(&position.symbol) { continue; } - if self.regular_sell_should_wait_due_to_highlimit( + self.mark_highlimit_for_delayed_exit_at_time( ctx, execution_date, &position.symbol, self.intraday_execution_start_time(), - )? { - continue; - } + )?; if pending_full_close_symbols.contains(&position.symbol) { continue; } @@ -11706,7 +11725,7 @@ mod tests { } #[test] - fn platform_aiquant_weak_market_skips_pending_highlimit_target_adjust_until_open() { + fn platform_aiquant_weak_market_allows_pending_highlimit_partial_target_adjust() { let prev_date = d(2023, 5, 4); let date = d(2023, 5, 5); let symbol = "600148.SH"; @@ -11845,13 +11864,15 @@ mod tests { let decision = strategy.on_day(&ctx).expect("platform decision"); assert!( - !decision.order_intents.iter().any(|intent| matches!( + decision.order_intents.iter().any(|intent| matches!( intent, OrderIntent::Shares { symbol: intent_symbol, + quantity, reason, - .. - } if intent_symbol == symbol && reason == "daily_position_target_adjust" + } if intent_symbol == symbol + && reason == "daily_position_target_adjust" + && *quantity < 0 )), "{:?}", decision.order_intents @@ -11999,13 +12020,15 @@ mod tests { let decision = strategy.on_day(&ctx).expect("platform decision"); assert!( - !decision.order_intents.iter().any(|intent| matches!( + decision.order_intents.iter().any(|intent| matches!( intent, OrderIntent::Shares { symbol: intent_symbol, + quantity, reason, - .. - } if intent_symbol == symbol && reason == "daily_position_target_adjust" + } if intent_symbol == symbol + && reason == "daily_position_target_adjust" + && *quantity < 0 )), "{:?}", decision.order_intents