diff --git a/crates/fidc-core/src/platform_strategy_spec.rs b/crates/fidc-core/src/platform_strategy_spec.rs index a255472..830091d 100644 --- a/crates/fidc-core/src/platform_strategy_spec.rs +++ b/crates/fidc-core/src/platform_strategy_spec.rs @@ -1793,6 +1793,12 @@ pub fn platform_expr_config_from_spec( { cfg.retry_empty_rebalance = true; } + if trading + .and_then(|item| item.release_slot_on_exit_signal) + .is_none() + { + cfg.release_slot_on_exit_signal = true; + } } let trade_times = spec_trade_times(spec); if let Some(main_trade_time) = trade_times.last().copied() { @@ -3087,6 +3093,51 @@ mod tests { ); } + #[test] + fn aiquant_compatibility_defaults_release_slot_on_exit_signal() { + let spec = serde_json::json!({ + "engineConfig": { + "profileName": "cn_a_microcap_v1", + "compatibilityProfile": "aiquant_rqalpha" + }, + "runtimeExpressions": { + "trading": { + "dailyTopUp": true + } + } + }); + + let cfg = platform_expr_config_from_value("", "", &spec).expect("config"); + + assert!( + cfg.release_slot_on_exit_signal, + "AiQuant compatibility must release the strategy working slot when an exit signal is emitted" + ); + } + + #[test] + fn aiquant_compatibility_respects_explicit_release_slot_false() { + let spec = serde_json::json!({ + "engineConfig": { + "profileName": "cn_a_microcap_v1", + "compatibilityProfile": "aiquant_rqalpha" + }, + "runtimeExpressions": { + "trading": { + "dailyTopUp": true, + "releaseSlotOnExitSignal": false + } + } + }); + + let cfg = platform_expr_config_from_value("", "", &spec).expect("config"); + + assert!( + !cfg.release_slot_on_exit_signal, + "explicit FIDC semantics must override the AiQuant compatibility default" + ); + } + #[test] fn parses_explicit_delayed_limit_open_exit() { let spec = serde_json::json!({