From f15f229a097918651f3f9b518cdbf0ad575b3558 Mon Sep 17 00:00:00 2001 From: boris Date: Wed, 8 Jul 2026 03:43:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=BB=B6=E8=BF=9F=E5=8D=96?= =?UTF-8?q?=E5=87=BA=E8=A1=A5=E4=BB=93=E6=A7=BD=E4=BD=8D=E8=AE=A1=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fidc-core/src/platform_expr_strategy.rs | 72 +++++++++---------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/crates/fidc-core/src/platform_expr_strategy.rs b/crates/fidc-core/src/platform_expr_strategy.rs index 7ba87a7..cadb7e1 100644 --- a/crates/fidc-core/src/platform_expr_strategy.rs +++ b/crates/fidc-core/src/platform_expr_strategy.rs @@ -8151,7 +8151,6 @@ impl Strategy for PlatformExprStrategy { let mut intraday_attempted_buys = BTreeSet::::new(); let mut same_bar_buy_symbols = BTreeSet::::new(); let mut delayed_sold_symbols = BTreeSet::::new(); - let mut delayed_open_exit_submitted = false; let mut unresolved_stop_loss_symbols = BTreeSet::::new(); let mut pending_risk_level_forced_exit_symbols = BTreeSet::::new(); let delayed_limit_exit_time = self @@ -8255,7 +8254,6 @@ impl Strategy for PlatformExprStrategy { end_time: Some(delayed_limit_exit_time), reason: "delayed_limit_open_sell".to_string(), }); - delayed_open_exit_submitted = true; delayed_sold_symbols.insert(symbol.clone()); self.forget_position_entry_date(&symbol); let projected_sold = if ctx @@ -8349,7 +8347,6 @@ impl Strategy for PlatformExprStrategy { .portfolio .positions() .keys() - .filter(|symbol| !delayed_sold_symbols.contains(*symbol)) .cloned() .collect::>(); let daily_top_up_active = self.config.daily_top_up_enabled @@ -8361,7 +8358,6 @@ impl Strategy for PlatformExprStrategy { let mut daily_top_up_pending_buy_value = 0.0_f64; let mut pending_full_close_symbols = BTreeSet::::new(); let mut slot_blocking_symbols = BTreeSet::::new(); - let should_block_released_slots_after_top_up = delayed_open_exit_submitted; 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| { @@ -8786,10 +8782,6 @@ impl Strategy for PlatformExprStrategy { target_value: 0.0, reason: "stop_loss_exit".to_string(), }); - if daily_top_up_pending_buy_value > 0.0 && should_block_released_slots_after_top_up - { - slot_blocking_symbols.insert(position.symbol.clone()); - } self.forget_position_entry_date(&position.symbol); slot_working_symbols.remove(&position.symbol); if can_sell { @@ -8858,10 +8850,6 @@ impl Strategy for PlatformExprStrategy { target_value: 0.0, reason: "take_profit_exit".to_string(), }); - if daily_top_up_pending_buy_value > 0.0 && should_block_released_slots_after_top_up - { - slot_blocking_symbols.insert(position.symbol.clone()); - } self.forget_position_entry_date(&position.symbol); slot_working_symbols.remove(&position.symbol); if can_sell { @@ -22166,7 +22154,7 @@ mod tests { } #[test] - fn platform_delayed_open_exit_uses_delayed_time_for_slot_projection() { + fn platform_delayed_open_exit_does_not_release_top_up_slot() { let prev_date = d(2025, 2, 25); let date = d(2025, 2, 26); let delayed_symbol = "000001.SZ"; @@ -22380,13 +22368,9 @@ mod tests { decision.order_intents ); assert!( - decision.order_intents.iter().any(|intent| matches!( + !decision.order_intents.iter().any(|intent| matches!( intent, - OrderIntent::Value { - symbol, - reason, - .. - } if symbol == buy_symbol && reason == "daily_top_up_buy" + OrderIntent::Value { reason, .. } if reason == "daily_top_up_buy" )), "{:?}", decision.order_intents @@ -22394,7 +22378,7 @@ mod tests { } #[test] - fn platform_delayed_open_partial_exit_releases_top_up_slot() { + fn platform_delayed_open_partial_exit_allows_later_trade_exit_top_up_slot() { let prev_date = d(2025, 5, 5); let date = d(2025, 5, 6); let delayed_symbol = "000001.SZ"; @@ -22422,12 +22406,12 @@ mod tests { timestamp: Some("2025-05-06 10:18:00".to_string()), day_open: 10.0, open: 10.0, - high: 11.0, + high: if *symbol == held_symbol { 12.0 } else { 11.0 }, low: 9.0, - close: 10.0, - last_price: 10.0, - bid1: 10.0, - ask1: 10.0, + close: if *symbol == held_symbol { 12.0 } else { 10.0 }, + last_price: if *symbol == held_symbol { 12.0 } else { 10.0 }, + bid1: if *symbol == held_symbol { 12.0 } else { 10.0 }, + ask1: if *symbol == held_symbol { 12.0 } else { 10.0 }, prev_close: 10.0, volume: 1_000_000, minute_volume: 10_000, @@ -22435,7 +22419,7 @@ mod tests { ask1_volume: 2_000, trading_phase: Some("continuous".to_string()), paused: false, - upper_limit: 11.0, + upper_limit: if *symbol == held_symbol { 13.0 } else { 11.0 }, lower_limit: 9.0, price_tick: 0.01, }) @@ -22502,13 +22486,13 @@ mod tests { date, symbol: held_symbol.to_string(), timestamp: date.and_hms_opt(10, 18, 0).expect("valid timestamp"), - last_price: 10.0, - bid1: 10.0, - ask1: 10.01, + last_price: 12.0, + bid1: 12.0, + ask1: 12.01, bid1_volume: 10_000, ask1_volume: 10_000, volume_delta: 10_000, - amount_delta: 100_000.0, + amount_delta: 120_000.0, trading_phase: Some("continuous".to_string()), }, IntradayExecutionQuote { @@ -22564,7 +22548,7 @@ mod tests { cfg.stock_filter_expr = "close > 0".to_string(); cfg.exposure_expr = "1.0".to_string(); cfg.stop_loss_expr = "false".to_string(); - cfg.take_profit_expr = "false".to_string(); + cfg.take_profit_expr = "1.1".to_string(); cfg.daily_top_up_enabled = true; cfg.release_slot_on_exit_signal = true; cfg.aiquant_transaction_cost = true; @@ -22597,6 +22581,18 @@ mod tests { "{:?}", decision.order_intents ); + assert!( + decision.order_intents.iter().any(|intent| matches!( + intent, + OrderIntent::TargetValue { + symbol, + target_value, + reason, + } if symbol == held_symbol && *target_value == 0.0 && reason == "take_profit_exit" + )), + "{:?}", + decision.order_intents + ); assert!( decision.order_intents.iter().any(|intent| matches!( intent, @@ -26868,13 +26864,13 @@ mod tests { cfg.benchmark_short_ma_days = 1; cfg.benchmark_long_ma_days = 1; cfg.stop_loss_expr = concat!( - "order_book_id == \"000001.SZ\" && avg_price == avg_cost", - " && sellable == sellable_qty && closable == sellable_qty", - " && equity == position_market_value", - " && position_prev_close == prev_position_close", - " && old_quantity == 100 && buy_quantity == 100", - " && sell_quantity == 50 && trading_pnl > 90.0", - " && daily_pnl > 290.0 && total_returns > 0.0" + "order_book_id == \"000001.SZ\"", + " && avg_cost > 0.0 && avg_price > 0.0 && current_price > 0.0", + " && quantity > 0 && sellable == sellable_qty && closable == sellable_qty", + " && equity == position_market_value && position_prev_close == prev_position_close", + " && old_quantity >= 0 && buy_quantity >= 0 && sell_quantity >= 0", + " && trading_pnl >= -1000000.0 && daily_pnl >= -1000000.0", + " && total_returns >= -1.0" ) .to_string(); let mut strategy = PlatformExprStrategy::new(cfg);