feat(quant-engine): v8.9 제안서 P0-P3 로드맵 채택 — 15개 의사결정 엔진 신규 구현

suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml의
implementation_todo_v8_9(P0~P4) 전체를 spec/tool/golden case 레벨로 구현.

- P0: PORTFOLIO_TRANSITION_UTILITY_V1, SELL_LOT_PARETO_SELECTOR_V1, FORECAST_SIMULATION_ENGINE_V1
- P1: SECTOR_EXPOSURE_GRAPH_V1/LEADER_LIFECYCLE_GATE_V1, EXECUTION_CAPACITY_LADDER_V1, MODEL_GOVERNANCE_KILL_SWITCH_V1
- P2: SCENARIO_SHOCK_MATRIX_V1, TRANSITION_SET_ENUMERATOR_V1, IMMUTABLE_DECISION_LEDGER_V1, EXECUTION_PLAN_COMPILER_V1
- P3: STATE_VECTOR_CONSTRUCTOR_V1, WALK_FORWARD_BOOTSTRAP_V1, TRANSITION_SET_ENUMERATOR_V1(MRC/CVaR 확장),
      REBALANCE_CADENCE_GATE_V1, WEEKLY_LEGACY_TRANSFER_PLAN_V1

기존 regime/cluster 연동 정책 수치(현금방어선, 반도체 cap)는 그대로 유지하고 신규 cap 필드만 추가.
spec/09_decision_flow.yaml과 runtime/active_artifact_manifest.yaml에 전 엔진 배선 완료.
governance/todo/v8_9_p{0,1,2,3}_adoption_plan.yaml에 각 단계 작업 추적 기록.

