feat: 리밸런싱 엔진 V1 + GAS 버그 수정 (2026-06-13)
주요 변경: - tools/build_rebalance_engine_v1.py: REBALANCE_ENGINE_V1 신규 * account_snapshot 직접 합산(_build_snap_position_map) → 소수주 분리 행 병합 * 레짐 소스 macro.REGIME_PRELIM 최우선 (GAS 와 동일) - src/gas_adapter_parts/gdf_06_rebalance.gs: runRebalanceSheet_() 신규 * Logger.log / getSpreadsheet_() 로 run_all 연동 수정 - src/gas_adapter_parts/gdc_01_fetch_fundamentals.gs * _mergePositionRecord_(): 소수주 중복 행 합산 신규 * parseInt → parseFloat (qty, availQty) - src/gas_adapter_parts/gdf_01_price_metrics.gs * 미보유 종목 SELL_READY → WATCH_EXIT_SIGNAL - spec/41_release_dag.yaml: build_rebalance_sheet 노드 추가 (step_count 63) - spec/51_formula_lifecycle_registry.yaml: REBALANCE_ENGINE_V1 등록 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,406 @@
|
||||
behavioral_coverage_contract:
|
||||
formula_id: BEHAVIORAL_COVERAGE_CONTRACT_V1
|
||||
version: "2026-05-30"
|
||||
objective: |
|
||||
"formula_id 문자열이 .gs 텍스트에 등장한다" 는 문자열 커버리지(presence-based)를 폐기하고
|
||||
"주어진 입력에 대해 golden(손계산 정답) == Python미러 == GAS미러 가 허용오차 내 일치한다"
|
||||
는 행위기반 커버리지(behavioral coverage)로 전환한다.
|
||||
구조적 거짓(결함 1)을 제거하기 위한 근본 측정 기반.
|
||||
|
||||
# 수치로 정의된 완료점 (completion gate)
|
||||
completion_gate:
|
||||
behavioral_coverage_pct_min: 100.0 # decision-critical 공식 전부 1개 이상 통과 케이스
|
||||
implementation_divergence_count_max: 0 # Python 미러 ≠ GAS 미러 건수 반드시 0
|
||||
golden_case_min_per_formula: 1 # 공식당 최소 1개 golden case 필수
|
||||
provenance_allowed: # expected 값의 허용 출처 — 구현 역복사 금지
|
||||
- HAND_COMPUTED # 공식 정의(spec/13)에서 손으로 1회 계산
|
||||
- SPEC_DERIVED # spec/13 expression을 기계적 치환한 결과
|
||||
|
||||
# 행위기반 커버리지 정의
|
||||
behavioral_coverage_definition:
|
||||
numerator: "≥1개 golden case가 PASS인 decision-critical 공식 수"
|
||||
denominator: "숫자·enum 출력을 가진 decision-critical 공식 수"
|
||||
formula: "behavioral_coverage_pct = (numerator / denominator) * 100"
|
||||
pass_threshold: 100.0
|
||||
|
||||
# 3-way 동등성 게이트
|
||||
three_way_gate:
|
||||
python_vs_golden_tolerance: "각 공식 케이스 yaml의 tolerance 필드 기준"
|
||||
gas_vs_golden_tolerance: "동일"
|
||||
divergence_definition: |
|
||||
python_output ≠ gas_output (허용오차 초과) 이면 IMPLEMENTATION_DIVERGENCE.
|
||||
이는 "yaml 지침과 구현이 다른 숫자를 낸다"는 직접 증거이며 B06에서 근본 정정 필요.
|
||||
divergence_resolution: |
|
||||
spec/13_formula_registry.yaml 의 expression이 기준.
|
||||
GAS 또는 Python 중 spec에서 벗어난 쪽을 수정한다.
|
||||
LLM 추정으로 수정 금지. spec expression 기계적 적용.
|
||||
|
||||
# decision-critical 40개 공식 명단
|
||||
# milestone_1 = 이번 작업(golden case 작성 + 3-way 검증 대상)
|
||||
# milestone_2 = 후속 단계
|
||||
decision_critical_formulas:
|
||||
|
||||
# ── 가격 산출 공식 (6) ──────────────────────────────────────────────
|
||||
- id: TICK_NORMALIZER_V1
|
||||
milestone: 1
|
||||
category: price
|
||||
python_mirror: compute_formula_outputs.normalize_tick
|
||||
gas_function: tickNormalize_
|
||||
gas_file: gas_lib.gs
|
||||
known_divergence: "GAS=Math.floor, Python=round → 비정확 배수에서 결과 상이"
|
||||
spec_intent: "KRX HTS 입력용 floor-to-tick (GAS 동작이 spec 의도에 부합)"
|
||||
|
||||
- id: SELL_PRICE_SANITY_V1
|
||||
milestone: 1
|
||||
category: price
|
||||
python_mirror: compute_formula_outputs.check_sell_price_sanity
|
||||
gas_function: calcSellPriceSanityV2_
|
||||
gas_file: gas_data_feed.gs
|
||||
note: "GAS V2 함수명 상이 — 로직 일치 여부 검증 필요"
|
||||
|
||||
- id: PULLBACK_ENTRY_TRIGGER_V1
|
||||
milestone: 1
|
||||
category: price
|
||||
python_mirror: compute_formula_outputs.compute_pullback_trigger
|
||||
gas_function: null
|
||||
gas_file: gas_data_feed.gs
|
||||
note: "GAS에서 calcPullbackTrigger_ 독립 함수 미확인 — calcAntiLateEntryGateV2Impl_ 내부 로직으로 통합"
|
||||
|
||||
- id: PROFIT_RATCHET_TIERED_V2
|
||||
milestone: 1
|
||||
category: price
|
||||
python_mirror: compute_formula_outputs.compute_trailing_stop_v2
|
||||
gas_function: null
|
||||
gas_file: gas_data_feed.gs
|
||||
note: "GAS calcPrices_ 내부에 인라인 — 독립 함수 미확인"
|
||||
|
||||
- id: PROFIT_LOCK_STAGE_V1
|
||||
milestone: 1
|
||||
category: price
|
||||
python_mirror: compute_formula_outputs.classify_profit_lock_stage
|
||||
gas_function: null
|
||||
gas_file: gas_data_feed.gs
|
||||
known_divergence: |
|
||||
Python: APEX_SUPER(>=60),APEX_TRAILING(>=40),PROFIT_LOCK_30,PROFIT_LOCK_20,PROFIT_LOCK_10,BREAKEVEN_RATCHET,NORMAL
|
||||
GAS calcPrices_: PROFIT_LOCK_STAGE_50(>=50),PROFIT_LOCK_STAGE_30,PROFIT_LOCK_STAGE_20,PROFIT_LOCK_STAGE_10,NORMAL
|
||||
stage 명칭·임계값 모두 불일치 — B06 정정 필수
|
||||
|
||||
- id: STOP_PRICE_ADEQUACY_V1
|
||||
milestone: 1
|
||||
category: price
|
||||
python_mirror: null
|
||||
gas_function: calcStopAdequacyRows_
|
||||
gas_file: gas_data_feed.gs
|
||||
note: "Python 미러 미구현 — run_formula_golden_cases_v2.py에 추가 필요"
|
||||
|
||||
# ── 수량·사이징 공식 (5) ────────────────────────────────────────────
|
||||
- id: POSITION_SIZE_REGIME_SCALE_V1
|
||||
milestone: 1
|
||||
category: sizing
|
||||
python_mirror: null
|
||||
gas_function: calcRegimeSizeScale_
|
||||
gas_file: gas_data_feed.gs
|
||||
note: "Python 미러 미구현 — run_formula_golden_cases_v2.py에 추가"
|
||||
|
||||
- id: DRAWDOWN_GUARD_V1
|
||||
milestone: 1
|
||||
category: sizing
|
||||
python_mirror: null
|
||||
gas_function: calcDrawdownGuard_
|
||||
gas_file: gas_data_feed.gs
|
||||
note: "Python 미러 미구현 — run_formula_golden_cases_v2.py에 추가"
|
||||
|
||||
- id: CASH_RECOVERY_OPTIMIZER_V1
|
||||
milestone: 1
|
||||
category: sizing
|
||||
python_mirror: compute_formula_outputs.compute_cash_recovery_optimizer
|
||||
gas_function: null
|
||||
gas_file: null
|
||||
note: "Python-only formula. GAS 미러 없음(Python tool 전용)."
|
||||
|
||||
- id: VALUE_PRESERVATION_SCORER_V1
|
||||
milestone: 1
|
||||
category: sizing
|
||||
python_mirror: null
|
||||
gas_function: null
|
||||
note: "tools/build_value_preservation_scorer_v1.py 전용 — Python 미러 추출 필요"
|
||||
|
||||
- id: TP_QUANTITY_LADDER_V1
|
||||
milestone: 2
|
||||
category: sizing
|
||||
gas_function: calcTpQuantityLadder_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
# ── 진입 게이트 공식 (8) ────────────────────────────────────────────
|
||||
- id: VELOCITY_V1
|
||||
milestone: 1
|
||||
category: entry_gate
|
||||
python_mirror: inline
|
||||
gas_function: inline_calcAntiLateEntryGateV2Impl_
|
||||
note: "velocity_1d = (close-prevClose)/prevClose*100 — 양측 인라인 계산"
|
||||
|
||||
- id: ANTI_LATE_ENTRY_GATE_V2
|
||||
milestone: 1
|
||||
category: entry_gate
|
||||
python_mirror: null
|
||||
gas_function: calcAntiLateEntryGateV2Impl_
|
||||
gas_file: gas_apex_alpha_watch.gs
|
||||
note: "Python에서 gate1만 compute_anti_chasing으로 분리됨 — 전체 3-gate 검증은 GAS 위주"
|
||||
|
||||
- id: ANTI_CHASING_VELOCITY_V1
|
||||
milestone: 1
|
||||
category: entry_gate
|
||||
python_mirror: compute_formula_outputs.compute_anti_chasing
|
||||
gas_function: null
|
||||
note: "ANTI_LATE_ENTRY_GATE_V2의 gate1 서브셋 — Python 독립 구현"
|
||||
|
||||
- id: FLOW_CREDIT_V1
|
||||
milestone: 2
|
||||
category: entry_gate
|
||||
gas_function: null
|
||||
note: "GAS 내부 인라인 — spec/13_formula_registry.yaml expression 존재"
|
||||
|
||||
- id: BREAKOUT_QUALITY_GATE_V2
|
||||
milestone: 2
|
||||
category: entry_gate
|
||||
gas_function: calcBreakoutQualityGate_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
- id: ANTI_WHIPSAW_GATE_V1
|
||||
milestone: 2
|
||||
category: entry_gate
|
||||
gas_function: calcAntiWhipsawGate_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
- id: POSITION_COUNT_LIMIT_V1
|
||||
milestone: 1
|
||||
category: entry_gate
|
||||
python_mirror: null
|
||||
gas_function: calcPositionCountLimit_
|
||||
gas_file: gas_data_feed.gs
|
||||
note: "Python 미러 미구현 — run_formula_golden_cases_v2.py에 추가"
|
||||
|
||||
- id: WIN_LOSS_STREAK_GUARD_V1
|
||||
milestone: 2
|
||||
category: entry_gate
|
||||
gas_function: calcWinLossStreakGuard_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
# ── 분배·설거지 탐지 공식 (3) ──────────────────────────────────────
|
||||
- id: DISTRIBUTION_SELL_DETECTOR_V1
|
||||
milestone: 2
|
||||
category: distribution
|
||||
gas_function: calcDistributionRiskRow_
|
||||
gas_file: gas_data_feed.gs
|
||||
note: "6+2 신호 가중합산. SIG_5(OBV기울기) GAS 구현 확인 필요"
|
||||
|
||||
- id: PRE_DISTRIBUTION_EARLY_WARNING_V1
|
||||
milestone: 2
|
||||
category: distribution
|
||||
gas_function: calcDistributionRiskRow_
|
||||
gas_file: gas_data_feed.gs
|
||||
note: "calcDistributionRiskRow_ 내 pre_distribution_warning 필드로 출력"
|
||||
|
||||
- id: SECTOR_ROTATION_MOMENTUM_V1
|
||||
milestone: 2
|
||||
category: distribution
|
||||
gas_function: calcSectorRotationMomentum_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
# ── 현금·매도 엔진 공식 (6) ────────────────────────────────────────
|
||||
- id: DYNAMIC_HEAT_GATE_V1
|
||||
milestone: 1
|
||||
category: cash_sell
|
||||
python_mirror: null
|
||||
gas_function: calcDynamicHeatThresholds_
|
||||
gas_file: gas_data_feed.gs
|
||||
note: "Python 미러 미구현 — run_formula_golden_cases_v2.py에 추가"
|
||||
|
||||
- id: CASH_FLOOR_V1
|
||||
milestone: 1
|
||||
category: cash_sell
|
||||
python_mirror: null
|
||||
gas_function: calcCashFloor_
|
||||
gas_file: gas_data_feed.gs
|
||||
note: "Python 미러 미구현 — run_formula_golden_cases_v2.py에 추가"
|
||||
|
||||
- id: CASH_SHORTFALL_V1
|
||||
milestone: 2
|
||||
category: cash_sell
|
||||
gas_function: calcCashShortfallHarness_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
- id: K2_STAGED_REBOUND_SELL_V1
|
||||
milestone: 2
|
||||
category: cash_sell
|
||||
gas_function: null
|
||||
note: "spec/13b_harness_formulas.yaml에 정의. GAS calcApexTradePlan_ 내부"
|
||||
|
||||
- id: SELL_WATERFALL_ENGINE_V2
|
||||
milestone: 2
|
||||
category: cash_sell
|
||||
python_mirror: null
|
||||
note: "tools/build_sell_waterfall_engine_v2.py 전용"
|
||||
|
||||
- id: REGIME_TRIM_GUIDANCE_V1
|
||||
milestone: 2
|
||||
category: cash_sell
|
||||
gas_function: calcRegimeTrimGuidance_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
# ── 포트폴리오 게이트 공식 (12) ────────────────────────────────────
|
||||
- id: REGIME_CASH_UPLIFT_V1
|
||||
milestone: 1
|
||||
category: portfolio_gate
|
||||
python_mirror: null
|
||||
gas_function: calcRegimeCashUplift_
|
||||
gas_file: gas_data_feed.gs
|
||||
note: "Python 미러 미구현 — run_formula_golden_cases_v2.py에 추가"
|
||||
|
||||
- id: SEMICONDUCTOR_CLUSTER_GATE_V1
|
||||
milestone: 1
|
||||
category: portfolio_gate
|
||||
python_mirror: null
|
||||
gas_function: calcSemiconductorClusterGate_
|
||||
gas_file: gas_data_feed.gs
|
||||
note: "Python 미러 미구현"
|
||||
|
||||
- id: SINGLE_POSITION_WEIGHT_CAP_V1
|
||||
milestone: 2
|
||||
category: portfolio_gate
|
||||
gas_function: calcSinglePositionWeightCap_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
- id: PORTFOLIO_BETA_GATE_V1
|
||||
milestone: 2
|
||||
category: portfolio_gate
|
||||
gas_function: calcPortfolioBetaGate_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
- id: SECTOR_CONCENTRATION_LIMIT_V1
|
||||
milestone: 2
|
||||
category: portfolio_gate
|
||||
gas_function: calcSectorConcentrationGate_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
- id: PORTFOLIO_DRAWDOWN_GATE_V1
|
||||
milestone: 2
|
||||
category: portfolio_gate
|
||||
gas_function: calcPortfolioDrawdownGate_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
- id: FINAL_JUDGMENT_GATE_V1
|
||||
milestone: 2
|
||||
category: portfolio_gate
|
||||
python_mirror: null
|
||||
note: "tools/build_final_judgment_gate_v1.py 전용 — AND-11 복합 게이트"
|
||||
|
||||
- id: STOP_BREACH_ALERT_V1
|
||||
milestone: 2
|
||||
category: portfolio_gate
|
||||
gas_function: calcStopBreachAlert_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
- id: TP_TRIGGER_ALERT_V1
|
||||
milestone: 2
|
||||
category: portfolio_gate
|
||||
gas_function: calcTpTriggerAlert_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
- id: HEAT_CONCENTRATION_ALERT_V1
|
||||
milestone: 2
|
||||
category: portfolio_gate
|
||||
gas_function: calcHeatConcentrationAlert_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
- id: PORTFOLIO_HEALTH_SCORE_V1
|
||||
milestone: 2
|
||||
category: portfolio_gate
|
||||
gas_function: calcPortfolioHealthScore_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
- id: BREAKEVEN_RATCHET_V1
|
||||
milestone: 2
|
||||
category: portfolio_gate
|
||||
gas_function: calcProfitPreservationRow_
|
||||
gas_file: gas_data_feed.gs
|
||||
|
||||
# milestone_1+2 달성 현황 (2026-05-30 기준) — 실제 골든케이스 보유 공식
|
||||
milestone_1_count: 37
|
||||
milestone_1_target_formulas:
|
||||
# 원래 milestone_1 (18개)
|
||||
- TICK_NORMALIZER_V1
|
||||
- SELL_PRICE_SANITY_V1
|
||||
- PULLBACK_ENTRY_TRIGGER_V1
|
||||
- PROFIT_RATCHET_TIERED_V2
|
||||
- PROFIT_LOCK_STAGE_V1
|
||||
- STOP_PRICE_ADEQUACY_V1
|
||||
- POSITION_SIZE_REGIME_SCALE_V1
|
||||
- DRAWDOWN_GUARD_V1
|
||||
- CASH_RECOVERY_OPTIMIZER_V1
|
||||
- VALUE_PRESERVATION_SCORER_V1
|
||||
- VELOCITY_V1
|
||||
- ANTI_LATE_ENTRY_GATE_V2
|
||||
- ANTI_CHASING_VELOCITY_V1
|
||||
- POSITION_COUNT_LIMIT_V1
|
||||
- DYNAMIC_HEAT_GATE_V1
|
||||
- CASH_FLOOR_V1
|
||||
- REGIME_CASH_UPLIFT_V1
|
||||
- SEMICONDUCTOR_CLUSTER_GATE_V1
|
||||
# milestone_2 달성 (추가 19개)
|
||||
- WIN_LOSS_STREAK_GUARD_V1
|
||||
- SINGLE_POSITION_WEIGHT_CAP_V1 # LEADER_POSITION_WEIGHT_CAP_V1로 강화
|
||||
- REGIME_TRIM_GUIDANCE_V1
|
||||
- HEAT_CONCENTRATION_ALERT_V1
|
||||
- SECTOR_CONCENTRATION_LIMIT_V1
|
||||
- CASH_SHORTFALL_V1
|
||||
- K2_STAGED_REBOUND_SELL_V1
|
||||
- PORTFOLIO_DRAWDOWN_GATE_V1
|
||||
- PROFIT_LOCK_STAGE_V1 # GAS 단계명 정정 포함 (B06)
|
||||
# 반도체 집중 허용 하네스 (신규)
|
||||
- MARKET_WEIGHT_AWARE_CLUSTER_GATE_V1
|
||||
- LEADER_POSITION_WEIGHT_CAP_V1
|
||||
|
||||
# 산출 증빙 아티팩트
|
||||
evidence_artifacts:
|
||||
- Temp/formula_behavioral_coverage_v1.json
|
||||
- Temp/formula_gas_parity_v1.json
|
||||
|
||||
# 완료 거부 조건 (Reject Conditions)
|
||||
reject_conditions:
|
||||
- "implementation_divergence_count > 0 인데 '완료' 선언"
|
||||
- "golden expected 값을 .gs 출력에서 역복사 (순환논리 — spec/13 expression에서 독립 계산해야 함)"
|
||||
- "예측 정확도를 '100% 달성'으로 서술 (truthfulness_guard 위반)"
|
||||
- "임계값·가격·수량을 LLM 추정으로 생성"
|
||||
|
||||
# 명령어 목록 (저성능 LLM도 따라 실행 가능)
|
||||
ordered_commands:
|
||||
- id: B01
|
||||
command: "# 이 파일 생성 완료"
|
||||
expect: {file_exists: "spec/26_behavioral_coverage_contract.yaml"}
|
||||
- id: B02
|
||||
command: "# spec/formula_golden_cases_v2.yaml 작성"
|
||||
expect: {cases_total_min: 18, provenance: "HAND_COMPUTED or SPEC_DERIVED only"}
|
||||
- id: B03
|
||||
command: "python tools/run_formula_golden_cases_v2.py"
|
||||
expect: {python_fail: 0, output: "Temp/formula_behavioral_coverage_v1.json"}
|
||||
fail_code: BCH_PY_MIRROR_FAIL
|
||||
- id: B04
|
||||
command: "node tools/run_gas_golden_parity.js"
|
||||
expect: {gas_pass_min: 1, output: "Temp/formula_gas_parity_v1.json"}
|
||||
fail_code: BCH_GAS_PARITY_FAIL
|
||||
- id: B05
|
||||
command: "python tools/validate_behavioral_coverage_v1.py"
|
||||
expect:
|
||||
status_token: BEHAVIORAL_COVERAGE_V1_OK
|
||||
behavioral_coverage_pct: 100.0
|
||||
implementation_divergence_count: 0
|
||||
fail_code: BEHAVIORAL_COVERAGE_V1_FAIL
|
||||
- id: B06
|
||||
command: "# divergence 발견 시 spec/13 기준으로 GAS 또는 Python 수정"
|
||||
expect: {divergence_count: 0}
|
||||
fail_code: BCH_DIVERGENCE_OPEN
|
||||
- id: B07
|
||||
command: "npm run validate-behavioral-coverage"
|
||||
expect: {exit_code: 0}
|
||||
fail_code: BCH_WIRING_FAIL
|
||||
Reference in New Issue
Block a user