修正延迟卖出意图的持仓槽位

This commit is contained in:
boris
2026-07-17 12:54:33 +08:00
parent 81ac623fca
commit 4d7245d8b0
+24 -4
View File
@@ -2830,6 +2830,13 @@ impl PlatformExprStrategy {
working_symbols.union(slot_blocking_symbols).count()
}
fn should_block_partial_exit_residual_slot(
trading_ratio: f64,
defer_execution_risk: bool,
) -> bool {
trading_ratio < 1.0 && !defer_execution_risk
}
fn remaining_buy_cash_active_value(
&self,
ctx: &StrategyContext<'_>,
@@ -9276,7 +9283,11 @@ impl Strategy for PlatformExprStrategy {
let mut deferred_daily_target_values = BTreeMap::<String, f64>::new();
let mut pending_full_close_symbols = BTreeSet::<String>::new();
let mut slot_blocking_symbols = BTreeSet::<String>::new();
let should_block_partial_exit_residual_slot = trading_ratio < 1.0;
// Lagged execution only freezes the T-day intent. Whether an exit leaves a
// residual position is an execution-day fact and must not consume a T+1
// replacement slot before the sell leg is actually matched.
let should_block_partial_exit_residual_slot =
Self::should_block_partial_exit_residual_slot(trading_ratio, defer_execution_risk);
let interleaved_pending_full_close_symbols = BTreeSet::<String>::new();
let risk_level_forced_exit_time = self.risk_level_forced_exit_time();
self.pending_full_close_symbols.retain(|symbol| {
@@ -9552,7 +9563,7 @@ impl Strategy for PlatformExprStrategy {
target_value: 0.0,
reason: "pending_full_close_exit".to_string(),
});
if daily_top_up_pending_buy_value > 0.0 {
if daily_top_up_pending_buy_value > 0.0 && should_block_partial_exit_residual_slot {
slot_blocking_symbols.insert(position.symbol.clone());
}
self.forget_position_entry_date(&position.symbol);
@@ -9576,7 +9587,9 @@ impl Strategy for PlatformExprStrategy {
self.pending_full_close_symbols.remove(&position.symbol);
} else {
pending_full_close_symbols.insert(position.symbol.clone());
if should_block_partial_exit_residual_slot {
slot_blocking_symbols.insert(position.symbol.clone());
}
self.pending_full_close_symbols
.insert(position.symbol.clone());
}
@@ -9643,7 +9656,7 @@ impl Strategy for PlatformExprStrategy {
self.pending_full_close_symbols.remove(&position.symbol);
} else {
exit_symbols.insert(position.symbol.clone());
if trading_ratio < 1.0 {
if should_block_partial_exit_residual_slot {
slot_blocking_symbols.insert(position.symbol.clone());
}
order_intents.push(OrderIntent::TargetValue {
@@ -9726,7 +9739,7 @@ impl Strategy for PlatformExprStrategy {
target_value: 0.0,
reason: "stop_loss_exit".to_string(),
});
if daily_top_up_pending_buy_value > 0.0 && trading_ratio < 1.0 {
if daily_top_up_pending_buy_value > 0.0 && should_block_partial_exit_residual_slot {
slot_blocking_symbols.insert(position.symbol.clone());
}
self.forget_position_entry_date(&position.symbol);
@@ -21900,6 +21913,13 @@ mod tests {
);
}
#[test]
fn platform_lagged_exit_does_not_reserve_replacement_slot_before_execution() {
assert!(PlatformExprStrategy::should_block_partial_exit_residual_slot(0.5, false));
assert!(!PlatformExprStrategy::should_block_partial_exit_residual_slot(0.5, true));
assert!(!PlatformExprStrategy::should_block_partial_exit_residual_slot(1.0, false));
}
#[test]
fn platform_aiquant_daily_top_up_uses_remaining_slot_budget() {
let prev_date = d(2025, 2, 2);