修正延迟调仓剩余仓位预算

This commit is contained in:
boris
2026-07-17 12:43:53 +08:00
parent bdd5a41106
commit 81ac623fca
@@ -2578,6 +2578,7 @@ impl PlatformExprStrategy {
working_symbols: &BTreeSet<String>, working_symbols: &BTreeSet<String>,
value_symbols: &BTreeSet<String>, value_symbols: &BTreeSet<String>,
pending_buy_value: f64, pending_buy_value: f64,
deferred_target_values: Option<&BTreeMap<String, f64>>,
slot_blocking_symbols: &BTreeSet<String>, slot_blocking_symbols: &BTreeSet<String>,
) -> f64 { ) -> f64 {
if selection_limit == 0 || !target_budget.is_finite() || target_budget <= 0.0 { if selection_limit == 0 || !target_budget.is_finite() || target_budget <= 0.0 {
@@ -2597,6 +2598,7 @@ impl PlatformExprStrategy {
date, date,
working_symbols, working_symbols,
value_symbols, value_symbols,
deferred_target_values,
); );
let working_value = active_value + pending_buy_value.max(0.0); let working_value = active_value + pending_buy_value.max(0.0);
let per_slot_budget = (target_budget - working_value).max(0.0) / slots_remaining as f64; let per_slot_budget = (target_budget - working_value).max(0.0) / slots_remaining as f64;
@@ -2632,6 +2634,7 @@ impl PlatformExprStrategy {
delayed_sold_symbols: &BTreeSet<String>, delayed_sold_symbols: &BTreeSet<String>,
intraday_attempted_buys: &mut BTreeSet<String>, intraday_attempted_buys: &mut BTreeSet<String>,
pending_buy_value: &mut f64, pending_buy_value: &mut f64,
deferred_target_values: &BTreeMap<String, f64>,
debug_daily_top_up: bool, debug_daily_top_up: bool,
daily_top_up_debug_notes: &mut Vec<String>, daily_top_up_debug_notes: &mut Vec<String>,
) -> Result<bool, BacktestError> { ) -> Result<bool, BacktestError> {
@@ -2668,6 +2671,7 @@ impl PlatformExprStrategy {
projection_date, projection_date,
&budget_working_symbols, &budget_working_symbols,
&value_symbols, &value_symbols,
Some(deferred_target_values),
) )
} else { } else {
0.0 0.0
@@ -2681,6 +2685,7 @@ impl PlatformExprStrategy {
&budget_working_symbols, &budget_working_symbols,
&value_symbols, &value_symbols,
*pending_buy_value, *pending_buy_value,
Some(deferred_target_values),
slot_blocking_symbols, slot_blocking_symbols,
); );
let available_buy_cash = slot_buy_cash.min(*aiquant_available_cash); let available_buy_cash = slot_buy_cash.min(*aiquant_available_cash);
@@ -2832,11 +2837,18 @@ impl PlatformExprStrategy {
date: NaiveDate, date: NaiveDate,
working_symbols: &BTreeSet<String>, working_symbols: &BTreeSet<String>,
value_symbols: &BTreeSet<String>, value_symbols: &BTreeSet<String>,
deferred_target_values: Option<&BTreeMap<String, f64>>,
) -> f64 { ) -> f64 {
working_symbols working_symbols
.iter() .iter()
.filter(|symbol| value_symbols.contains(*symbol)) .filter(|symbol| value_symbols.contains(*symbol))
.map(|symbol| { .map(|symbol| {
if let Some(target_value) = deferred_target_values
.and_then(|target_values| target_values.get(symbol))
.filter(|target_value| target_value.is_finite() && **target_value >= 0.0)
{
return *target_value;
}
if self.config.aiquant_transaction_cost { if self.config.aiquant_transaction_cost {
self.projected_strategy_visible_position_value_for_remaining_buy_cash( self.projected_strategy_visible_position_value_for_remaining_buy_cash(
ctx, projected, date, symbol, ctx, projected, date, symbol,
@@ -9261,6 +9273,7 @@ impl Strategy for PlatformExprStrategy {
&& selection_limit > 0; && selection_limit > 0;
let daily_top_up_target_budget = aiquant_total_value * trading_ratio; let daily_top_up_target_budget = aiquant_total_value * trading_ratio;
let mut daily_top_up_pending_buy_value = 0.0_f64; let mut daily_top_up_pending_buy_value = 0.0_f64;
let mut deferred_daily_target_values = BTreeMap::<String, f64>::new();
let mut pending_full_close_symbols = BTreeSet::<String>::new(); let mut pending_full_close_symbols = BTreeSet::<String>::new();
let mut slot_blocking_symbols = BTreeSet::<String>::new(); let mut slot_blocking_symbols = BTreeSet::<String>::new();
let should_block_partial_exit_residual_slot = trading_ratio < 1.0; let should_block_partial_exit_residual_slot = trading_ratio < 1.0;
@@ -9506,6 +9519,10 @@ impl Strategy for PlatformExprStrategy {
target_value, target_value,
reason: "daily_position_target_adjust".to_string(), reason: "daily_position_target_adjust".to_string(),
}); });
if defer_execution_risk {
deferred_daily_target_values
.insert(position.symbol.clone(), target_value);
}
if quantity_delta > 0 { if quantity_delta > 0 {
same_bar_buy_symbols.insert(position.symbol.clone()); same_bar_buy_symbols.insert(position.symbol.clone());
} }
@@ -9592,6 +9609,7 @@ impl Strategy for PlatformExprStrategy {
&delayed_sold_symbols, &delayed_sold_symbols,
&mut intraday_attempted_buys, &mut intraday_attempted_buys,
&mut daily_top_up_pending_buy_value, &mut daily_top_up_pending_buy_value,
&deferred_daily_target_values,
debug_daily_top_up, debug_daily_top_up,
&mut daily_top_up_debug_notes, &mut daily_top_up_debug_notes,
)?; )?;
@@ -9691,6 +9709,7 @@ impl Strategy for PlatformExprStrategy {
&delayed_sold_symbols, &delayed_sold_symbols,
&mut intraday_attempted_buys, &mut intraday_attempted_buys,
&mut daily_top_up_pending_buy_value, &mut daily_top_up_pending_buy_value,
&deferred_daily_target_values,
debug_daily_top_up, debug_daily_top_up,
&mut daily_top_up_debug_notes, &mut daily_top_up_debug_notes,
)?; )?;
@@ -9766,6 +9785,7 @@ impl Strategy for PlatformExprStrategy {
&delayed_sold_symbols, &delayed_sold_symbols,
&mut intraday_attempted_buys, &mut intraday_attempted_buys,
&mut daily_top_up_pending_buy_value, &mut daily_top_up_pending_buy_value,
&deferred_daily_target_values,
debug_daily_top_up, debug_daily_top_up,
&mut daily_top_up_debug_notes, &mut daily_top_up_debug_notes,
)?; )?;
@@ -9835,6 +9855,7 @@ impl Strategy for PlatformExprStrategy {
&delayed_sold_symbols, &delayed_sold_symbols,
&mut intraday_attempted_buys, &mut intraday_attempted_buys,
&mut daily_top_up_pending_buy_value, &mut daily_top_up_pending_buy_value,
&deferred_daily_target_values,
debug_daily_top_up, debug_daily_top_up,
&mut daily_top_up_debug_notes, &mut daily_top_up_debug_notes,
)?; )?;
@@ -10084,6 +10105,7 @@ impl Strategy for PlatformExprStrategy {
&rebalance_working_symbols, &rebalance_working_symbols,
&rebalance_value_symbols, &rebalance_value_symbols,
rebalance_pending_buy_value, rebalance_pending_buy_value,
None,
&pending_full_close_symbols, &pending_full_close_symbols,
); );
let target_cash = slot_buy_cash * stock_scale; let target_cash = slot_buy_cash * stock_scale;
@@ -21850,6 +21872,7 @@ mod tests {
&working_symbols, &working_symbols,
&value_symbols, &value_symbols,
0.0, 0.0,
None,
&BTreeSet::new(), &BTreeSet::new(),
); );
@@ -21857,6 +21880,24 @@ mod tests {
(cash - 5_000.0).abs() < 1e-6, (cash - 5_000.0).abs() < 1e-6,
"remaining cash should use strategy-visible price and projected 500-share quantity, got {cash}" "remaining cash should use strategy-visible price and projected 500-share quantity, got {cash}"
); );
let deferred_targets = BTreeMap::from([("000001.SZ".to_string(), 2_000.0)]);
let deferred_cash = strategy.remaining_buy_cash_per_slot(
&ctx,
&projected,
date,
6_000.0,
2,
&working_symbols,
&value_symbols,
0.0,
Some(&deferred_targets),
&BTreeSet::new(),
);
assert!(
(deferred_cash - 3_000.0).abs() < 1e-6,
"lagged target reductions should reserve their frozen target value, got {deferred_cash}"
);
} }
#[test] #[test]