fix(stock-pool): keep full stops stronger than simultaneous reductions
This commit is contained in:
@@ -669,6 +669,13 @@ pub fn build_stock_pool_target_plan_with_fee_model(
|
||||
}
|
||||
}
|
||||
}
|
||||
// Validate source targets before a stronger stop/expiry can replace them.
|
||||
// Otherwise an invalid ratio could be hidden by target consolidation.
|
||||
for (symbol, target) in &constraints.position_target_bps {
|
||||
if *target >= 10_000 {
|
||||
return Err(format!("factor position target for {symbol} must be below 10000 bps"));
|
||||
}
|
||||
}
|
||||
let mut effective_position_targets = constraints.position_target_bps.clone();
|
||||
for (symbol, permission) in &constraints.automatic_permissions {
|
||||
if permission.max_holding_exit {
|
||||
@@ -863,6 +870,13 @@ pub fn build_stock_pool_target_plan_with_fee_model(
|
||||
.then(|| symbol.clone())
|
||||
})
|
||||
.collect::<BTreeSet<_>>();
|
||||
// A full stop is stricter than a simultaneous relative reduction. Merge
|
||||
// the target before selecting its single owner, never emit a second exit.
|
||||
for symbol in &global_stop_hits {
|
||||
if let Some(target) = effective_position_targets.get_mut(symbol) {
|
||||
*target = 0;
|
||||
}
|
||||
}
|
||||
let mut quote_sell_exits = BTreeSet::new();
|
||||
let mut sell_condition_denials = BTreeSet::new();
|
||||
if rule.sell_trigger_mode == POOL_SELL_CONDITION {
|
||||
@@ -1327,11 +1341,6 @@ pub fn build_stock_pool_target_plan_with_fee_model(
|
||||
}
|
||||
|
||||
for (symbol, target_bps) in factor_position_target_bps {
|
||||
if *target_bps >= 10_000 {
|
||||
return Err(format!(
|
||||
"factor position target for {symbol} must be below 10000 bps"
|
||||
));
|
||||
}
|
||||
if !member_map.contains_key(symbol) && !current.contains_key(symbol) {
|
||||
return Err(format!(
|
||||
"factor position-action symbol {symbol} is outside candidates and managed holdings"
|
||||
@@ -1418,6 +1427,8 @@ pub fn build_stock_pool_target_plan_with_fee_model(
|
||||
"达到最长持有期,按配置退出"
|
||||
} else if quote_sell_exits.contains(symbol) {
|
||||
"卖出行情条件命中"
|
||||
} else if stop_take_exits.contains(symbol) {
|
||||
"止损/止盈触发,覆盖较弱的减仓目标"
|
||||
} else if *target_bps == 0 {
|
||||
"生产因子退出条件命中"
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user