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:
@@ -537,6 +537,73 @@ formulas:
|
||||
activation_threshold:
|
||||
min_t20_sample: 30
|
||||
retirement_condition: performance_degradation
|
||||
SELL_LOT_PARETO_SELECTOR_V1:
|
||||
purpose: >
|
||||
SELL_WATERFALL_ENGINE_V1의 동일 hard_precedence 단계 안에서 후보 lot을 점수화하고,
|
||||
세금 회피 효과·반등 후 재진입 비용·놓친 상승분까지 포함한 다목적(Pareto) 비교로
|
||||
동순위 후보 중 어느 lot을 먼저 매도할지 결정론적으로 선택한다.
|
||||
(governance/todo/v8_9_p0_adoption_plan.yaml P0-2.1,
|
||||
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:sell_and_cash_repair_optimizer_v8_9)
|
||||
applicable: SELL_WATERFALL_ENGINE_V1의 동일 stage 내 후보가 2개 이상일 때.
|
||||
inputs:
|
||||
- field: avoided_tail_loss_krw
|
||||
unit: KRW
|
||||
- field: cash_repair_benefit_krw
|
||||
unit: KRW
|
||||
- field: concentration_reduction_benefit_krw
|
||||
unit: KRW
|
||||
- field: tax_loss_benefit_krw
|
||||
unit: KRW
|
||||
note: 손실 lot 매도 시 세금 절감 효과(tax-loss harvesting). 비과세 계좌는 0.
|
||||
- field: tax_fee_slippage_krw
|
||||
unit: KRW
|
||||
- field: reentry_cost_krw
|
||||
unit: KRW
|
||||
note: 매도 후 동일·유사 종목 재진입 시 예상 거래비용·스프레드 비용.
|
||||
- field: missed_upside_penalty_krw
|
||||
unit: KRW
|
||||
note: 매도하지 않았다면 얻었을 상승분 추정치. CE70_NET_PROFIT_KRW 분포가 있으면 그 값을 사용하고, 없으면 0(추정 금지).
|
||||
expression: >
|
||||
LOT_SELL_SCORE_KRW = avoided_tail_loss_krw + cash_repair_benefit_krw + concentration_reduction_benefit_krw
|
||||
+ tax_loss_benefit_krw - tax_fee_slippage_krw - reentry_cost_krw - missed_upside_penalty_krw
|
||||
output:
|
||||
field: lot_sell_score_krw
|
||||
unit: KRW
|
||||
pareto_dominance_rule:
|
||||
purpose: 동일 hard_precedence 단계 안에서 단일 점수만으로 비교하기 모호할 때 다목적 우위를 결정론적으로 판정.
|
||||
objectives_maximize: [avoided_tail_loss_krw, cash_repair_benefit_krw, concentration_reduction_benefit_krw, tax_loss_benefit_krw]
|
||||
objectives_minimize: [tax_fee_slippage_krw, reentry_cost_krw, missed_upside_penalty_krw]
|
||||
dominates_if: >
|
||||
candidate A가 모든 objectives_maximize 항목에서 B 이상이고 모든 objectives_minimize 항목에서 B 이하이며,
|
||||
적어도 한 항목에서 A가 B보다 우월하면 A dominates B.
|
||||
tie_breaker_if_no_dominance:
|
||||
- lot_sell_score_krw 높은 순
|
||||
- tax_fee_slippage_krw 낮은 순
|
||||
- reentry_cost_krw 낮은 순
|
||||
missing_policy:
|
||||
missed_upside_penalty_krw: CE70_NET_PROFIT_KRW 분포 없으면 0 사용(추정 아님 — 보수적 하한). 0 사용 사실을 output에 명시.
|
||||
tax_loss_benefit_krw: 계좌유형 미확인 시 0 (taxable 가정 금지, ISA/연금 비과세 가정도 금지 — DATA_MISSING 표기)
|
||||
canonical_ref: spec/risk/portfolio_exposure.yaml:sell_priority_engine.candidate_scoring
|
||||
implementation: tools/build_sell_waterfall_engine_v4.py
|
||||
owner: quant_team
|
||||
lifecycle_state: shadow
|
||||
input_fields:
|
||||
- avoided_tail_loss_krw
|
||||
- cash_repair_benefit_krw
|
||||
- concentration_reduction_benefit_krw
|
||||
- tax_loss_benefit_krw
|
||||
- tax_fee_slippage_krw
|
||||
- reentry_cost_krw
|
||||
- missed_upside_penalty_krw
|
||||
output_fields:
|
||||
- lot_sell_score_krw
|
||||
golden_cases:
|
||||
- V89_029_deconcentration_trim
|
||||
- V89_030_profit_lock
|
||||
- V89_031_tax_drag_too_high
|
||||
activation_threshold:
|
||||
min_t20_sample: 30
|
||||
retirement_condition: performance_degradation
|
||||
SMART_MONEY_LIQUIDITY_GATE_V1:
|
||||
purpose: '스마트머니·유동성 차단 게이트. SM001(외국인+기관 동시 순매도→BLOCK_BUY), SM002(5일 평균 거래대금 <
|
||||
50억→LIMIT_QUANTITY), SM003(RSI14>70 AND flow_credit<0.3→BLOCK_BUY) 결정론 구현. FINAL_JUDGMENT_GATE_V1의
|
||||
@@ -946,3 +1013,50 @@ formulas:
|
||||
activation_threshold:
|
||||
min_t20_sample: 30
|
||||
retirement_condition: performance_degradation
|
||||
WEEKLY_LEGACY_TRANSFER_PLAN_V1:
|
||||
purpose: >
|
||||
주간 레거시종목→CMA 이전 계획(weekly_legacy_to_cma_transfer_plan_krw)을 입금이 실제로
|
||||
확인되기 전까지는 deployable_cash_krw에 합산하지 않는다. 계획 단계(planned)와
|
||||
확정 단계(confirmed)를 분리해 "이전될 돈을 이미 쓸 수 있는 돈"으로 취급하는 오류를 막는다.
|
||||
(governance/todo/v8_9_p3_adoption_plan.yaml P3-E,
|
||||
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:implementation_todo_v8_9.P3_sell_and_rebalance,
|
||||
portfolio_policy_v8_9.operator_cashflow_config)
|
||||
applicable: CASH_RATIOS_V1·DEPLOYABLE_CASH_KRW_V1 계산 직전. weekly_legacy_to_cma_transfer_plan_krw가 0보다 클 때.
|
||||
inputs:
|
||||
- field: weekly_legacy_to_cma_transfer_plan_krw
|
||||
unit: KRW
|
||||
default: 4000000
|
||||
note: spec/risk/portfolio_exposure.yaml의 operator_cashflow_config 고정 계획값(월별 갱신).
|
||||
- field: transfer_confirmed
|
||||
unit: boolean
|
||||
note: 실제 계좌 입금 확인 여부. 계획만으로는 false.
|
||||
- field: transfer_confirmed_amount_krw
|
||||
unit: KRW_or_null
|
||||
note: 확인된 입금액. transfer_confirmed=false면 null.
|
||||
rule: >
|
||||
transfer_confirmed=false인 동안 weekly_legacy_to_cma_transfer_plan_krw는 deployable_cash_krw
|
||||
계산에 포함되지 않는다(plan_status=PLANNED_NOT_DEPLOYABLE). transfer_confirmed=true가 되면
|
||||
transfer_confirmed_amount_krw만 deployable_cash_krw에 합산한다(plan_status=CONFIRMED_DEPLOYABLE).
|
||||
계획액과 확정액이 다르면 확정액을 우선한다(계획액으로 추정 보완 금지).
|
||||
output:
|
||||
field: deployable_cash_contribution_krw
|
||||
unit: KRW
|
||||
additional_outputs:
|
||||
- plan_status
|
||||
missing_policy: transfer_confirmed가 null이면 false로 간주(보수적 — 입금 미확인 상태와 동일 처리).
|
||||
canonical_ref: spec/risk/portfolio_exposure.yaml:cash_floor
|
||||
implementation: tools/build_weekly_legacy_transfer_plan_v1.py
|
||||
owner: quant_team
|
||||
lifecycle_state: shadow
|
||||
input_fields:
|
||||
- weekly_legacy_to_cma_transfer_plan_krw
|
||||
- transfer_confirmed
|
||||
- transfer_confirmed_amount_krw
|
||||
output_fields:
|
||||
- deployable_cash_contribution_krw
|
||||
- plan_status
|
||||
golden_cases:
|
||||
- V89_005_deployable_cash_negative
|
||||
activation_threshold:
|
||||
min_t20_sample: 30
|
||||
retirement_condition: performance_degradation
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
schema_version: formula_domain.v1
|
||||
source: C:\Temp\data_feed\spec\13_formula_registry.yaml
|
||||
domain: execution
|
||||
meta:
|
||||
note: >
|
||||
governance/todo/v8_9_p1_adoption_plan.yaml P1-B.
|
||||
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:execution_plan_compiler_v8_9
|
||||
formulas:
|
||||
EXECUTION_CAPACITY_LADDER_V1:
|
||||
purpose: >
|
||||
계획된 주문금액이 종목의 실제 체결 가능 용량(20일 평균거래대금, 당일 거래대금, 호가창 깊이)을
|
||||
초과하지 않도록 결정론적으로 캡핑한다. broker_microstructure_packet이 없으면 주문 계획 자체를
|
||||
차단한다(v8.9 V89_019).
|
||||
(governance/todo/v8_9_p1_adoption_plan.yaml P1-B.1,
|
||||
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:execution_plan_compiler_v8_9.broker_microstructure_packet_required)
|
||||
applicable: PORTFOLIO_TRANSITION_UTILITY_V1에서 selected_transition 확정 후, 주문 분할(split_order_template) 직전.
|
||||
inputs:
|
||||
- field: planned_order_amount_krw
|
||||
unit: KRW
|
||||
- field: avg_trade_value_20d_krw
|
||||
unit: KRW
|
||||
source: 기존 avg_trade_value_5d(spec/12_field_dictionary.yaml)의 20일 윈도우 변형
|
||||
- field: intraday_trade_value_krw
|
||||
unit: KRW
|
||||
- field: orderbook_top3_depth_krw
|
||||
unit: KRW
|
||||
- field: spread_bps
|
||||
unit: basis_points
|
||||
- field: tick_size
|
||||
unit: KRW_per_share
|
||||
source: spec/formulas/domains/cash.yaml:tick_size_table
|
||||
- field: daily_price_limit
|
||||
unit: percent
|
||||
- field: halt_status
|
||||
unit: boolean
|
||||
expression: >
|
||||
order_capacity_krw = min(planned_order_amount_krw, avg_trade_value_20d_krw * 0.003,
|
||||
intraday_trade_value_krw * 0.01, orderbook_top3_depth_krw * 0.30)
|
||||
output:
|
||||
field: order_capacity_krw
|
||||
unit: KRW
|
||||
gates:
|
||||
- if: halt_status == true
|
||||
action: EXECUTION_PLAN_BLOCKED
|
||||
reason_code: trading_halt
|
||||
- if: avg_trade_value_20d_krw is null OR orderbook_top3_depth_krw is null OR spread_bps is null
|
||||
action: EXECUTION_PLAN_BLOCKED
|
||||
reason_code: broker_packet_missing
|
||||
- if: order_capacity_krw < planned_order_amount_krw
|
||||
action: ORDER_SIZE_CAPPED
|
||||
reason_code: capacity_too_low
|
||||
spread_widen_cancel_rule:
|
||||
condition: spread_bps > spread_bps_baseline * 1.5 (slice 체결 사이 측정)
|
||||
action: CANCEL_REMAINING_SLICES
|
||||
canonical_ref: suggest/quant_investment_engine_v8_9...:execution_plan_compiler_v8_9.cancel_remaining_if
|
||||
split_order_template:
|
||||
slice_1_pct: 30
|
||||
slice_2_pct: 30
|
||||
slice_3_pct: 40
|
||||
requires_revalidation_before_each_slice: true
|
||||
revalidation_fields: [cash_floor, deployable_cash, order_capacity_krw, spread_bps]
|
||||
missing_policy: broker_microstructure_packet 필드 중 하나라도 null이면 EXECUTION_PLAN_BLOCKED. 추정 금지.
|
||||
canonical_ref: spec/05_position_sizing.yaml
|
||||
implementation: tools/build_execution_capacity_ladder_v1.py
|
||||
owner: quant_team
|
||||
lifecycle_state: shadow
|
||||
input_fields:
|
||||
- planned_order_amount_krw
|
||||
- avg_trade_value_20d_krw
|
||||
- intraday_trade_value_krw
|
||||
- orderbook_top3_depth_krw
|
||||
- spread_bps
|
||||
- tick_size
|
||||
- daily_price_limit
|
||||
- halt_status
|
||||
output_fields:
|
||||
- order_capacity_krw
|
||||
golden_cases:
|
||||
- V89_019_broker_packet_missing
|
||||
- V89_020_capacity_too_low
|
||||
- V89_022_spread_widens
|
||||
activation_threshold:
|
||||
min_t20_sample: 30
|
||||
retirement_condition: performance_degradation
|
||||
EXECUTION_PLAN_COMPILER_V1:
|
||||
purpose: >
|
||||
EXECUTION_CAPACITY_LADDER_V1이 산출한 order_capacity_krw를 30/30/40 LIMIT_SPLIT 슬라이스로
|
||||
컴파일하고, 각 슬라이스 실행 직전 cash_floor·capacity·spread를 재검증한다.
|
||||
재검증 실패 또는 cancel_remaining_if 조건 충족 시 잔여 슬라이스를 취소한다.
|
||||
(governance/todo/v8_9_p2_adoption_plan.yaml P2-D,
|
||||
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:execution_plan_compiler_v8_9.split_order_template,
|
||||
execution_plan_compiler_v8_9.cancel_remaining_if)
|
||||
applicable: EXECUTION_CAPACITY_LADDER_V1.gate가 PASS 또는 ORDER_SIZE_CAPPED일 때만 호출.
|
||||
inputs:
|
||||
- field: order_capacity_krw
|
||||
unit: KRW
|
||||
source: spec/formulas/domains/execution.yaml:EXECUTION_CAPACITY_LADDER_V1
|
||||
- field: slice_index
|
||||
unit: 'enum: 1 | 2 | 3'
|
||||
- field: revalidation_snapshot
|
||||
unit: json
|
||||
note: 'slice 직전 시점의 {cash_floor_pct, deployable_cash_krw, order_capacity_krw, spread_bps}'
|
||||
- field: baseline_snapshot
|
||||
unit: json
|
||||
note: 컴파일 시점(slice 1 이전)의 동일 필드 스냅샷. spread_widen_cancel_rule 기준값.
|
||||
cancel_remaining_if:
|
||||
- captain_reverses_intraday
|
||||
- index_drop_exceeds_threshold
|
||||
- spread_widens_beyond_limit: "revalidation_snapshot.spread_bps > baseline_snapshot.spread_bps * 1.5"
|
||||
- cash_floor_after_fill_breached: "revalidation_snapshot.cash_floor_pct < required_cash_pct"
|
||||
- data_quarantine_after_slice
|
||||
- orderbook_capacity_collapses: "revalidation_snapshot.order_capacity_krw < baseline_snapshot.order_capacity_krw * 0.5"
|
||||
expression: >
|
||||
slice_amount_krw(1) = order_capacity_krw * 0.30
|
||||
slice_amount_krw(2) = order_capacity_krw * 0.30
|
||||
slice_amount_krw(3) = order_capacity_krw * 0.40
|
||||
각 슬라이스는 직전 슬라이스 체결 후 revalidation_snapshot을 재계산하고 cancel_remaining_if를
|
||||
평가한 뒤에만 진행한다. 어느 한 조건이라도 true이면 이후 슬라이스는 컴파일하지 않는다.
|
||||
output:
|
||||
field: compiled_slices
|
||||
unit: 'list_of_{slice_index, slice_amount_krw, status}'
|
||||
additional_outputs:
|
||||
- cancel_reason_code
|
||||
- slices_executed_count
|
||||
missing_policy: order_capacity_krw 또는 baseline_snapshot 결측 시 컴파일 자체를 EXECUTION_PLAN_BLOCKED.
|
||||
canonical_ref: spec/formulas/domains/execution.yaml:EXECUTION_CAPACITY_LADDER_V1
|
||||
implementation: tools/build_execution_plan_compiler_v1.py
|
||||
owner: quant_team
|
||||
lifecycle_state: shadow
|
||||
input_fields:
|
||||
- order_capacity_krw
|
||||
- slice_index
|
||||
- revalidation_snapshot
|
||||
- baseline_snapshot
|
||||
output_fields:
|
||||
- compiled_slices
|
||||
- cancel_reason_code
|
||||
golden_cases:
|
||||
- V89_021_partial_fill
|
||||
- V89_022_spread_widens
|
||||
- V89_023_gap_up_chase
|
||||
activation_threshold:
|
||||
min_t20_sample: 30
|
||||
retirement_condition: performance_degradation
|
||||
@@ -0,0 +1,163 @@
|
||||
schema_version: formula_domain.v1
|
||||
source: C:\Temp\data_feed\spec\13_formula_registry.yaml
|
||||
domain: governance
|
||||
meta:
|
||||
note: >
|
||||
governance/todo/v8_9_p1_adoption_plan.yaml P1-C.
|
||||
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:model_governance_v8_9
|
||||
이 도메인은 종목/팩터 수준 promotion(spec/57_shadow_promotion_scorecard.yaml)과는 별개로
|
||||
전략 execution_mode 단계(AUDIT_ONLY→SHADOW→PILOT→LIVE_LIMITED→LIVE_FULL) 전체를 다룬다.
|
||||
formulas:
|
||||
MODEL_GOVERNANCE_KILL_SWITCH_V1:
|
||||
purpose: >
|
||||
data_quarantine_rate, implementation_shortfall, T5_hit_rate, calibration_error,
|
||||
drawdown 5개 지표를 감시해 기준 이탈 시 execution_mode를 자동으로 한 단계 강등한다.
|
||||
LLM이나 운영자가 "이번엔 괜찮을 것"이라는 서사로 강등을 보류하는 것을 금지한다.
|
||||
(governance/todo/v8_9_p1_adoption_plan.yaml P1-C.1,
|
||||
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:risk_controls_v8_9.kill_switches,
|
||||
model_governance_v8_9.automatic_demotion)
|
||||
applicable: 매 의사결정 사이클 시작 전. PORTFOLIO_TRANSITION_UTILITY_V1보다 먼저 평가되어 execution_mode를 확정한다.
|
||||
promotion_ladder: [AUDIT_ONLY, SHADOW, PILOT, LIVE_LIMITED, LIVE_FULL]
|
||||
inputs:
|
||||
- field: data_quarantine_rate_pct
|
||||
unit: percent
|
||||
source: tools/build_yaml_code_coverage_v1.py 계열 — 결측/충돌로 quarantine된 입력 비율
|
||||
- field: implementation_shortfall_ratio
|
||||
unit: ratio
|
||||
note: 실제 슬리피지 / 기대 슬리피지. 2.0 초과 시 위반.
|
||||
- field: t5_hit_rate_pct
|
||||
source: spec/29_backtest_harness_contract.yaml:current_metrics.direction_accuracy.t5_op_rate
|
||||
unit: percent
|
||||
- field: t5_sample_count
|
||||
source: spec/29_backtest_harness_contract.yaml:current_metrics.direction_accuracy.t5_op_rate.n_sample
|
||||
unit: count
|
||||
- field: calibration_error
|
||||
source: spec/calibration_registry.yaml
|
||||
unit: ratio
|
||||
- field: calibration_error_limit
|
||||
unit: ratio
|
||||
- field: account_mdd_pct
|
||||
unit: percent
|
||||
- field: account_mdd_budget_pct
|
||||
source: spec/risk/aggregate_risk.yaml
|
||||
unit: percent
|
||||
kill_switch_conditions:
|
||||
- id: data_quarantine_rate_above_5pct
|
||||
condition: data_quarantine_rate_pct > 5.0
|
||||
- id: implementation_shortfall_above_2x_expected
|
||||
condition: implementation_shortfall_ratio > 2.0
|
||||
- id: t5_hit_rate_below_50pct_for_30_trades
|
||||
condition: t5_sample_count >= 30 AND t5_hit_rate_pct < 50.0
|
||||
- id: calibration_error_above_limit
|
||||
condition: calibration_error > calibration_error_limit
|
||||
- id: unexpected_drawdown_breach
|
||||
condition: account_mdd_pct > account_mdd_budget_pct
|
||||
demotion_rule: >
|
||||
kill_switch_conditions 중 하나라도 true이면 execution_mode를 promotion_ladder에서
|
||||
현재 단계 -1 (한 단계만 강등). AUDIT_ONLY는 더 이상 강등되지 않는다(최저 단계).
|
||||
여러 조건이 동시에 발동해도 1단계만 강등(과잉반응 방지) — 단, 재평가 사이클마다 조건이
|
||||
계속 true이면 추가로 1단계씩 강등된다.
|
||||
promotion_rule: >
|
||||
kill_switch_conditions 전부 false이고 spec/57_shadow_promotion_scorecard.yaml의
|
||||
promotion_gate_criteria(해당 단계 전환 기준)를 만족할 때만 한 단계 승급. 자동 승급 없음 —
|
||||
승급은 operator_override 기록을 동반해야 한다(v8.9 V89_039).
|
||||
output:
|
||||
field: execution_mode
|
||||
unit: enum
|
||||
additional_outputs:
|
||||
- kill_switch_triggered
|
||||
- kill_switch_reason_codes
|
||||
- execution_mode_changed
|
||||
missing_policy: 입력 지표 중 하나라도 null이면 해당 kill switch는 평가 불가로 PARTIAL 표기하고, 평가 가능한 지표만으로 판정한다. 모든 지표 null이면 execution_mode 변경 없이 DATA_MISSING.
|
||||
canonical_ref: spec/57_shadow_promotion_scorecard.yaml
|
||||
implementation: tools/build_model_governance_kill_switch_v1.py
|
||||
owner: quant_team
|
||||
lifecycle_state: shadow
|
||||
input_fields:
|
||||
- data_quarantine_rate_pct
|
||||
- implementation_shortfall_ratio
|
||||
- t5_hit_rate_pct
|
||||
- t5_sample_count
|
||||
- calibration_error
|
||||
- calibration_error_limit
|
||||
- account_mdd_pct
|
||||
- account_mdd_budget_pct
|
||||
output_fields:
|
||||
- execution_mode
|
||||
- kill_switch_triggered
|
||||
- kill_switch_reason_codes
|
||||
golden_cases:
|
||||
- V89_035_model_kill_switch_hit_rate
|
||||
- V89_036_model_kill_switch_slippage
|
||||
- V89_037_data_quarantine_rate
|
||||
activation_threshold:
|
||||
min_t20_sample: 30
|
||||
retirement_condition: performance_degradation
|
||||
IMMUTABLE_DECISION_LEDGER_V1:
|
||||
purpose: >
|
||||
모든 의사결정을 append-only로 기록해 사후 재구성과 T1/T5/T20 성과 귀속을 가능하게 한다.
|
||||
기존 레코드 수정·삭제를 금지하며, 동일 decision_id 재기록 시도는 거부한다.
|
||||
(governance/todo/v8_9_p2_adoption_plan.yaml P2-C,
|
||||
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:model_governance_v8_9.immutable_decision_log_required_fields)
|
||||
applicable: PORTFOLIO_TRANSITION_UTILITY_V1 또는 TRANSITION_SET_ENUMERATOR_V1이 selected_transition을 확정한 직후.
|
||||
required_fields:
|
||||
- decision_id
|
||||
- timestamp
|
||||
- engine_version
|
||||
- input_hash_bundle
|
||||
- execution_mode
|
||||
- candidate_ids
|
||||
- selected_transition_id
|
||||
- hard_blocks
|
||||
- transition_utility_krw
|
||||
- operator_override
|
||||
- order_ids
|
||||
- fill_prices
|
||||
- slippage
|
||||
- T1_return
|
||||
- T5_return
|
||||
- T20_return
|
||||
- MAE
|
||||
- MFE
|
||||
append_only_rule: >
|
||||
decision_id가 이미 ledger에 존재하면 신규 append를 거부하고 DUPLICATE_DECISION_ID 오류를 반환한다.
|
||||
기존 레코드의 필드 값을 변경하는 호출은 없다 — T1/T5/T20/MAE/MFE는 별도의 update_outcome
|
||||
append(새 레코드, 동일 decision_id 참조)로만 추가하고 원본 decision 레코드는 불변으로 둔다.
|
||||
inputs:
|
||||
- field: decision_id
|
||||
unit: string
|
||||
- field: engine_version
|
||||
unit: string
|
||||
- field: input_hash_bundle
|
||||
unit: string
|
||||
- field: execution_mode
|
||||
unit: enum
|
||||
- field: candidate_ids
|
||||
unit: list_of_string
|
||||
- field: selected_transition_id
|
||||
unit: string_or_null
|
||||
- field: transition_utility_krw
|
||||
unit: number_or_null
|
||||
output:
|
||||
field: ledger_append_status
|
||||
unit: 'enum: APPENDED | DUPLICATE_DECISION_ID | REJECTED_MISSING_FIELDS'
|
||||
missing_policy: required_fields 중 하나라도 없으면 REJECTED_MISSING_FIELDS — 빈 문자열/0으로 채워 append 금지.
|
||||
canonical_ref: spec/formulas/domains/portfolio.yaml:PORTFOLIO_TRANSITION_UTILITY_V1
|
||||
implementation: tools/build_immutable_decision_ledger_v1.py
|
||||
owner: quant_team
|
||||
lifecycle_state: shadow
|
||||
input_fields:
|
||||
- decision_id
|
||||
- engine_version
|
||||
- input_hash_bundle
|
||||
- execution_mode
|
||||
- candidate_ids
|
||||
- selected_transition_id
|
||||
- transition_utility_krw
|
||||
output_fields:
|
||||
- ledger_append_status
|
||||
golden_cases:
|
||||
- V89_039_operator_override
|
||||
activation_threshold:
|
||||
min_t20_sample: 30
|
||||
retirement_condition: performance_degradation
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
schema_version: formula_domain.v1
|
||||
source: C:\Temp\data_feed\spec\13_formula_registry.yaml
|
||||
domain: sector
|
||||
meta:
|
||||
note: >
|
||||
governance/todo/v8_9_p1_adoption_plan.yaml P1-A.
|
||||
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:sector_graph_engine_v8_9
|
||||
formulas:
|
||||
SECTOR_EXPOSURE_GRAPH_V1:
|
||||
purpose: >
|
||||
섹터를 단일 텍스트 라벨이 아니라 L1:L2:L3:L4 canonical ID로 분류하고, ETF 구성종목을
|
||||
lookthrough하여 직접보유와 합산한 실질노출을 계산하며, AI/반도체/전력 등 테마 간
|
||||
중복 베타를 residualize해 과집중 진단의 이중계산을 막는다.
|
||||
(governance/todo/v8_9_p1_adoption_plan.yaml P1-A.1,
|
||||
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:sector_graph_engine_v8_9)
|
||||
canonical_sector_id_format: 'L1:L2:L3:L4, 예: EQ:TECH:SEMIS:HBM'
|
||||
applicable: portfolio_exposure.concentration_caps_v8_9_supplement, PORTFOLIO_TRANSITION_UTILITY_V1.concentration_reduction_benefit_krw 계산 직전.
|
||||
inputs:
|
||||
- field: direct_weight_pct
|
||||
unit: percent
|
||||
note: 종목 직접보유 비중
|
||||
- field: etf_constituents_json
|
||||
unit: json
|
||||
note: 'ETF 구성종목 리스트 [{ticker, weight_pct}]. ETF_quality_gate(NAV_asof_valid, constituents_asof_valid) 통과 필요.'
|
||||
- field: etf_weight_pct
|
||||
unit: percent
|
||||
note: 해당 ETF의 포트폴리오 내 비중
|
||||
- field: sector_id
|
||||
unit: string
|
||||
note: canonical_sector_id_format 준수
|
||||
- field: peer_sector_betas
|
||||
unit: list_of_ratio
|
||||
note: 동일 macro_driver(AI_capex, semiconductor 등)를 공유하는 다른 섹터의 베타 목록
|
||||
expression:
|
||||
lookthrough_etf_weight_pct: "sum(constituent.weight_pct * etf_weight_pct / 100 for constituent in etf_constituents_json if constituent.sector_id == sector_id)"
|
||||
sector_family_total_pct: "direct_weight_pct + lookthrough_etf_weight_pct"
|
||||
factor_beta_residualized: "factor_beta_raw - sum(shared_variance_with(peer) for peer in peer_sector_betas if peer.macro_driver == self.macro_driver)"
|
||||
output:
|
||||
field: sector_family_total_pct
|
||||
unit: percent
|
||||
additional_outputs:
|
||||
- lookthrough_etf_weight_pct
|
||||
- factor_beta_residualized
|
||||
- theme_overlap_pct
|
||||
gates:
|
||||
- if: sector_family_total_pct > concentration_caps_v8_9_supplement.top3_combined_cap_pct.hard_cap_pct
|
||||
action: HARD_CONCENTRATION_BLOCK
|
||||
missing_policy:
|
||||
etf_constituents_json: ETF_BUY_BLOCKED — constituents_missing (v8.9 V89_016). lookthrough를 0으로 추정 금지.
|
||||
peer_sector_betas: factor_beta_residualized를 raw 값 그대로 사용하고 PARTIAL 표기. 0으로 추정 금지.
|
||||
canonical_ref: spec/risk/portfolio_exposure.yaml:duplicate_exposure_rule
|
||||
implementation: tools/build_sector_exposure_graph_v1.py
|
||||
owner: quant_team
|
||||
lifecycle_state: shadow
|
||||
input_fields:
|
||||
- direct_weight_pct
|
||||
- etf_constituents_json
|
||||
- etf_weight_pct
|
||||
- sector_id
|
||||
- peer_sector_betas
|
||||
output_fields:
|
||||
- sector_family_total_pct
|
||||
- lookthrough_etf_weight_pct
|
||||
- factor_beta_residualized
|
||||
golden_cases:
|
||||
- V89_044_sector_overlap
|
||||
- V89_045_ETF_direct_overlap
|
||||
activation_threshold:
|
||||
min_t20_sample: 30
|
||||
retirement_condition: performance_degradation
|
||||
LEADER_LIFECYCLE_GATE_V1:
|
||||
purpose: >
|
||||
종목의 시장 주도력을 CAPTAIN/CORE_LEADER/ENABLER/CYCLICAL_BETA/LAGGARD/DISTRIBUTION_RISK
|
||||
6개 role로 분류하고, 승급·강등 조건을 결정론적으로 평가한다. LLM이 '주도주라서 산다'는
|
||||
서사로 role을 임의 부여하는 것을 금지한다.
|
||||
(governance/todo/v8_9_p1_adoption_plan.yaml P1-A.2,
|
||||
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:sector_graph_engine_v8_9.leader_lifecycle)
|
||||
applicable: SECTOR_EXPOSURE_GRAPH_V1 산출 직후. PORTFOLIO_TRANSITION_UTILITY_V1 candidate_action 생성 전.
|
||||
roles: [CAPTAIN, CORE_LEADER, ENABLER, CYCLICAL_BETA, LAGGARD, DISTRIBUTION_RISK]
|
||||
inputs:
|
||||
- field: relative_strength_leads_sector
|
||||
unit: boolean
|
||||
- field: volume_quality_confirmed
|
||||
unit: boolean
|
||||
- field: above_ma60_or_reclaim_confirmed
|
||||
unit: boolean
|
||||
- field: earnings_revision_status
|
||||
unit: 'enum: positive | neutral | negative'
|
||||
- field: institutional_flow_status
|
||||
unit: 'enum: accumulation | neutral | distribution'
|
||||
- field: current_role
|
||||
unit: enum
|
||||
note: 직전 평가에서 결정된 role. 최초 평가 시 LAGGARD로 시작.
|
||||
promotion_requires_all:
|
||||
- relative_strength_leads_sector == true
|
||||
- volume_quality_confirmed == true
|
||||
- above_ma60_or_reclaim_confirmed == true
|
||||
- earnings_revision_status != negative
|
||||
- institutional_flow_status != distribution
|
||||
demotion_triggers_any:
|
||||
- break_ma60_with_distribution: "above_ma60_or_reclaim_confirmed == false AND institutional_flow_status == distribution"
|
||||
- underperform_sector_20d: relative_strength_leads_sector == false (20거래일 연속)
|
||||
- earnings_revision_negative: earnings_revision_status == negative
|
||||
- crowded_flow_reversal: institutional_flow_status == distribution AND current_role IN [CAPTAIN, CORE_LEADER]
|
||||
role_transition_table:
|
||||
promotion_path: [LAGGARD, CYCLICAL_BETA, ENABLER, CORE_LEADER, CAPTAIN]
|
||||
demotion_path: [CAPTAIN, CORE_LEADER, ENABLER, CYCLICAL_BETA, LAGGARD, DISTRIBUTION_RISK]
|
||||
rule: 승급은 promotion_requires_all 충족 시 promotion_path 다음 단계로 1단계만 이동. 강등은 demotion_triggers_any 발동 시 즉시 DISTRIBUTION_RISK로 직행(단계적 강등 아님 — 보수적 원칙).
|
||||
output:
|
||||
field: leader_role
|
||||
unit: enum
|
||||
additional_outputs:
|
||||
- role_transition_reason
|
||||
- role_changed
|
||||
gates:
|
||||
- if: leader_role == DISTRIBUTION_RISK
|
||||
action: NEW_BUY_BLOCKED
|
||||
missing_policy: 입력 필드 중 하나라도 null이면 role 유지(current_role) + role_transition_reason=DATA_MISSING. 임의 승급/강등 금지.
|
||||
canonical_ref: spec/strategy/leader_scan.yaml
|
||||
implementation: tools/build_sector_exposure_graph_v1.py
|
||||
owner: quant_team
|
||||
lifecycle_state: shadow
|
||||
input_fields:
|
||||
- relative_strength_leads_sector
|
||||
- volume_quality_confirmed
|
||||
- above_ma60_or_reclaim_confirmed
|
||||
- earnings_revision_status
|
||||
- institutional_flow_status
|
||||
- current_role
|
||||
output_fields:
|
||||
- leader_role
|
||||
- role_transition_reason
|
||||
golden_cases:
|
||||
- V89_046_leader_distribution
|
||||
activation_threshold:
|
||||
min_t20_sample: 30
|
||||
retirement_condition: performance_degradation
|
||||
@@ -0,0 +1,205 @@
|
||||
schema_version: formula_domain.v1
|
||||
source: C:\Temp\data_feed\spec\13_formula_registry.yaml
|
||||
domain: simulation
|
||||
meta:
|
||||
note: >
|
||||
governance/todo/v8_9_p0_adoption_plan.yaml P0-3.1.
|
||||
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:forecast_and_simulation_engine_v8_9
|
||||
배경: spec/29_backtest_harness_contract.yaml가 이미 "T+20 실현 표본 0건, walk_forward=insufficient_data"를
|
||||
명시한다(AGENTS.md §6b). 이 도메인 파일은 분포를 날조하지 않고, 표본이 minimum_sample_rules를 충족할 때만
|
||||
실제 bootstrap 계산 경로를 열고 미달이면 DATA_MISSING/WATCH_ONLY를 결정론적으로 반환하는 계약이다.
|
||||
formulas:
|
||||
FORECAST_SIMULATION_ENGINE_V1:
|
||||
purpose: >
|
||||
개별 종목의 점 추정 기대수익률이 아니라 레짐별 손익분포에서 CE70(30%분위)·CE90(10%분위)·
|
||||
CVaR95(95% 신뢰구간 꼬리손실 평균)를 산출한다. 표본 부족 시 가짜 분포를 만들지 않고
|
||||
WATCH_ONLY 또는 DATA_MISSING으로 정직하게 반환한다.
|
||||
applicable: PORTFOLIO_TRANSITION_UTILITY_V1의 ce70_net_profit_krw 입력 직전.
|
||||
inputs:
|
||||
- field: net_profit_distribution_after_tax_fee_slippage
|
||||
source: spec/29_backtest_harness_contract.yaml:current_metrics
|
||||
unit: list_of_KRW
|
||||
note: 세후·비용 차감 손익 표본. 현재 t20_op_rate.n_sample=0 (insufficient_data).
|
||||
- field: sample_count_total
|
||||
unit: count
|
||||
- field: sample_count_same_regime
|
||||
unit: count
|
||||
- field: execution_mode
|
||||
unit: enum
|
||||
note: AUDIT_ONLY | SHADOW | PILOT | LIVE_LIMITED | LIVE_FULL
|
||||
minimum_sample_rules:
|
||||
AUDIT_ONLY:
|
||||
sample_count_total_min: 0
|
||||
sample_count_same_regime_min: 0
|
||||
note: no minimum; report missing samples only (documentation only, no live order)
|
||||
SHADOW:
|
||||
sample_count_total_min: 30
|
||||
sample_count_same_regime_min: 10
|
||||
PILOT:
|
||||
sample_count_total_min: 80
|
||||
sample_count_same_regime_min: 20
|
||||
LIVE_LIMITED:
|
||||
sample_count_total_min: 150
|
||||
sample_count_same_regime_min: 30
|
||||
LIVE_FULL:
|
||||
sample_count_total_min: 300
|
||||
sample_count_same_regime_min: 50
|
||||
agents_md_cross_check: "AGENTS.md §6b: Live T+20 표본 30건 미만이면 active/PASS_100 승격 금지"
|
||||
gate_logic:
|
||||
- if: sample_count_total < minimum_sample_rules[execution_mode].sample_count_total_min
|
||||
action: WATCH_ONLY
|
||||
output: "ce70_net_profit_krw=null, ce90_net_profit_krw=null, cvar95_loss_krw=null"
|
||||
- if: sample_count_same_regime < minimum_sample_rules[execution_mode].sample_count_same_regime_min
|
||||
action: WATCH_ONLY
|
||||
output: "ce70_net_profit_krw=null, ce90_net_profit_krw=null, cvar95_loss_krw=null"
|
||||
- if: sample_count_total >= minimum AND sample_count_same_regime >= minimum
|
||||
action: COMPUTE
|
||||
expression:
|
||||
ce70_net_profit_krw: quantile(net_profit_distribution_after_tax_fee_slippage, 0.30)
|
||||
ce90_net_profit_krw: quantile(net_profit_distribution_after_tax_fee_slippage, 0.10)
|
||||
cvar95_loss_krw: mean(losses beyond 95th percentile loss threshold in net_profit_distribution_after_tax_fee_slippage)
|
||||
estimator_allowlist:
|
||||
- walk_forward_bootstrap
|
||||
- regime_matched_bootstrap
|
||||
forbidden_estimators:
|
||||
- LLM_guess_return
|
||||
- single_point_target_price_without_distribution
|
||||
- backtest_without_cost_or_leakage_test
|
||||
output:
|
||||
field: ce70_net_profit_krw
|
||||
unit: KRW_or_null
|
||||
additional_outputs:
|
||||
- ce90_net_profit_krw
|
||||
- cvar95_loss_krw
|
||||
- sample_count_total
|
||||
- sample_count_same_regime
|
||||
- gate
|
||||
missing_policy:
|
||||
net_profit_distribution_after_tax_fee_slippage: 표본 없으면 모든 출력 null + gate=WATCH_ONLY. 0으로 대체 금지.
|
||||
canonical_ref: spec/29_backtest_harness_contract.yaml:current_metrics.walk_forward
|
||||
implementation: tools/build_forecast_simulation_engine_v1.py
|
||||
owner: quant_team
|
||||
lifecycle_state: shadow
|
||||
input_fields:
|
||||
- net_profit_distribution_after_tax_fee_slippage
|
||||
- sample_count_total
|
||||
- sample_count_same_regime
|
||||
- execution_mode
|
||||
output_fields:
|
||||
- ce70_net_profit_krw
|
||||
- ce90_net_profit_krw
|
||||
- cvar95_loss_krw
|
||||
- sample_count_total
|
||||
- sample_count_same_regime
|
||||
- gate
|
||||
golden_cases:
|
||||
- V89_013_missing_CVaR
|
||||
- V89_014_same_regime_sample_low
|
||||
activation_threshold:
|
||||
min_t20_sample: 30
|
||||
retirement_condition: performance_degradation
|
||||
SCENARIO_SHOCK_MATRIX_V1:
|
||||
purpose: >
|
||||
base_case 분포 하나만으로 위기 취약성을 가리지 않도록, FORECAST_SIMULATION_ENGINE_V1의
|
||||
net_profit_distribution_after_tax_fee_slippage에 5개 스트레스 시나리오를 결정론적으로
|
||||
적용해 각 시나리오별 CE70/CVaR95를 산출한다. 거짓 분포 생성을 금지하며, base distribution이
|
||||
없으면 모든 시나리오가 DATA_MISSING이다.
|
||||
(governance/todo/v8_9_p2_adoption_plan.yaml P2-A,
|
||||
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:forecast_and_simulation_engine_v8_9.simulation_grid)
|
||||
applicable: FORECAST_SIMULATION_ENGINE_V1의 gate=PASS(분포 산출 성공) 직후.
|
||||
scenario_definitions:
|
||||
base_case: {shock_multiplier: 1.0, note: current_regime_probability_weighted, source_distribution: as-is}
|
||||
adverse_case: {shock_multiplier: 1.5, note: volatility_up_and_breadth_down — 손실 구간 증폭}
|
||||
liquidity_drought_case: {shock_multiplier: 1.3, capacity_derate_pct: 40, note: spread_widening_and_capacity_down}
|
||||
crisis_case: {shock_multiplier: 2.0, correlation_to_one: true, note: correlation_to_one_and_gap_down}
|
||||
fx_shock_case: {shock_multiplier: 1.2, applies_only_to: foreign_assets, note: USDKRW adverse movement}
|
||||
tax_cost_case: {shock_multiplier: 1.0, additional_cost_pct: 5, note: realized_gain_tax_and_reentry_cost_stress}
|
||||
inputs:
|
||||
- field: net_profit_distribution_after_tax_fee_slippage
|
||||
unit: list_of_KRW
|
||||
- field: scenario_id
|
||||
unit: 'enum: base_case | adverse_case | liquidity_drought_case | crisis_case | fx_shock_case | tax_cost_case'
|
||||
expression: >
|
||||
shocked_distribution = [v * scenario.shock_multiplier if v < 0 else v / scenario.shock_multiplier
|
||||
for v in net_profit_distribution_after_tax_fee_slippage] (손실만 증폭, 이익은 보수적으로 축소)
|
||||
scenario_ce70_krw = quantile(shocked_distribution, 0.30)
|
||||
scenario_cvar95_krw = mean(losses beyond 95th percentile loss threshold in shocked_distribution)
|
||||
output:
|
||||
field: scenario_results
|
||||
unit: 'list_of_{scenario_id, scenario_ce70_krw, scenario_cvar95_krw}'
|
||||
missing_policy: net_profit_distribution_after_tax_fee_slippage가 없으면 전체 scenario_results가 DATA_MISSING. 시나리오별로 임의 분포 생성 금지.
|
||||
canonical_ref: spec/formulas/domains/simulation.yaml:FORECAST_SIMULATION_ENGINE_V1
|
||||
implementation: tools/build_scenario_shock_matrix_v1.py
|
||||
owner: quant_team
|
||||
lifecycle_state: shadow
|
||||
input_fields:
|
||||
- net_profit_distribution_after_tax_fee_slippage
|
||||
- scenario_id
|
||||
output_fields:
|
||||
- scenario_results
|
||||
golden_cases:
|
||||
- V89_010_candidate_good_portfolio_bad
|
||||
activation_threshold:
|
||||
min_t20_sample: 30
|
||||
retirement_condition: performance_degradation
|
||||
WALK_FORWARD_BOOTSTRAP_V1:
|
||||
purpose: >
|
||||
FORECAST_SIMULATION_ENGINE_V1이 입력으로 받는 net_profit_distribution_after_tax_fee_slippage를
|
||||
실제 historical_returns 표본에서 walk-forward(시간순 비복원, in-sample/out-of-sample 분리) 및
|
||||
regime-matched(현재 레짐과 동일한 구간만 필터) 리샘플링으로 생성한다. 가짜 분포 생성을 금지하며
|
||||
historical_returns가 없거나 표본이 1건뿐이면 DATA_MISSING.
|
||||
(governance/todo/v8_9_p3_adoption_plan.yaml P3-B,
|
||||
source: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:forecast_and_simulation_engine_v8_9.allowed_estimators)
|
||||
applicable: FORECAST_SIMULATION_ENGINE_V1 직전 — 이 엔진의 출력이 FORECAST_SIMULATION_ENGINE_V1의 입력이 된다.
|
||||
inputs:
|
||||
- field: historical_returns
|
||||
unit: list_of_object
|
||||
note: 'spec/29_backtest_harness_contract.yaml 연동. [{date, regime_state, net_return_after_cost_pct}]. 현재 t20 n_sample=0.'
|
||||
- field: current_regime_state
|
||||
unit: string
|
||||
- field: bootstrap_method
|
||||
unit: 'enum: walk_forward | regime_matched'
|
||||
- field: resample_count
|
||||
unit: count
|
||||
default: 1000
|
||||
note: 리샘플링 반복 횟수. historical_returns 표본이 적으면 resample_count와 무관하게 sample_count_total은 historical_returns 길이로 결정.
|
||||
estimator_rule:
|
||||
walk_forward: >
|
||||
historical_returns를 시간순으로 정렬해 첫 70%를 in-sample, 나머지 30%를 out-of-sample로
|
||||
고정 분리한다. out-of-sample 구간에서만 비복원 블록 리샘플링(block size=5)으로
|
||||
net_profit_distribution을 생성한다. in-sample 재사용 금지(leakage 방지).
|
||||
regime_matched: >
|
||||
historical_returns 중 regime_state == current_regime_state인 행만 필터링 후
|
||||
복원추출(bootstrap with replacement)로 net_profit_distribution을 생성한다.
|
||||
필터 결과가 비어 있으면 DATA_MISSING(다른 레짐으로 대체 금지).
|
||||
leakage_controls:
|
||||
- asof_join_required
|
||||
- future_constituent_exclusion
|
||||
- calendar_alignment
|
||||
output:
|
||||
field: net_profit_distribution_after_tax_fee_slippage
|
||||
unit: list_of_KRW_or_null
|
||||
additional_outputs:
|
||||
- sample_count_total
|
||||
- sample_count_same_regime
|
||||
- leakage_check_status
|
||||
missing_policy: historical_returns 결측 또는 표본 1건 이하면 net_profit_distribution=null + gate=DATA_MISSING. 보간·추정 금지.
|
||||
canonical_ref: spec/29_backtest_harness_contract.yaml:current_metrics.walk_forward
|
||||
implementation: tools/build_walk_forward_bootstrap_v1.py
|
||||
owner: quant_team
|
||||
lifecycle_state: shadow
|
||||
input_fields:
|
||||
- historical_returns
|
||||
- current_regime_state
|
||||
- bootstrap_method
|
||||
- resample_count
|
||||
output_fields:
|
||||
- net_profit_distribution_after_tax_fee_slippage
|
||||
- sample_count_total
|
||||
- sample_count_same_regime
|
||||
golden_cases:
|
||||
- V89_014_same_regime_sample_low
|
||||
- V89_048_solver_failure
|
||||
activation_threshold:
|
||||
min_t20_sample: 30
|
||||
retirement_condition: performance_degradation
|
||||
Reference in New Issue
Block a user