修正延迟撮合选股与目标金额语义

This commit is contained in:
boris
2026-07-17 08:55:16 +08:00
parent 8f167e7de1
commit a734cbeaec
+29 -34
View File
@@ -7745,31 +7745,11 @@ impl PlatformExprStrategy {
band_high: f64,
limit: usize,
) -> Result<(Vec<String>, Vec<String>, Vec<FidcRiskDecisionAudit>), BacktestError> {
let selection_risk_deferral = if ctx.is_lagged_execution() {
SelectionRiskDeferral::All
} else {
SelectionRiskDeferral::None
};
let universe = if selection_risk_deferral != SelectionRiskDeferral::None {
self.selectable_universe_on_with_options(
ctx,
date,
universe_factor_date,
selection_risk_deferral,
)
} else {
self.selectable_universe_on(ctx, date, universe_factor_date)
};
let risk_decisions = if selection_risk_deferral != SelectionRiskDeferral::None {
self.selection_risk_decisions_with_options(
ctx,
date,
universe_factor_date,
selection_risk_deferral,
)
} else {
self.selection_risk_decisions(ctx, date, universe_factor_date)
};
// Selection policy is evaluated on the signal day. Lagged execution only
// defers buy/sell risk to the actual execution bar; it must not disable an
// explicitly configured signal-day universe filter.
let universe = self.selectable_universe_on(ctx, date, universe_factor_date);
let risk_decisions = self.selection_risk_decisions(ctx, date, universe_factor_date);
let mut diagnostics = Self::selection_risk_decision_diagnostics(
&risk_decisions,
date,
@@ -9456,7 +9436,16 @@ impl Strategy for PlatformExprStrategy {
}
projected = trial_projected;
projected_execution_state = trial_execution_state;
if quantity_delta != 0 {
if self.config.target_portfolio_daily_enabled {
order_intents.push(OrderIntent::TargetValue {
symbol: position.symbol.clone(),
target_value,
reason: "daily_position_target_adjust".to_string(),
});
if quantity_delta > 0 {
same_bar_buy_symbols.insert(position.symbol.clone());
}
} else if quantity_delta != 0 {
order_intents.push(OrderIntent::Shares {
symbol: position.symbol.clone(),
quantity: quantity_delta,
@@ -16344,6 +16333,8 @@ mod tests {
cfg.stock_filter_expr = "false".to_string();
cfg.stop_loss_expr.clear();
cfg.take_profit_expr.clear();
cfg.target_portfolio_daily_enabled = true;
cfg.matching_type = MatchingType::NextBarOpen;
cfg.risk_config.trading_constraints.volume_limit_enabled = true;
cfg.risk_config.trading_constraints.liquidity_limit_enabled = true;
cfg.risk_config.trading_constraints.volume_percent = 0.25;
@@ -16353,13 +16344,17 @@ mod tests {
assert!(decision.order_intents.iter().any(|intent| matches!(
intent,
OrderIntent::Shares {
OrderIntent::TargetValue {
symbol: intent_symbol,
quantity,
target_value,
reason
} if intent_symbol == symbol
&& reason == "daily_position_target_adjust"
&& *quantity == 100
&& *target_value > 0.0
)));
assert!(!decision.order_intents.iter().any(|intent| matches!(
intent,
OrderIntent::Shares { reason, .. } if reason == "daily_position_target_adjust"
)));
}
@@ -19088,7 +19083,7 @@ mod tests {
}
#[test]
fn platform_next_open_selection_records_risk_diagnostics_without_filtering() {
fn platform_next_open_selection_applies_explicit_signal_day_risk_filter() {
let factor_date = d(2023, 11, 10);
let decision_date = d(2023, 11, 13);
let execution_date = d(2023, 11, 14);
@@ -19259,7 +19254,7 @@ mod tests {
decision
.diagnostics
.iter()
.any(|item| item == "selected_symbols=600462.SH"),
.all(|item| item != "selected_symbols=600462.SH"),
"{:?}",
decision.diagnostics
);
@@ -19272,15 +19267,15 @@ mod tests {
decision.diagnostics
);
assert!(
decision.order_intents.iter().any(|intent| matches!(
decision.order_intents.iter().all(|intent| !matches!(
intent,
OrderIntent::Shares { symbol, quantity, .. }
if symbol == candidate_symbol && *quantity > 0
) || matches!(
) && !matches!(
intent,
OrderIntent::Value { symbol, value, .. }
if symbol == candidate_symbol && *value > 0.0
) || matches!(
) && !matches!(
intent,
OrderIntent::TargetValue {
symbol,