修正延迟卖出后止盈止损补仓槽位

This commit is contained in:
boris
2026-07-08 05:32:59 +08:00
parent bfbbac8952
commit 5e480cd69b
2 changed files with 3 additions and 60 deletions
@@ -8197,7 +8197,6 @@ impl Strategy for PlatformExprStrategy {
let mut intraday_attempted_buys = BTreeSet::<String>::new(); let mut intraday_attempted_buys = BTreeSet::<String>::new();
let mut same_bar_buy_symbols = BTreeSet::<String>::new(); let mut same_bar_buy_symbols = BTreeSet::<String>::new();
let mut delayed_sold_symbols = BTreeSet::<String>::new(); let mut delayed_sold_symbols = BTreeSet::<String>::new();
let mut delayed_open_exit_submitted = false;
let mut unresolved_stop_loss_symbols = BTreeSet::<String>::new(); let mut unresolved_stop_loss_symbols = BTreeSet::<String>::new();
let mut pending_risk_level_forced_exit_symbols = BTreeSet::<String>::new(); let mut pending_risk_level_forced_exit_symbols = BTreeSet::<String>::new();
let delayed_limit_exit_time = self let delayed_limit_exit_time = self
@@ -8301,7 +8300,6 @@ impl Strategy for PlatformExprStrategy {
end_time: Some(delayed_limit_exit_time), end_time: Some(delayed_limit_exit_time),
reason: "delayed_limit_open_sell".to_string(), reason: "delayed_limit_open_sell".to_string(),
}); });
delayed_open_exit_submitted = true;
delayed_sold_symbols.insert(symbol.clone()); delayed_sold_symbols.insert(symbol.clone());
self.forget_position_entry_date(&symbol); self.forget_position_entry_date(&symbol);
let projected_sold = if ctx let projected_sold = if ctx
@@ -8407,10 +8405,7 @@ impl Strategy for PlatformExprStrategy {
let mut daily_top_up_pending_buy_value = 0.0_f64; let mut daily_top_up_pending_buy_value = 0.0_f64;
let mut pending_full_close_symbols = BTreeSet::<String>::new(); let mut pending_full_close_symbols = BTreeSet::<String>::new();
let mut slot_blocking_symbols = BTreeSet::<String>::new(); let mut slot_blocking_symbols = BTreeSet::<String>::new();
let should_block_released_slots_after_top_up = let should_block_partial_exit_residual_slot = trading_ratio < 1.0;
delayed_open_exit_submitted && !self.config.release_slot_on_exit_signal;
let should_block_partial_exit_residual_slot =
should_block_released_slots_after_top_up || trading_ratio < 1.0;
let interleaved_pending_full_close_symbols = BTreeSet::<String>::new(); let interleaved_pending_full_close_symbols = BTreeSet::<String>::new();
let risk_level_forced_exit_time = self.risk_level_forced_exit_time(); let risk_level_forced_exit_time = self.risk_level_forced_exit_time();
self.pending_full_close_symbols.retain(|symbol| { self.pending_full_close_symbols.retain(|symbol| {
@@ -8870,8 +8865,7 @@ impl Strategy for PlatformExprStrategy {
target_value: 0.0, target_value: 0.0,
reason: "stop_loss_exit".to_string(), reason: "stop_loss_exit".to_string(),
}); });
if daily_top_up_pending_buy_value > 0.0 && should_block_released_slots_after_top_up if daily_top_up_pending_buy_value > 0.0 && trading_ratio < 1.0 {
{
slot_blocking_symbols.insert(position.symbol.clone()); slot_blocking_symbols.insert(position.symbol.clone());
} }
self.forget_position_entry_date(&position.symbol); self.forget_position_entry_date(&position.symbol);
@@ -23324,7 +23318,7 @@ mod tests {
cfg.stop_loss_expr = "false".to_string(); cfg.stop_loss_expr = "false".to_string();
cfg.take_profit_expr = "1.1".to_string(); cfg.take_profit_expr = "1.1".to_string();
cfg.daily_top_up_enabled = true; cfg.daily_top_up_enabled = true;
cfg.release_slot_on_exit_signal = true; cfg.release_slot_on_exit_signal = false;
cfg.aiquant_transaction_cost = true; cfg.aiquant_transaction_cost = true;
cfg.intraday_execution_time = Some(NaiveTime::from_hms_opt(10, 18, 0).unwrap()); cfg.intraday_execution_time = Some(NaiveTime::from_hms_opt(10, 18, 0).unwrap());
cfg.delayed_limit_open_exit_enabled = true; cfg.delayed_limit_open_exit_enabled = true;
@@ -1793,12 +1793,6 @@ pub fn platform_expr_config_from_spec(
{ {
cfg.retry_empty_rebalance = true; 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); let trade_times = spec_trade_times(spec);
if let Some(main_trade_time) = trade_times.last().copied() { if let Some(main_trade_time) = trade_times.last().copied() {
@@ -3093,51 +3087,6 @@ 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] #[test]
fn parses_explicit_delayed_limit_open_exit() { fn parses_explicit_delayed_limit_open_exit() {
let spec = serde_json::json!({ let spec = serde_json::json!({