禁止退出信号股票当日补仓

This commit is contained in:
boris
2026-07-10 14:21:13 +08:00
parent 0aef8f9491
commit 558d92fe23
+36 -54
View File
@@ -8762,23 +8762,9 @@ impl Strategy for PlatformExprStrategy {
if !stop_hit && !profit_hit { if !stop_hit && !profit_hit {
continue; continue;
} }
let lower_limit_blocked = match self.stock_state_at_time(
ctx,
projection_date,
&position.symbol,
Some(self.intraday_execution_start_time()),
) {
Ok(stock) => stock.lower_limit > 0.0 && stock.last <= stock.lower_limit,
Err(BacktestError::Data(crate::data::DataSetError::MissingSnapshot {
..
})) => false,
Err(error) => return Err(error),
};
if !lower_limit_blocked {
stop_take_exit_signal_symbols.insert(position.symbol.clone()); stop_take_exit_signal_symbols.insert(position.symbol.clone());
} }
} }
}
if self.config.aiquant_transaction_cost if self.config.aiquant_transaction_cost
&& self.config.rotation_enabled && self.config.rotation_enabled
@@ -9255,6 +9241,9 @@ impl Strategy for PlatformExprStrategy {
let rebalance_value_symbols = rebalance_working_symbols.clone(); let rebalance_value_symbols = rebalance_working_symbols.clone();
let mut rebalance_pending_buy_value = 0.0_f64; let mut rebalance_pending_buy_value = 0.0_f64;
for symbol in stock_list.iter().take(selection_limit) { for symbol in stock_list.iter().take(selection_limit) {
if exit_symbols.contains(symbol) {
continue;
}
let decision_stock = self.stock_state_with_factor_date( let decision_stock = self.stock_state_with_factor_date(
ctx, ctx,
decision_date, decision_date,
@@ -17290,7 +17279,7 @@ mod tests {
} }
#[test] #[test]
fn platform_aiquant_allows_target_adjust_when_stop_loss_sell_is_lower_limit_blocked() { fn platform_aiquant_blocks_target_increase_when_stop_loss_sell_is_lower_limit_blocked() {
let prev_date = d(2025, 1, 10); let prev_date = d(2025, 1, 10);
let date = d(2025, 1, 13); let date = d(2025, 1, 13);
let symbol = "603269.SH"; let symbol = "603269.SH";
@@ -17420,7 +17409,7 @@ mod tests {
reason, reason,
} if intent_symbol == symbol && *target_value == 0.0 && reason == "stop_loss_exit" } if intent_symbol == symbol && *target_value == 0.0 && reason == "stop_loss_exit"
))); )));
assert!(decision.order_intents.iter().any(|intent| matches!( assert!(!decision.order_intents.iter().any(|intent| matches!(
intent, intent,
OrderIntent::Shares { OrderIntent::Shares {
symbol: intent_symbol, symbol: intent_symbol,
@@ -21189,7 +21178,7 @@ mod tests {
} }
#[test] #[test]
fn platform_weak_market_adjusts_before_lower_limit_blocked_stop_loss() { fn platform_weak_market_skips_target_increase_before_lower_limit_blocked_stop_loss() {
let prev_date = d(2025, 2, 2); let prev_date = d(2025, 2, 2);
let date = d(2025, 2, 3); let date = d(2025, 2, 3);
let symbols = ["000001.SZ", "000002.SZ"]; let symbols = ["000001.SZ", "000002.SZ"];
@@ -21315,24 +21304,8 @@ mod tests {
let decision = strategy.on_day(&ctx).expect("platform decision"); let decision = strategy.on_day(&ctx).expect("platform decision");
let stop_loss_index = decision
.order_intents
.iter()
.position(|intent| {
matches!(
intent,
OrderIntent::TargetValue {
symbol,
target_value,
reason,
} if symbol == "000001.SZ" && *target_value == 0.0 && reason == "stop_loss_exit"
)
})
.expect("stop-loss exit");
assert!( assert!(
decision.order_intents[..stop_loss_index] !decision.order_intents.iter().any(|intent| matches!(
.iter()
.any(|intent| matches!(
intent, intent,
OrderIntent::Shares { OrderIntent::Shares {
symbol, symbol,
@@ -21345,6 +21318,14 @@ mod tests {
"{:?}", "{:?}",
decision.order_intents decision.order_intents
); );
assert!(decision.order_intents.iter().any(|intent| matches!(
intent,
OrderIntent::TargetValue {
symbol,
target_value,
reason,
} if symbol == "000001.SZ" && *target_value == 0.0 && reason == "stop_loss_exit"
)));
assert!(decision.order_intents.iter().any(|intent| matches!( assert!(decision.order_intents.iter().any(|intent| matches!(
intent, intent,
OrderIntent::Value { symbol, reason, .. } OrderIntent::Value { symbol, reason, .. }
@@ -21353,7 +21334,7 @@ mod tests {
} }
#[test] #[test]
fn platform_weak_market_adjusts_before_intraday_stop_loss_sell_blocked() { fn platform_weak_market_skips_target_increase_before_intraday_stop_loss_sell_blocked() {
let prev_date = d(2025, 2, 2); let prev_date = d(2025, 2, 2);
let date = d(2025, 2, 3); let date = d(2025, 2, 3);
let symbols = ["000001.SZ", "000002.SZ"]; let symbols = ["000001.SZ", "000002.SZ"];
@@ -21497,24 +21478,8 @@ mod tests {
let decision = strategy.on_day(&ctx).expect("platform decision"); let decision = strategy.on_day(&ctx).expect("platform decision");
let stop_loss_index = decision
.order_intents
.iter()
.position(|intent| {
matches!(
intent,
OrderIntent::TargetValue {
symbol,
target_value,
reason,
} if symbol == "000001.SZ" && *target_value == 0.0 && reason == "stop_loss_exit"
)
})
.expect("stop-loss exit");
assert!( assert!(
decision.order_intents[..stop_loss_index] !decision.order_intents.iter().any(|intent| matches!(
.iter()
.any(|intent| matches!(
intent, intent,
OrderIntent::Shares { OrderIntent::Shares {
symbol, symbol,
@@ -21527,6 +21492,14 @@ mod tests {
"{:?}", "{:?}",
decision.order_intents decision.order_intents
); );
assert!(decision.order_intents.iter().any(|intent| matches!(
intent,
OrderIntent::TargetValue {
symbol,
target_value,
reason,
} if symbol == "000001.SZ" && *target_value == 0.0 && reason == "stop_loss_exit"
)));
assert!(decision.order_intents.iter().any(|intent| matches!( assert!(decision.order_intents.iter().any(|intent| matches!(
intent, intent,
OrderIntent::Value { symbol, reason, .. } OrderIntent::Value { symbol, reason, .. }
@@ -24915,7 +24888,7 @@ mod tests {
} }
#[test] #[test]
fn platform_periodic_rebalance_can_rebuy_released_unsellable_stop_loss_symbol() { fn platform_periodic_rebalance_skips_unsellable_stop_loss_symbol() {
let prev_date = d(2025, 5, 13); let prev_date = d(2025, 5, 13);
let date = d(2025, 5, 14); let date = d(2025, 5, 14);
let symbols = ["000001.SZ", "000002.SZ", "000003.SZ"]; let symbols = ["000001.SZ", "000002.SZ", "000003.SZ"];
@@ -25078,7 +25051,7 @@ mod tests {
decision.order_intents decision.order_intents
); );
assert!( assert!(
decision.order_intents.iter().any(|intent| matches!( !decision.order_intents.iter().any(|intent| matches!(
intent, intent,
OrderIntent::Value { symbol, reason, .. } OrderIntent::Value { symbol, reason, .. }
if symbol == "000001.SZ" && reason == "periodic_rebalance_buy" if symbol == "000001.SZ" && reason == "periodic_rebalance_buy"
@@ -25086,6 +25059,15 @@ mod tests {
"{:?}", "{:?}",
decision.order_intents decision.order_intents
); );
assert!(
decision.order_intents.iter().any(|intent| matches!(
intent,
OrderIntent::Value { symbol, reason, .. }
if symbol == "000003.SZ" && reason == "periodic_rebalance_buy"
)),
"{:?}",
decision.order_intents
);
} }
#[test] #[test]