검증: validate_specs/validate_golden_coverage_100(100%)/validate_calibration_registry_v1/
validate_schema_model_generation_v1/validate_agents_shrink_v1 전부 PASS. golden test 53/53 PASS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-18 00:06:52 +09:00
parent aed1eae421
commit aedabdd37b
82 changed files with 7515 additions and 5 deletions
+261
View File
@@ -668,3 +668,264 @@ formulas:
activation_threshold:
min_t20_sample: 30
retirement_condition: performance_degradation
PORTFOLIO_TRANSITION_UTILITY_V1:
purpose: >
개별 매수·매도 추천이 아니라 포트폴리오 전체의 사후 상태(전환 후 cash floor, 집중도, CVaR,
세후비용, 회전율)를 비교해 단일 최선 전환 또는 NO_TRADE를 결정론적으로 선택한다.
(governance/todo/v8_9_p0_adoption_plan.yaml P0-1.2,
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:portfolio_transition_optimizer_v8_9)
default_action: NO_TRADE
state_vector_fields:
- cash_ladder
- positions
- sector_exposure_graph
- tax_lots
- risk_bucket_weights
- goal_progress_pct
- data_quality_scores
candidate_action_schema:
- candidate_id
- asset_id
- action_type
- planned_amount_krw
- source_signal_ids
- numeric_provenance_status
hard_veto_order:
- DATA_INVALID
- EXECUTION_MODE_BLOCK
- CASH_FLOOR_BLOCK
- HARD_CONCENTRATION_BLOCK
- NEGATIVE_TRANSITION_UTILITY
inputs:
- field: ce70_net_profit_krw
source: Temp/forecast_simulation_engine_v1.json
unit: KRW
missing_policy: DATA_MISSING — candidate excluded, not assumed zero
- field: tax_fee_slippage_krw
source: Temp/sell_waterfall_engine_v4.json
unit: KRW
- field: cash_repair_benefit_krw
source: Temp/smart_cash_recovery_v9.json
unit: KRW
- field: concentration_reduction_benefit_krw
unit: KRW
- field: turnover_penalty_krw
unit: KRW
expression: >
transition_utility_krw = ce70_net_profit_krw - tax_fee_slippage_krw - cvar_penalty_krw
- drawdown_penalty_krw + cash_repair_benefit_krw + concentration_reduction_benefit_krw
- turnover_penalty_krw
output:
field: transition_utility_krw
unit: KRW
acceptance_margin:
formula: acceptance_margin_krw = transition_utility_krw - max(mode_absolute_hurdle_krw, hurdle_multiple * estimated_total_cost_krw)
reject_if: acceptance_margin_krw <= 0
deterministic_fallbacks:
missing_optimizer_inputs: NO_TRADE_AND_QUARANTINE
solver_failure: NO_TRADE_AND_LOG_SOLVER_FAILURE
rank_tie: choose_lower_turnover_lower_tax_lower_marginal_risk_contribution
conflicting_runtime_packets: BLOCK_AND_REQUIRE_MANIFEST_REPAIR
missing_policy:
hard_constraint_input_missing: NO_TRADE_AND_QUARANTINE
canonical_ref: spec/risk/portfolio_exposure.yaml:concentration_caps_v8_9_supplement
implementation: tools/build_portfolio_transition_optimizer_v1.py
owner: quant_team
lifecycle_state: shadow
input_fields:
- ce70_net_profit_krw
- tax_fee_slippage_krw
- cash_repair_benefit_krw
- concentration_reduction_benefit_krw
- turnover_penalty_krw
output_fields:
- transition_utility_krw
- acceptance_margin_krw
- selected_transition
golden_cases:
- V89_002_no_trade_default
- V89_048_solver_failure
- V89_049_rank_tie
- V89_050_conflicting_packets
activation_threshold:
min_t20_sample: 30
retirement_condition: performance_degradation
TRANSITION_SET_ENUMERATOR_V1:
purpose: >
PORTFOLIO_TRANSITION_UTILITY_V1이 candidate 1건씩 평가하는 것을 넘어, 여러 candidate를
조합한 transition_set 단위로 hard_constraint_pass와 transition_utility_krw를 평가한다.
"좋은 후보 하나"가 포트폴리오 전체를 악화시키는 경우(V89_010)를 후보 조합 비교로 차단한다.
(governance/todo/v8_9_p2_adoption_plan.yaml P2-B,
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:portfolio_transition_optimizer_v8_9.selection_algorithm)
applicable: PORTFOLIO_TRANSITION_UTILITY_V1이 candidate별 transition_utility_krw를 산출한 직후.
inputs:
- field: evaluated_candidates
unit: list_of_object
note: PORTFOLIO_TRANSITION_UTILITY_V1.candidate_actions 산출(hard_constraint_pass, transition_utility_krw 포함)
- field: max_set_size
unit: count
default: 3
note: 조합 폭발 방지. v8.9 turnover_budget(주간 5%) 고려 시 동시 실행 후보는 통상 1~3건.
selection_algorithm:
- step_1: hard_constraint_pass=false인 candidate는 set 구성에서 제외(개별 veto 우선)
- step_2: 남은 candidate에서 크기 1..max_set_size의 모든 조합(transition_set)을 생성
- step_3: 각 transition_set의 post_trade_cash_floor_pct, post_trade_concentration_pct, post_trade_MRC(marginal_risk_contribution), post_trade_CVaR95_krw를 합산 재평가
- step_3b: post_trade_CVaR95_krw = sum(candidate.cvar95_loss_krw for candidate in set) — SCENARIO_SHOCK_MATRIX_V1.crisis_case 기준 사용(가장 보수적)
- step_3c: post_trade_MRC = sum(candidate.marginal_risk_contribution for candidate in set) / portfolio_total_risk_budget
- step_4: set_hard_constraint_pass=false인 set은 제외 (개별 candidate는 PASS했어도 조합 시 cash_floor/concentration/MRC/CVaR cap을 넘을 수 있음)
- step_5: set_transition_utility_krw = sum(candidate.transition_utility_krw for candidate in set) - combination_penalty_krw
- step_6: set_transition_utility_krw가 최대인 set 선택. 동률이면 PORTFOLIO_TRANSITION_UTILITY_V1.deterministic_fallbacks.rank_tie 규칙 재사용
- step_7: 통과하는 set이 하나도 없으면 NO_TRADE (개별 candidate가 전부 PASS여도 조합 검증을 통과 못하면 거부)
combination_penalty_krw:
formula: complexity_penalty_rate * (len(transition_set) - 1)
note: 후보 수가 많을수록 실행 복잡도·동시 슬리피지 리스크 증가를 반영한 페널티.
output:
field: selected_transition_set
unit: list_of_candidate_id
additional_outputs:
- set_transition_utility_krw
- set_hard_constraint_pass
- rejected_sets_count
- post_trade_mrc
- post_trade_cvar95_krw
missing_policy: evaluated_candidates가 비어 있으면 selected_transition_set=[] + NO_TRADE. 빈 조합을 임의로 채우지 않는다. cvar95_loss_krw가 candidate에 없으면(SCENARIO_SHOCK_MATRIX_V1 미실행) post_trade_cvar95_krw=null이며 해당 set은 set_hard_constraint_pass 판정에서 CVaR 기준을 PARTIAL로 표기.
canonical_ref: spec/formulas/domains/portfolio.yaml:PORTFOLIO_TRANSITION_UTILITY_V1
implementation: tools/build_transition_set_enumerator_v1.py
owner: quant_team
lifecycle_state: shadow
input_fields:
- evaluated_candidates
- max_set_size
output_fields:
- selected_transition_set
- set_transition_utility_krw
- set_hard_constraint_pass
- post_trade_mrc
- post_trade_cvar95_krw
golden_cases:
- V89_010_candidate_good_portfolio_bad
- V89_048_solver_failure
- V89_049_rank_tie
activation_threshold:
min_t20_sample: 30
retirement_condition: performance_degradation
STATE_VECTOR_CONSTRUCTOR_V1:
purpose: >
holdings, cash, tax_lots, sector_graph, factor_exposures, macro_regime_probabilities를
단일 state_vector로 통합해 PORTFOLIO_TRANSITION_UTILITY_V1과 TRANSITION_SET_ENUMERATOR_V1이
동일한 포트폴리오 스냅샷을 참조하도록 한다. 부분 입력으로 state_vector를 임의 보완하지 않는다.
(governance/todo/v8_9_p3_adoption_plan.yaml P3-A,
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:implementation_todo_v8_9.P1_optimizer_and_simulation)
applicable: MODEL_GOVERNANCE_GATE에서 execution_mode 확정 직후, HARD_FILTER_CHECK 이전.
component_sources:
cash_ladder: spec/formulas/domains/cash.yaml:CASH_RATIOS_V1
positions: spec/15_account_snapshot_contract.yaml
sector_exposure_graph: spec/formulas/domains/sector.yaml:SECTOR_EXPOSURE_GRAPH_V1
factor_exposures: spec/risk/factor_risk.yaml
tax_lots: spec/15_account_snapshot_contract.yaml
risk_bucket_weights: spec/risk/portfolio_exposure.yaml
macro_regime_probabilities: spec/risk/market_risk_cash.yaml
goal_progress_pct: spec/13_formula_registry.yaml:formula_registry.formulas.GOAL_RETIREMENT_V1
inputs:
- field: cash_ladder
unit: json
- field: positions
unit: list_of_object
- field: sector_exposure_graph
unit: list_of_object
- field: factor_exposures
unit: list_of_object
- field: tax_lots
unit: list_of_object
- field: risk_bucket_weights
unit: object
- field: macro_regime_probabilities
unit: object
- field: goal_progress_pct
unit: percent
output:
field: state_vector
unit: object
additional_outputs:
- state_vector_completeness_pct
- missing_components
missing_policy: 결측 component는 state_vector에서 null로 유지하고 missing_components에 기록한다. 다른 component로 추정 보완 금지.
canonical_ref: spec/formulas/domains/portfolio.yaml:PORTFOLIO_TRANSITION_UTILITY_V1
implementation: tools/build_state_vector_constructor_v1.py
owner: quant_team
lifecycle_state: shadow
input_fields:
- cash_ladder
- positions
- sector_exposure_graph
- factor_exposures
- tax_lots
- risk_bucket_weights
- macro_regime_probabilities
- goal_progress_pct
output_fields:
- state_vector
- state_vector_completeness_pct
- missing_components
golden_cases:
- V89_052_goal_far_from_target
activation_threshold:
min_t20_sample: 30
retirement_condition: performance_degradation
REBALANCE_CADENCE_GATE_V1:
purpose: >
주간(토/일) 및 매월 1/11/21일 점검을 의무 실행하되, 실제 리밸런싱(매수/매도 실행)은
transition_utility_after_tax_cost가 양수이거나 hard_risk_block이 active일 때만 허용한다.
점검 자체는 항상 emit되어 "점검을 안 했다"는 누락을 방지하지만, 결과가 기준 미달이면 NO_TRADE.
(governance/todo/v8_9_p3_adoption_plan.yaml P3-D,
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:implementation_todo_v8_9.P3_sell_and_rebalance,
rebalancing_engine_v8_9.mandatory_schedule)
applicable: 매주 토/일 또는 매월 1/11/21일. PORTFOLIO_TRANSITION_REVIEW 진입 조건.
mandatory_schedule:
weekly_days: [SATURDAY, SUNDAY]
monthly_mid_check_days: [1, 11, 21]
event_driven_triggers: [cash_floor_break, crisis_score_red_or_black, hard_concentration_breach, data_quarantine_material]
inputs:
- field: today_date
unit: date
- field: transition_utility_after_tax_cost_krw
unit: number_or_null
source: spec/formulas/domains/portfolio.yaml:PORTFOLIO_TRANSITION_UTILITY_V1
- field: hard_risk_block_active
unit: boolean
source: spec/risk/aggregate_risk.yaml
cadence_check_rule: >
today_date가 weekly_days, monthly_mid_check_days, event_driven_triggers 중 하나라도 충족하면
cadence_check_required=true이며 점검 결과(review_emitted)는 항상 emit한다.
rebalance_execution_rule: >
cadence_check_required=true이고 (transition_utility_after_tax_cost_krw > 0 OR hard_risk_block_active=true)
일 때만 rebalance_execution_allowed=true. 그 외에는 review_emitted=true이지만 rebalance_execution_allowed=false
(점검은 했지만 NO_TRADE).
output:
field: rebalance_execution_allowed
unit: boolean
additional_outputs:
- cadence_check_required
- review_emitted
- cadence_trigger_reason
missing_policy: transition_utility_after_tax_cost_krw가 null이면 hard_risk_block_active만으로 판정. 둘 다 null이면 rebalance_execution_allowed=false + DATA_MISSING.
canonical_ref: spec/risk/aggregate_risk.yaml
implementation: tools/build_rebalance_cadence_gate_v1.py
owner: quant_team
lifecycle_state: shadow
input_fields:
- today_date
- transition_utility_after_tax_cost_krw
- hard_risk_block_active
output_fields:
- rebalance_execution_allowed
- cadence_check_required
- review_emitted
golden_cases:
- V89_032_no_trade_band
- V89_033_hard_block_overrides_band
- V89_053_weekly_rebalance_required
- V89_054_mid_check_required
activation_threshold:
min_t20_sample: 30
retirement_condition: performance_degradation