From e37b8e1265cbb0ee21db04ffc0eaee0be46fa31d Mon Sep 17 00:00:00 2001 From: boris Date: Tue, 7 Jul 2026 06:36:33 +0800 Subject: [PATCH] =?UTF-8?q?=E9=99=90=E5=88=B6=E5=BB=B6=E8=BF=9F=E6=BB=91?= =?UTF-8?q?=E7=82=B9=E7=8E=B0=E9=87=91=E5=8F=A3=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fidc-core/src/platform_strategy_spec.rs | 48 +++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/crates/fidc-core/src/platform_strategy_spec.rs b/crates/fidc-core/src/platform_strategy_spec.rs index 985780e..2a0fb89 100644 --- a/crates/fidc-core/src/platform_strategy_spec.rs +++ b/crates/fidc-core/src/platform_strategy_spec.rs @@ -1119,7 +1119,19 @@ fn apply_execution_behavior_overrides( "sellThenBuyDelaySlippageRate must be a finite number in [0, 1)".to_string(), ); } - cfg.sell_then_buy_delay_slippage_rate = rate; + if cfg.rebalance_cash_mode != RebalanceCashMode::SellThenBuy { + if rate != 0.0 { + return Err( + "sellThenBuyDelaySlippageRate can only be set when rebalanceCashMode is sell_then_buy" + .to_string(), + ); + } + cfg.sell_then_buy_delay_slippage_rate = 0.0; + } else { + cfg.sell_then_buy_delay_slippage_rate = rate; + } + } else if cfg.rebalance_cash_mode != RebalanceCashMode::SellThenBuy { + cfg.sell_then_buy_delay_slippage_rate = 0.0; } Ok(()) } @@ -2684,15 +2696,43 @@ mod tests { let spec = serde_json::json!({ "execution": { "matchingType": "next_bar_open", - "rebalanceCashMode": "pre_open_cash", - "sellThenBuyDelaySlippageRate": 0.003 + "rebalanceCashMode": "pre_open_cash" } }); let cfg = platform_expr_config_from_value("", "", &spec).expect("config"); assert_eq!(cfg.matching_type, MatchingType::NextBarOpen); assert_eq!(cfg.rebalance_cash_mode, RebalanceCashMode::PreOpenCash); - assert_eq!(cfg.sell_then_buy_delay_slippage_rate, 0.003); + assert_eq!(cfg.sell_then_buy_delay_slippage_rate, 0.0); + + let invalid_delay_spec = serde_json::json!({ + "execution": { + "matchingType": "next_bar_open", + "rebalanceCashMode": "pre_open_cash", + "sellThenBuyDelaySlippageRate": 0.003 + } + }); + let invalid_delay = platform_expr_config_from_value("", "", &invalid_delay_spec) + .expect_err("delay slippage should be rejected outside sell_then_buy"); + assert!(invalid_delay.to_string().contains("can only be set")); + + let override_to_pre_open_spec = serde_json::json!({ + "engineConfig": { + "rebalanceCashMode": "sell_then_buy", + "sellThenBuyDelaySlippageRate": 0.003 + }, + "execution": { + "matchingType": "next_bar_open", + "rebalanceCashMode": "pre_open_cash" + } + }); + let override_to_pre_open = + platform_expr_config_from_value("", "", &override_to_pre_open_spec).expect("config"); + assert_eq!( + override_to_pre_open.rebalance_cash_mode, + RebalanceCashMode::PreOpenCash + ); + assert_eq!(override_to_pre_open.sell_then_buy_delay_slippage_rate, 0.0); let minute_spec = serde_json::json!({ "execution": {