分离股票池精确预算比例与展示基点并持久化状态
This commit is contained in:
@@ -484,6 +484,8 @@ pub struct StockPoolDecisionConstraints {
|
||||
pub execution_date: Option<NaiveDate>,
|
||||
pub frozen_positions: BTreeMap<String, FrozenStockPoolPosition>,
|
||||
pub prior_target_weights: BTreeMap<String, i32>,
|
||||
/// Sizing ratios from prior plans; integer bps are display/legacy only.
|
||||
pub prior_target_weight_ratios: BTreeMap<String, Decimal>,
|
||||
pub pending_entry_symbols: BTreeSet<String>,
|
||||
pub next_day_outside_exit_symbols: BTreeSet<String>,
|
||||
pub market_timing_policy: Option<crate::stock_pool_index_policy::MarketTimingPolicy>,
|
||||
@@ -530,6 +532,8 @@ pub struct StockPoolPlanRow {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct StockPoolPlan {
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub target_weight_ratios: BTreeMap<String, Decimal>,
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub position_action_bases: BTreeMap<String, Decimal>,
|
||||
pub market_timing: Option<crate::stock_pool_index_policy::MarketTimingEvaluation>,
|
||||
@@ -1096,6 +1100,11 @@ pub fn build_stock_pool_target_plan_with_fee_model(
|
||||
target_count,
|
||||
)?
|
||||
};
|
||||
let target_weight_ratios = frozen::sizing_ratios(
|
||||
&original_final_symbols, &active_symbols, &explicit_weights,
|
||||
constraints, reserved_protected_slots, &weights,
|
||||
)?;
|
||||
let sizing_ratio = |symbol: &str| target_weight_ratios.get(symbol).copied().unwrap_or(Decimal::ZERO);
|
||||
for symbol in &rebuy_exclusions {
|
||||
if original_final_symbols.contains(symbol) || current.contains_key(symbol) {
|
||||
weights.insert(symbol.clone(), 0);
|
||||
@@ -1235,8 +1244,7 @@ pub fn build_stock_pool_target_plan_with_fee_model(
|
||||
.map(|symbol| {
|
||||
let current_value = current[symbol].0
|
||||
* frozen::valuation(symbol, "e_map, &constraints.frozen_positions)?;
|
||||
let desired =
|
||||
budget * Decimal::from(*weights.get(symbol).unwrap_or(&0)) / Decimal::from(10_000);
|
||||
let desired = budget * sizing_ratio(symbol);
|
||||
if constraints.frozen_positions.contains_key(symbol) {
|
||||
return Ok((symbol.clone(), desired));
|
||||
}
|
||||
@@ -1277,7 +1285,7 @@ pub fn build_stock_pool_target_plan_with_fee_model(
|
||||
let free_desired = weights
|
||||
.iter()
|
||||
.filter(|(symbol, _)| !protected_values.contains_key(*symbol))
|
||||
.map(|(_, weight)| budget * Decimal::from(*weight) / Decimal::from(10_000))
|
||||
.map(|(symbol, _)| budget * sizing_ratio(symbol))
|
||||
.sum::<Decimal>();
|
||||
let free_budget = (budget * Decimal::from(requested_weight_total) / Decimal::from(10_000)
|
||||
- protected_values.values().copied().sum::<Decimal>())
|
||||
@@ -1296,7 +1304,7 @@ pub fn build_stock_pool_target_plan_with_fee_model(
|
||||
rows.push(StockPoolPlanRow {
|
||||
symbol: symbol.clone(),
|
||||
target_weight_bps: weight,
|
||||
target_value: budget * Decimal::from(weight) / Decimal::from(10_000),
|
||||
target_value: budget * sizing_ratio(symbol),
|
||||
current_quantity: quantity,
|
||||
target_quantity: quantity,
|
||||
delta_quantity: Decimal::ZERO,
|
||||
@@ -1570,7 +1578,7 @@ pub fn build_stock_pool_target_plan_with_fee_model(
|
||||
let target_value = protected_values
|
||||
.get(symbol)
|
||||
.copied()
|
||||
.unwrap_or(budget * Decimal::from(weight) / Decimal::from(10_000) * free_scale)
|
||||
.unwrap_or(if weight == 0 { Decimal::ZERO } else { budget * sizing_ratio(symbol) * free_scale })
|
||||
.round_dp_with_strategy(2, RoundingStrategy::MidpointNearestEven);
|
||||
let sizing_price = if target_value >= current_quantity * quote.last_price {
|
||||
quote.buy_sizing_price.unwrap_or(quote.last_price)
|
||||
@@ -1995,6 +2003,7 @@ pub fn build_stock_pool_target_plan_with_fee_model(
|
||||
.map(|row| (row.symbol.clone(), constraints.position_action_bases.get(&row.symbol).copied().unwrap_or(row.current_quantity)))
|
||||
.collect();
|
||||
Ok(StockPoolPlan {
|
||||
target_weight_ratios,
|
||||
position_action_bases,
|
||||
market_timing,
|
||||
rows,
|
||||
|
||||
Reference in New Issue
Block a user