修正延迟撮合选股与目标金额语义
This commit is contained in:
@@ -7745,31 +7745,11 @@ impl PlatformExprStrategy {
|
|||||||
band_high: f64,
|
band_high: f64,
|
||||||
limit: usize,
|
limit: usize,
|
||||||
) -> Result<(Vec<String>, Vec<String>, Vec<FidcRiskDecisionAudit>), BacktestError> {
|
) -> Result<(Vec<String>, Vec<String>, Vec<FidcRiskDecisionAudit>), BacktestError> {
|
||||||
let selection_risk_deferral = if ctx.is_lagged_execution() {
|
// Selection policy is evaluated on the signal day. Lagged execution only
|
||||||
SelectionRiskDeferral::All
|
// defers buy/sell risk to the actual execution bar; it must not disable an
|
||||||
} else {
|
// explicitly configured signal-day universe filter.
|
||||||
SelectionRiskDeferral::None
|
let universe = self.selectable_universe_on(ctx, date, universe_factor_date);
|
||||||
};
|
let risk_decisions = self.selection_risk_decisions(ctx, date, universe_factor_date);
|
||||||
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)
|
|
||||||
};
|
|
||||||
let mut diagnostics = Self::selection_risk_decision_diagnostics(
|
let mut diagnostics = Self::selection_risk_decision_diagnostics(
|
||||||
&risk_decisions,
|
&risk_decisions,
|
||||||
date,
|
date,
|
||||||
@@ -9456,7 +9436,16 @@ impl Strategy for PlatformExprStrategy {
|
|||||||
}
|
}
|
||||||
projected = trial_projected;
|
projected = trial_projected;
|
||||||
projected_execution_state = trial_execution_state;
|
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 {
|
order_intents.push(OrderIntent::Shares {
|
||||||
symbol: position.symbol.clone(),
|
symbol: position.symbol.clone(),
|
||||||
quantity: quantity_delta,
|
quantity: quantity_delta,
|
||||||
@@ -16344,6 +16333,8 @@ mod tests {
|
|||||||
cfg.stock_filter_expr = "false".to_string();
|
cfg.stock_filter_expr = "false".to_string();
|
||||||
cfg.stop_loss_expr.clear();
|
cfg.stop_loss_expr.clear();
|
||||||
cfg.take_profit_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.volume_limit_enabled = true;
|
||||||
cfg.risk_config.trading_constraints.liquidity_limit_enabled = true;
|
cfg.risk_config.trading_constraints.liquidity_limit_enabled = true;
|
||||||
cfg.risk_config.trading_constraints.volume_percent = 0.25;
|
cfg.risk_config.trading_constraints.volume_percent = 0.25;
|
||||||
@@ -16353,13 +16344,17 @@ mod tests {
|
|||||||
|
|
||||||
assert!(decision.order_intents.iter().any(|intent| matches!(
|
assert!(decision.order_intents.iter().any(|intent| matches!(
|
||||||
intent,
|
intent,
|
||||||
OrderIntent::Shares {
|
OrderIntent::TargetValue {
|
||||||
symbol: intent_symbol,
|
symbol: intent_symbol,
|
||||||
quantity,
|
target_value,
|
||||||
reason
|
reason
|
||||||
} if intent_symbol == symbol
|
} if intent_symbol == symbol
|
||||||
&& reason == "daily_position_target_adjust"
|
&& 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]
|
#[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 factor_date = d(2023, 11, 10);
|
||||||
let decision_date = d(2023, 11, 13);
|
let decision_date = d(2023, 11, 13);
|
||||||
let execution_date = d(2023, 11, 14);
|
let execution_date = d(2023, 11, 14);
|
||||||
@@ -19259,7 +19254,7 @@ mod tests {
|
|||||||
decision
|
decision
|
||||||
.diagnostics
|
.diagnostics
|
||||||
.iter()
|
.iter()
|
||||||
.any(|item| item == "selected_symbols=600462.SH"),
|
.all(|item| item != "selected_symbols=600462.SH"),
|
||||||
"{:?}",
|
"{:?}",
|
||||||
decision.diagnostics
|
decision.diagnostics
|
||||||
);
|
);
|
||||||
@@ -19272,15 +19267,15 @@ mod tests {
|
|||||||
decision.diagnostics
|
decision.diagnostics
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
decision.order_intents.iter().any(|intent| matches!(
|
decision.order_intents.iter().all(|intent| !matches!(
|
||||||
intent,
|
intent,
|
||||||
OrderIntent::Shares { symbol, quantity, .. }
|
OrderIntent::Shares { symbol, quantity, .. }
|
||||||
if symbol == candidate_symbol && *quantity > 0
|
if symbol == candidate_symbol && *quantity > 0
|
||||||
) || matches!(
|
) && !matches!(
|
||||||
intent,
|
intent,
|
||||||
OrderIntent::Value { symbol, value, .. }
|
OrderIntent::Value { symbol, value, .. }
|
||||||
if symbol == candidate_symbol && *value > 0.0
|
if symbol == candidate_symbol && *value > 0.0
|
||||||
) || matches!(
|
) && !matches!(
|
||||||
intent,
|
intent,
|
||||||
OrderIntent::TargetValue {
|
OrderIntent::TargetValue {
|
||||||
symbol,
|
symbol,
|
||||||
|
|||||||
Reference in New Issue
Block a user