修正目标组合卖出后统一补仓

This commit is contained in:
boris
2026-07-17 22:22:14 +08:00
parent b6df63c79e
commit 031e4ee054
+55 -10
View File
@@ -9728,7 +9728,7 @@ impl Strategy for PlatformExprStrategy {
.unwrap_or(0);
let quantity_delta = after_qty as i32 - before_qty as i32;
if stop_take_exit_signal_symbols.contains(&position.symbol)
&& quantity_delta >= 0
&& (self.config.target_portfolio_daily_enabled || quantity_delta >= 0)
{
continue;
}
@@ -9874,7 +9874,7 @@ impl Strategy for PlatformExprStrategy {
}
}
}
if daily_top_up_active {
if daily_top_up_active && !self.config.target_portfolio_daily_enabled {
self.try_daily_top_up_at_position(
ctx,
&day,
@@ -9986,7 +9986,7 @@ impl Strategy for PlatformExprStrategy {
} else if stop_hit {
unresolved_stop_loss_symbols.insert(position.symbol.clone());
}
if daily_top_up_active {
if daily_top_up_active && !self.config.target_portfolio_daily_enabled {
self.try_daily_top_up_at_position(
ctx,
&day,
@@ -10073,7 +10073,7 @@ impl Strategy for PlatformExprStrategy {
} else {
unresolved_stop_loss_symbols.insert(position.symbol.clone());
}
if daily_top_up_active {
if daily_top_up_active && !self.config.target_portfolio_daily_enabled {
self.try_daily_top_up_at_position(
ctx,
&day,
@@ -10154,7 +10154,7 @@ impl Strategy for PlatformExprStrategy {
}
}
}
if daily_top_up_active {
if daily_top_up_active && !self.config.target_portfolio_daily_enabled {
self.try_daily_top_up_at_position(
ctx,
&day,
@@ -10188,6 +10188,39 @@ impl Strategy for PlatformExprStrategy {
}
}
if daily_top_up_active && self.config.target_portfolio_daily_enabled {
self.try_daily_top_up_at_position(
ctx,
&day,
&stock_list,
decision_date,
execution_date,
projection_date,
selection_factor_date,
signal_date,
daily_top_up_target_budget,
selection_limit,
defer_execution_risk,
None,
&mut projected,
&mut projected_execution_state,
&mut order_intents,
&mut aiquant_available_cash,
&mut slot_working_symbols,
&mut same_bar_buy_symbols,
&pending_full_close_symbols,
&slot_blocking_symbols,
&same_day_sold_symbols,
&exit_symbols,
&delayed_sold_symbols,
&mut intraday_attempted_buys,
&mut daily_top_up_pending_buy_value,
&deferred_daily_target_values,
debug_daily_top_up,
&mut daily_top_up_debug_notes,
)?;
}
if periodic_rebalance {
let rebalance_existing_positions = self.config.rebalance_existing_positions
|| self
@@ -23988,6 +24021,8 @@ mod tests {
cfg.exposure_expr = "1.0".to_string();
cfg.take_profit_expr = "1.1".to_string();
cfg.daily_top_up_enabled = true;
cfg.daily_position_target_adjust_enabled = true;
cfg.target_portfolio_daily_enabled = true;
cfg.release_slot_on_exit_signal = true;
cfg.aiquant_transaction_cost = true;
cfg.intraday_execution_time = Some(NaiveTime::from_hms_opt(10, 18, 0).unwrap());
@@ -23995,13 +24030,15 @@ mod tests {
strategy.rebalance_day_counter = 2;
let decision = strategy.on_day(&ctx).expect("platform decision");
let top_up_symbols = decision
let top_ups = decision
.order_intents
.iter()
.filter_map(|intent| match intent {
OrderIntent::Value { symbol, reason, .. } if reason == "daily_top_up_buy" => {
Some(symbol.as_str())
}
OrderIntent::Value {
symbol,
value,
reason,
} if reason == "daily_top_up_buy" => Some((symbol.as_str(), *value)),
_ => None,
})
.collect::<Vec<_>>();
@@ -24019,11 +24056,19 @@ mod tests {
decision.order_intents
);
assert_eq!(
top_up_symbols,
top_ups
.iter()
.map(|(symbol, _)| *symbol)
.collect::<Vec<_>>(),
vec![buy_first, buy_second],
"{:?}",
decision.order_intents
);
assert!(
top_ups.iter().all(|(_, value)| *value >= 6_900.0),
"top ups must be sized after all same-batch sells: {:?}",
decision.order_intents
);
}
fn partial_stop_loss_top_up_symbols_for_exposure(exposure_expr: &str) -> Vec<String> {