diff --git a/docs/runbook.md b/docs/runbook.md index 25d81cb..ba4c729 100644 --- a/docs/runbook.md +++ b/docs/runbook.md @@ -6,3 +6,18 @@ 4. Render reports from canonical data only. 5. Package upload artifacts only after the full gate passes or the output is explicitly audit-only. 6. Treat work as complete only when YAML, code, data artifacts, and validation evidence all exist together. +7. For calibration maintenance, run `npm run ops:calibration-backlog` or the Gitea schedule in `.gitea/workflows/calibration_backlog.yml`. +8. Promote a threshold to `PROVISIONAL` only when there is a recorded sample note and an explicit change note in `Temp/calibration_change_ledger_v4.json`. +9. Promote a threshold to `CALIBRATED` only when `sample_n >= 30`, a backtest note exists, and the validator still reports `overclaimed_count == 0`. +10. For human review, open `Temp/calibration_review_report_v1.md` after each backlog build. +11. For approval signoff, open `Temp/calibration_approval_list_v1.md` and approve only `source=PROVISIONAL` rows unless a new provisional review is explicitly requested. +12. For spreadsheet-like edits of `settings` and `account_snapshot`, run `npm run ops:snapshot-web` and validate with `npm run ops:snapshot-web-validate`. +13. Treat the snapshot admin web UI as the canonical edit surface for SQLite-backed manual maintenance; export JSON only when CI or downstream tooling needs a file artifact. +14. Keep `settings` and `account_snapshot` in the same workspace SQLite DB. Do not split them into separate files per sheet; use a separate SQLite DB only for the KIS collection pipeline. +15. Use the `KIS Collection` panel in snapshot admin to inspect the latest SQLite collection run, report status, source counts, and recent errors before you touch the editor. +16. Use the collection filter when you need to narrow runs, snapshots, or errors by ticker/source/status. +17. Use the change log filter when you need to audit a specific domain, action, or target reference. +18. Use `/collection` when you want the collection-only dashboard with raw JSON download. +19. Use `Export approval packet` in the snapshot admin UI to write `Temp/snapshot_admin_approval_packet_v1.json` and `Temp/snapshot_admin_approval_packet_v1.md` for review handoff. +20. Short balance ratio (`short_balance_ratio`) has no automatable path — confirmed 2026-06-22 by live-testing `pykrx.stock.get_shorting_balance()` (already used elsewhere in this repo for EOD prices), which returns `HTTP 400 LOGOUT` even with a properly bootstrapped session. This KRX "standard report" endpoint family requires actual KRX member login (`KRX_ID`/`KRX_PW`), unlike the basic OHLCV endpoints. Adding KRX login credentials is a new credential-management policy decision (same category as governance/rules/06-07) that requires explicit user approval — do not add it unilaterally. Until then, download the KRX 공매도종합포털 CSV weekly (every Monday before market open) and feed it via `--short-csv` to `build_qualitative_sell_inputs_v1.py`. +21. ETF NAV/iNAV/괴리율/추적오차/AUM has no automatable path either — same 2026-06-22 test confirmed `pykrx.stock.get_etf_price_deviation()`/`get_etf_tracking_error()` also return `HTTP 400 LOGOUT` (same KRX member-login gate as item 20). See `spec/16_data_gaps_roadmap.yaml` S4/S5 `automation_attempt_2026_06_22` for the full reproduction. Until a KRX login policy decision is made, keep feeding `etf_nav_manual` via `tools/import_etf_nav_manual.py` from manually downloaded KRX/KIND/운용사 CSV exports. diff --git a/spec/16_data_gaps_roadmap.yaml b/spec/16_data_gaps_roadmap.yaml index 4bfbd0a..ab43353 100644 --- a/spec/16_data_gaps_roadmap.yaml +++ b/spec/16_data_gaps_roadmap.yaml @@ -1,6 +1,6 @@ meta: title: "데이터 갭 로드맵 — 단계별 보완 계획" - version: "2026-05-17-initial" + version: "2026-06-21-platform-transition-v1" language: "ko-KR" purpose: > 의사결정 파이프라인(spec/09_decision_flow.yaml)에서 식별된 데이터 공백을 @@ -145,6 +145,25 @@ phase_2_structural: limitation: > KRX/KIND 기반 NAV/괴리율/추적오차/AUM 수집은 아직 미구현이며 etf_raw에서 ETF_NAV_Risk=NAV_DATA_MISSING으로 명시한다. + next_review_date: "2026-09-30" # WBS-7.8(2026-06-21) — KRX/KIND API 키 발급 가능성 분기별 재조사 + next_review_action: > + KRX 정보데이터시스템/KIND 공식 API 또는 공개 데이터셋의 발급/이용약관 변경 여부를 + 재확인한다. 변경이 없으면 next_review_date를 다음 분기로 갱신하고 PLANNED 유지, + 변경이 있으면 P1_kis_core_api_collector와 동일한 패턴으로 착수 여부를 결정한다. + automation_attempt_2026_06_22: > + pykrx(이미 tools/build_prediction_accuracy_harness_v2.py에서 EOD 가격 조회로 사용 중)의 + get_etf_price_deviation()/get_etf_tracking_error()/get_shorting_balance()를 실제로 + 호출해 자동화 가능성을 재시도했다. 결과: 기본 시세조회(OHLCV)는 정상 작동(공개 + 엔드포인트, 로그인 불필요)하지만, 공매도 잔고/ETF 괴리율/추적오차 엔드포인트는 + 세션 쿠키를 정상 부트스트랩한 뒤에도 "HTTP 400 LOGOUT"을 반환했다(raw HTTP로 + 재현 확인). 이는 pykrx 임포트 시 출력되는 "KRX_ID/KRX_PW 환경변수 미설정" 경고와 + 정확히 일치 — 이 카테고리는 KRX 회원 로그인이 있어야 접근 가능한 서버측 인증 + 게이트이며, 헤더/세션 보정으로 해결되는 문제가 아님을 확인했다. 자동화하려면 + KRX 계정(KRX_ID/KRX_PW)을 자격증명으로 코드에 등록해야 하는데, 이는 + governance/rules/06·07과 유사한 새로운 자격증명 정책 결정이 필요한 사안이라 + 사용자 승인 없이 추가하지 않는다. 기술적 장벽 자체는 명확히 확정됐으므로 + next_review_date 재조사 시 "API 키 발급 가능성"이 아니라 "KRX 계정 발급·자격증명 + 관리 정책 승인 여부"로 재구성해 검토할 것. S5_etf_raw_execution_quality: priority: HIGH @@ -158,6 +177,9 @@ phase_2_structural: etf_nav_manual 시트가 있으면 NAV, iNAV, 괴리율, 추적오차, AUM을 etf_raw에 반영한다. tools/import_etf_nav_manual.py로 KRX/KIND/운용사 CSV/XLSX export를 etf_nav_manual로 변환할 수 있다. limitation: "NAV, iNAV, 괴리율, 추적오차, AUM 자동 수집은 KRX/KIND 수집 경로 확정 전까지 미구현." + next_review_date: "2026-09-30" # WBS-7.8(2026-06-21) — S4와 동일 주기로 재검토 + next_review_action: "S4_sector_flow.next_review_action과 동일 — KRX/KIND 경로 확정 시 etf_nav_manual 수동 경로를 자동 수집으로 대체." + automation_attempt_2026_06_22: "S4_sector_flow.automation_attempt_2026_06_22와 동일 사유로 자동화 불가 확정(pykrx get_etf_price_deviation/get_etf_tracking_error 모두 HTTP 400 LOGOUT — KRX 회원 로그인 필요)." S6_sector_flow_history: priority: HIGH @@ -169,6 +191,41 @@ phase_2_structural: 이력이 부족할 때만 기존 sector_flow/PropertiesService 값을 fallback으로 사용한다. Snapshot_Date는 Apps Script Date 객체와 문자열 날짜를 모두 yyyy-MM-dd로 정규화한다. + S7_snapshot_admin_web_editor: + priority: HIGH + status: DONE + implementation: > + SQLite canonical store용 웹 편집기 구현. + settings/account_snapshot을 contenteditable 그리드로 직접 수정하고, + TSV import/export, 행 삽입/복제, 승인/잠금/undo를 API로 제어한다. + KIS SQLite collector 상태 패널을 함께 노출해서 최신 수집 run/오류를 + 같은 화면에서 확인한다. + web UI는 Snapshot Admin 서버가 담당하며 JSON export는 CI/파생 도구용이다. + enables: > + settings/account_snapshot을 xlsx 대신 SQLite에서 직접 관리하면서도 + 스프레드시트처럼 편집 가능한 운영 surface와 수집 현황 대시보드 제공. + success_criteria: + settings_sheet_web_editor: true + account_snapshot_sheet_web_editor: true + contenteditable_grid: true + api_save_round_trip: PASS + kis_collection_dashboard: true + single_workspace_sqlite: true + collection_filter_controls: true + collection_dashboard_page: true + change_timeline_view: true + evidence: + code: + - "src/quant_engine/snapshot_admin_server_v1.py" + - "src/quant_engine/snapshot_admin_store_v1.py" + - "tools/validate_snapshot_admin_web_v1.py" + tests: + - "tests/unit/test_snapshot_admin_store_v1.py" + - "tests/unit/test_snapshot_admin_web_v1.py" + workflow: + - ".gitea/workflows/snapshot_admin.yml" + verification: "python tools/validate_snapshot_admin_web_v1.py" + # ───────────────────────────────────────────────────────────────────────────── # 3단계 — 분석 품질 고도화 (낮은 우선순위) # ───────────────────────────────────────────────────────────────────────────── @@ -503,6 +560,203 @@ phase_4_backdata_collection: 2026-06-14 구현 완료 확인. GAS(syncBackdataFeatureBank_) + Python(synthesize_backdata_feature_bank) 모두 구현됨. T+20 데이터 누적 후 ML 패턴 학습 품질 향상 예정. +# ───────────────────────────────────────────────────────────────────────────── +# 5단계 — CI 기반 데이터 플랫폼 전환 +# ───────────────────────────────────────────────────────────────────────────── +phase_5_platform_transition: + P1_kis_core_api_collector: + priority: HIGH + status: PLANNED + purpose: > + KIS Open API를 read-only 코어 수집원으로 두고, 가격/호가/공매도/수급의 + 1차 수집을 Python canonical collector에서 직접 수행한다. + inputs: + - "KIS_APP_Key / KIS_APP_Secret" + - "KIS_APP_Key_TEST / KIS_APP_Secret_TEST" + - "GatherTradingData.json" + outputs: + - "Temp/kis_data_collection_v1.json" + - "outputs/kis_data_collection/kis_data_collection.db" + fallback_order: + - "KIS Open API" + - "Naver Finance" + - "Yahoo Finance" + - "OpenDART" + - "Investing.com(best-effort, 차단 시 DATA_MISSING)" + note: > + 주문 API는 사용하지 않는다. 조회형 quotations/ranking 계열만 허용한다. + success_criteria: + expected_success_value: + collector_gate: "PASS" + output_json_gate: "PASS" + sqlite_run_count_min: 1 + sqlite_snapshot_count_min: 1 + provenance_source_count_min: 1 + evidence_artifacts: + - "Temp/test_kis_data_collection.json" + - "Temp/test_kis_data_collection.db" + verification_commands: + - "python tools/run_kis_data_collection_v1.py --input-json GatherTradingData.json --sqlite-db Temp/test_kis_data_collection.db --output-json Temp/test_kis_data_collection.json --kis-account real --no-live-kis --no-naver" + - "python - <<'PY' ... sqlite count check ... PY" + + P2_sqlite_canonical_store: + priority: HIGH + status: PLANNED + purpose: > + xlsx 중심 저장을 중단하고, 수집 결과를 SQLite에 누적 저장한다. + 향후 PostgreSQL 승격 시 동일 저장 인터페이스를 유지한다. + required_tables: + - "collection_runs" + - "collection_snapshots" + - "collection_source_errors" + stored_payloads: + - "raw source payload" + - "normalized factor row" + - "provenance JSON" + - "batch/run metadata" + migration_note: "PostgreSQL 전환 시 dialect만 교체하고 row shape은 유지한다." + success_criteria: + expected_success_value: + sqlite_schema_tables_min: 3 + round_trip_snapshot_lookup: "PASS" + backend_contract_sqlite: "PASS" + backend_contract_postgresql: "READY" + evidence_artifacts: + - "src/quant_engine/data_collection_store_v1.py" + - "src/quant_engine/data_collection_backend_v1.py" + - "tests/unit/test_data_collection_store_v1.py" + verification_commands: + - "python -m pytest tests/unit/test_data_collection_store_v1.py -q" + - "python -m py_compile src/quant_engine/data_collection_store_v1.py src/quant_engine/data_collection_backend_v1.py" + + P3_ci_scheduler_cutover: + priority: HIGH + status: PLANNED + purpose: > + Gitea schedule에서 Python collector를 직접 실행하고, CI가 SQLite 산출을 검증한다. + 기존 GAS 워크플로우는 thin adapter/legacy fallback으로만 유지한다. + validation_gate: + - "read-only KIS gate" + - "source fallback gate" + - "sqlite round-trip gate" + - "provenance completeness gate" + - "no-direct-trading gate" + output_policy: + - "CI는 xlsx 생성에 의존하지 않는다." + - "결과는 JSON + SQLite + 로그 증빙으로 남긴다." + success_criteria: + expected_success_value: + xlsx_dependency_removed: true + json_seed_input: true + sqlite_output: true + mock_api_validation: "PASS" + no_direct_trading_gate: "PASS" + provenance_completeness_gate: "PASS" + evidence_artifacts: + - ".gitea/workflows/kis_data_collection.yml" + - "Temp/kis_api_credentials_validation_v1.json" + - "Temp/test_kis_data_collection.json" + verification_commands: + - "python tools/validate_no_direct_api_trading_v1.py" + - "python tools/validate_kis_api_credentials_v1.py --account mock --ticker 005930" + - "python tools/run_kis_data_collection_v1.py --help" + + P4_gas_thin_adapter_minimize: + priority: MEDIUM + status: PLANNED + purpose: > + .gs는 기존 스프레드시트 호환과 과도기 검증용 얇은 어댑터만 남기고, + 판단·수집·저장 로직은 Python으로 이동시킨다. + allowed_responsibilities: + - "collect" + - "normalize" + - "export" + - "display" + forbidden_responsibilities: + - "decision" + - "sizing" + - "stop_loss" + - "take_profit" + - "risk_score" + success_criteria: + expected_success_value: + allowed_responsibilities_only: true + forbidden_responsibilities_present: false + thin_adapter_gate: "PASS" + evidence_artifacts: + - "tools/validate_gas_thin_adapter_v1.py" + - "Temp/gas_thin_adapter_validation_v1.json" + - "src/gas/core/gas_lib.gs" + verification_commands: + - "python tools/validate_gas_thin_adapter_v1.py" + + P5_postgresql_upgrade_path: + priority: MEDIUM + status: PLANNED + purpose: > + SQLite에서 검증된 스키마/업서트/프로venance 모델을 PostgreSQL로 승격한다. + 운영 데이터 증가와 멀티잡 동시성 증가를 대비한다. + upgrade_steps: + - "sqlite schema parity 검증" + - "db_url 기반 backend 추상화" + - "migration script 추가" + - "CI에서 sqlite/postgres 동일 테스트" + compatibility_rule: "SQLite와 PostgreSQL 모두 동일한 row contract를 유지한다." + success_criteria: + expected_success_value: + sqlite_schema_parity: "PASS" + backend_contract_present: true + postgres_execution: "DATA_GATED" + caller_compatibility_preserved: true + evidence_artifacts: + - "src/quant_engine/data_collection_backend_v1.py" + - "src/quant_engine/kis_data_collection_v1.py" + - "tests/unit/test_data_collection_store_v1.py" + - "tools/generate_postgresql_upgrade_stub_v1.py" + verification_commands: + - "python -m pytest tests/unit/test_data_collection_store_v1.py -q" + - "python -m py_compile src/quant_engine/kis_data_collection_v1.py tools/run_kis_data_collection_v1.py" + - "python tools/generate_postgresql_upgrade_stub_v1.py" + + Q1_qualitative_sell_pipeline: + priority: MEDIUM + status: PLANNED + purpose: > + 비기계적 매도전략 파이프라인을 Gitea workflow + SQLite 시계열 + mock KIS 유효성 + 검증 + 사후 적중률 평가까지 일관된 계약으로 묶는다. + success_criteria: + expected_success_value: + mock_api_validation: "PASS" + pipeline_contract: "PASS" + workflow_present: true + schedule_present: true + package_scripts_present: true + evidence_artifacts: + - ".gitea/workflows/qualitative_sell_strategy.yml" + - "tools/validate_qualitative_sell_strategy_pipeline_v1.py" + - "Temp/qualitative_sell_strategy_pipeline_v1.json" + verification_commands: + - "python tools/validate_qualitative_sell_strategy_pipeline_v1.py" + + Q2_gitea_secrets_contract: + priority: HIGH + status: PLANNED + purpose: > + Gitea workflow에서 KIS mock/real 자격증명과 GITHUB_TOKEN 시크릿 이름을 + 정확히 고정해, 수동 등록 실수로 인한 파이프라인 붕괴를 방지한다. + success_criteria: + expected_success_value: + secrets_contract: "PASS" + workflow_secret_mapping: "PASS" + docs_present: true + ci_validation_present: true + evidence_artifacts: + - "docs/GITEA_SECRETS_SETUP.md" + - "tools/validate_gitea_secrets_contract_v1.py" + - "Temp/gitea_secrets_contract_v1.json" + verification_commands: + - "python tools/validate_gitea_secrets_contract_v1.py" + # 2026-05-30 구현 현황 # - S5_etf_raw: PARTIAL_DONE 유지 (수동 NAV 병행) # - Stage2_Gate PENDING: T+20 표본 누적 후 자동 평가