修正延迟撮合选股与目标金额语义
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user