880 lines
41 KiB
YAML
880 lines
41 KiB
YAML
meta:
|
||
title: 데이터 갭 로드맵 — 단계별 보완 계획
|
||
version: 2026-06-21-platform-transition-v1
|
||
language: ko-KR
|
||
purpose: '의사결정 파이프라인(spec/09_decision_flow.yaml)에서 식별된 데이터 공백을 우선순위별로 정리하고, 단계별
|
||
구현 계획을 명시한다. GAS 수집 → spec 공식 → LLM 판단 순서로 각 갭의 의존성을 추적한다.
|
||
|
||
'
|
||
has_code_implementation: true
|
||
code_path:
|
||
- spec\16_data_gaps_roadmap.yaml
|
||
phase_1_completed:
|
||
G1_KOSPI_MA60:
|
||
status: DONE
|
||
implementation: fetchYahooOhlcMetrics → macro 탭 MA60 컬럼
|
||
enables: RISK_ON 판정 조건 KOSPI_MA20 >= KOSPI_MA60
|
||
G2_KOSPI_KOSDAQ_Ret10D:
|
||
status: DONE
|
||
implementation: fetchYahooOhlcMetrics → macro 탭 Ret10D
|
||
enables: 'daily_leader_scan C2: Ret10D_종목 - Ret10D_KOSPI'
|
||
G3_ETF_Ret10D:
|
||
status: DONE
|
||
implementation: fetchYahooPrice → sector_flow ETF_Ret10D
|
||
enables: 'RW2 상대약세: Ret10D_종목 - Ret10D_주도섹터ETF'
|
||
G4_USD_JPY_Ret2D:
|
||
status: DONE
|
||
implementation: calcDerivedPriceMetrics.ret2D → macro 탭 Ret2D (USD_JPY행)
|
||
enables: 'MRS usd_jpy_score: Ret2D <= -1 → +1점'
|
||
G5_credit_stress_proxy:
|
||
status: DONE
|
||
implementation: HYG ETF Ret5D → REGIME_PRELIM 행 credit_stress 필드
|
||
enables: MRS credit_score 자동 계산
|
||
limitation: HYG는 미국 HY proxy. 한국 신용스프레드 직접 수집은 3단계 과제.
|
||
G6_Rotation_Rank:
|
||
status: DONE
|
||
implementation: runSectorFlow 정렬 후 Rotation_Rank 컬럼
|
||
enables: C5 Rotation_Score 순위 <= 3 판단, RW1 섹터 순위 변화 추적
|
||
S4_MRS_auto_compute:
|
||
status: DONE
|
||
implementation: runMacro 내 MARKET_RISK_SCORE_V1 계산 → macro 탭 MRS_COMPUTED 행
|
||
enables: LLM이 macro 탭 한 번 읽어 MRS 즉시 확인 가능
|
||
phase_2_structural:
|
||
S1_trades_performance_sheet:
|
||
priority: HIGH
|
||
status: DONE
|
||
purpose: 'Bayesian multiplier (high/medium/low/no_bet) 및 net_expectancy 산출 기반.
|
||
미구현 시 bayesian_confidence는 항상 medium_confidence(0.5×) 고정.
|
||
|
||
'
|
||
required_columns:
|
||
- trade_id
|
||
- ticker
|
||
- sector
|
||
- entry_date
|
||
- entry_price
|
||
- entry_stage
|
||
- quantity
|
||
- stop_price_at_entry
|
||
- target_price_at_entry
|
||
- exit_date
|
||
- exit_price
|
||
- exit_reason
|
||
- pnl_pct
|
||
- holding_days
|
||
- entry_c1_score
|
||
- entry_c2_score
|
||
- entry_c3_score
|
||
- entry_c4_score
|
||
- entry_c5_score
|
||
- entry_mrs_score
|
||
- fc_bucket
|
||
derived_outputs:
|
||
- win_rate (최근 30건)
|
||
- avg_win_pct
|
||
- avg_loss_pct
|
||
- net_expectancy = (win_rate × avg_win_pct) - (loss_rate × avg_loss_pct)
|
||
- bayesian_confidence_multiplier 자동 결정
|
||
implementation_plan:
|
||
step_1: Google Sheets에 'performance' 탭 수동 생성
|
||
step_2: spec/17_performance_contract.yaml 계약서 작성
|
||
step_3: GAS에 performance 탭 읽기 함수 추가 → Bayesian multiplier 자동 계산
|
||
step_4: runDataFeed 내 bayesian_multiplier 필드 → data_feed 탭 추가
|
||
implementation_note: '2026-05-17 구현 완료. spec/17_performance_contract.yaml 신규 작성.
|
||
readPerformanceSheet_() GAS 함수 추가. EE_Est 계산에 Bayesian multiplier 반영. macro
|
||
탭 BAYESIAN_COMPUTED 행으로 상태 출력.
|
||
|
||
'
|
||
S2_stop_price_tracking:
|
||
priority: HIGH
|
||
status: DONE
|
||
purpose: 'TOTAL_HEAT_V1 계산 필수 입력값. 미구현 시 HF005(Total_Heat 10% 차단) 미작동. stop_price
|
||
없으면 포트폴리오 총 위험노출 계산 불가.
|
||
|
||
'
|
||
required_fields_per_position:
|
||
- ticker
|
||
- account
|
||
- average_cost
|
||
- stop_price
|
||
- holding_quantity
|
||
- last_updated
|
||
implementation_plan:
|
||
step_1: account_snapshot에 stop_price/highest_price_since_entry/last_updated
|
||
선택 컬럼 추가
|
||
step_2: spec/15_account_snapshot_contract.yaml에 account_snapshot_position_state
|
||
추가
|
||
step_3: 'GAS: account_snapshot 기반 TOTAL_HEAT 및 trailing stop 갱신'
|
||
interim_workaround: 'stop_price 미기록 시 STOP_PRICE_CORE_V1 공식으로 ATR 기준 추정: stop_price_est
|
||
= average_cost - ATR20 × 1.5 Total_Heat_est = sum((average_cost - stop_price_est)
|
||
× holding_quantity) / total_asset × 100
|
||
|
||
'
|
||
implementation_note: '2026-05-18 account_snapshot 통합 완료. positions_tab은 deprecated.
|
||
readAccountSnapshotHeat_() GAS 함수 추가 (ATR 추정 폴백 포함). macro 탭 TOTAL_HEAT 행으로
|
||
HF005 상태 출력.
|
||
|
||
'
|
||
S3_sector_flow_weekly_history:
|
||
priority: MEDIUM
|
||
status: DONE
|
||
implementation: 'option_B legacy interim 구현 완료 (2026-05-17). sector_flow 탭에 Prev_Rotation_Rank(W1),
|
||
Prev_Rotation_Rank_W2 컬럼 추가. W1 = sector_flow 시트에서 직전 실행 결과 읽기. W2 = PropertiesService[''sf_w2_ranks_json'']
|
||
캐시 (직전 실행 시 저장). RW1·RW3 컬럼이 sector_flow 탭에 자동 계산됨 → data_feed RW1·RW3 컬럼으로
|
||
전파.
|
||
|
||
'
|
||
enables: 'RW1 ''2주 연속 섹터 순위 3순위 이상 하락'' 자동 판단. RW3 ''외국인+기관 5D 순매도 2주 연속'' 자동
|
||
판단.
|
||
|
||
'
|
||
note: '2회 이상 실행 후 W1/W2 데이터가 축적되어야 RW1·RW3가 작동한다. 단, 이는 전회 실행 기준 legacy interim이며
|
||
주간 스냅샷 기반 sector_flow_history는 후속 Phase 4 과제다.
|
||
|
||
'
|
||
S4_sector_flow:
|
||
priority: HIGH
|
||
status: DONE
|
||
implementation: '2026-05-17 Phase 1-2 구현. sector_universe 원장 또는 DEFAULT_SECTOR_UNIVERSE_V2를
|
||
canonical source로 사용하고, 구성종목 수급을 수량 단순합산이 아닌 원화금액×가중치로 sector_flow에 집계한다. Coverage_Weight,
|
||
SmartMoney_5D_KRW, SmartMoney_5D_Norm, Flow_Breadth_5D, Data_Quality, Decision_Use를
|
||
추가했다. sector_universe 시트가 없으면 기본 템플릿을 생성하며, Is_ETF=Y 구성행은 ETF 자체 수급 혼입을 막기 위해
|
||
섹터 smart money 집계에서 제외한다.
|
||
|
||
'
|
||
limitation: 'KRX/KIND 기반 NAV/괴리율/추적오차/AUM 수집은 아직 미구현이며 etf_raw에서 ETF_NAV_Risk=NAV_DATA_MISSING으로
|
||
명시한다.
|
||
|
||
'
|
||
next_review_date: '2026-09-30'
|
||
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
|
||
status: DATA_GATED
|
||
implementation: '2026-05-17 Phase 3 interim 구현. etf_raw 시트를 신설하고 ETF proxy/ETF
|
||
구성행에 대해 Close, Bid, Ask, Spread_Pct, AvgTradeValue_5D_KRW, AvgTradeValue_20D_KRW,
|
||
ETF_Frg_5D_KRW, ETF_Inst_5D_KRW, ETF_Liquidity_Score, ETF_Liquidity_Status를
|
||
산출한다. NAV_DATA_MISSING 상태에서는 ETF_Execution_Use=WATCH_ONLY로 표시해 ETF 매매 실행 근거와
|
||
섹터 수급 근거를 분리한다. 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'
|
||
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
|
||
status: DONE
|
||
implementation: '2026-05-17 Phase 4 interim 구현. sector_flow_history 시트에 Snapshot_Date+Sector
|
||
기준으로 sector_flow 누적 스냅샷을 upsert한다. sector_flow의 RW1/RW3 계산은 sector_flow_history를
|
||
우선 사용하고, 이력이 부족할 때만 기존 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
|
||
|
||
S8_kis_open_api_token_cache:
|
||
priority: HIGH
|
||
status: DONE
|
||
purpose: KIS Open API access token을 호출마다 재발급하지 않고 SQLite 캐시로 재사용한다.
|
||
required_fields:
|
||
- access_token
|
||
- expires_at
|
||
- updated_at
|
||
implementation_plan:
|
||
step_1: 토큰 캐시를 수집 DB와 분리된 SQLite 파일로 저장한다.
|
||
step_2: TOKEN_REFRESH_SKEW_MINUTES=10 기준으로 기존 토큰을 재사용한다.
|
||
step_3: 동시 호출 시 토큰 재발급을 직렬화한다.
|
||
step_4: DB 오버라이드 경로를 환경변수로 노출한다.
|
||
step_5: 토큰 캐시 상태를 조회하는 진단 CLI를 제공한다.
|
||
implementation_note: '2026-06-23 구현 완료. src/quant_engine/kis_api_client_v1.py가 Temp/kis_tokens.db를 기본 캐시로 사용하고, KIS_TOKEN_DB_PATH로 오버라이드 가능하다. 갱신 임계값은 TOKEN_REFRESH_SKEW_MINUTES=10이며, tools/inspect_kis_token_cache_v1.py로 상태를 조회한다.'
|
||
phase_3_enhancement:
|
||
A1_daily_leader_scan_auto:
|
||
priority: MEDIUM
|
||
status: DONE
|
||
implementation: 'P1(2026-05-17) 구현 완료. runDataFeed 루프 내 C1~C5 자동 계산. data_feed
|
||
탭: C1_Price, C2_RelStr, C3_VolSurge, C4_Flow, C5_Sector, Leader_Scan_Total,
|
||
Leader_Gate.
|
||
|
||
'
|
||
output_columns:
|
||
- C1_Price
|
||
- C2_RelStr
|
||
- C3_VolSurge
|
||
- C4_Flow
|
||
- C5_Sector
|
||
- Leader_Scan_Total
|
||
- Leader_Gate
|
||
A2_eps_growth_3y_cagr:
|
||
priority: MEDIUM
|
||
status: DONE
|
||
implementation: '2026-05-17 구현 완료. fetchYahooConsensusEps() 확장. Yahoo earningsTrend
|
||
+1y의 earningsEstimate.growth.raw 직접 추출. 없으면 (+1y avg - 0y avg) / abs(0y avg)
|
||
× 100 으로 계산. data_feed 탭 EPS_Growth_1Y_Pct 컬럼 추가 → LLM이 PEG = Forward_PE / EPS_Growth_1Y_Pct
|
||
계산 가능.
|
||
|
||
'
|
||
accuracy_note: 1년 성장률 추정치 (3Y CAGR 완전 대체 불가). KOSDAQ PEG 게이트에서 fallback보다 정확.
|
||
A3_pct_from_52w_low:
|
||
priority: LOW
|
||
status: DONE
|
||
purpose: Low52W 대비 현재가 반등률 — 저점 대비 위치 파악 (눌림 구간 분석)
|
||
expression: (Close / Low52W - 1) × 100
|
||
implementation: data_feed 탭 Pct_From_52W_Low 컬럼 (2026-05-17)
|
||
A4_ex_dividend_date:
|
||
priority: LOW
|
||
status: DONE
|
||
implementation: '2026-05-17 구현 완료. fetchYahooTargetPrice() 확장 (추가 API 호출 없음).
|
||
calendarEvents.exDividendDate → data_feed Ex_Dividend_Date, Days_To_Ex_Div 컬럼.
|
||
defaultKeyStatistics.lastDividendValue → data_feed DPS 컬럼.
|
||
|
||
'
|
||
A6_pos_size_qty:
|
||
priority: HIGH
|
||
status: DONE
|
||
implementation: '2026-05-17 구현 완료. data_feed Pos_Size_Qty 컬럼: POSITION_SIZE_V1
|
||
간략 버전 자동 계산. atr_qty = floor(total_asset × 0.007 × bayesian_multiplier / (ATR20
|
||
× 1.5)) weight_qty = floor(total_asset × 0.05 / Close) Pos_Size_Qty = min(atr_qty,
|
||
weight_qty). requires: settings 탭 total_asset_krw 입력. limitation: "cash/sector/liquidity
|
||
한도는 account_snapshot 필요. 현재는 ATR+weight 한도만 적용."
|
||
|
||
'
|
||
A7_stop_price_actual:
|
||
priority: HIGH
|
||
status: DONE
|
||
implementation: '2026-05-17 구현 완료. data_feed Stop_Price_Est: account_snapshot
|
||
실제 stop_price 우선 → ATR 추정 폴백. Stop_Price_Source 컬럼: "account_snapshot" / "ATR추정"
|
||
표시. EE_Est가 실제 stop_price 기반으로 계산됨 (포지션 있는 종목).
|
||
|
||
'
|
||
A8_settings_tab:
|
||
priority: HIGH
|
||
status: DONE
|
||
implementation: '2026-05-17 구현 완료. readSettingsTab_() GAS 함수 추가. settings 탭: key-value
|
||
구조 (key, value, note 컬럼). total_asset_krw: Pos_Size_Qty, TOTAL_HEAT_V1, FC_BUDGET
|
||
계산에 사용. spec/18_settings_contract.yaml 계약서 작성.
|
||
|
||
'
|
||
A9_fc_budget_tracking:
|
||
priority: MEDIUM
|
||
status: DONE
|
||
implementation: '2026-05-17 구현 완료. calcFcBudget_() GAS 함수 추가. performance 탭 fc_bucket=Y
|
||
거래 중 당월 청산 손실 집계. macro 탭 FC_BUDGET 행 추가: used_pct / 2.5% 예산 상태 출력. exhausted
|
||
시 LLM이 신규 stage_1 탐색 자동 억제 가능.
|
||
|
||
'
|
||
A5_kosdaq_vs_ma20:
|
||
priority: LOW
|
||
status: DONE
|
||
purpose: 'kosdaq_regime_supplement 규칙: KOSDAQ_Close < KOSDAQ_MA20 → MRS +1'
|
||
implementation: runMacro MRS 계산에 kosdaqSupp 로직 추가. macro 탭 KOSDAQ (^KQ11) 이미 수집
|
||
중 (2026-05-17)
|
||
analysis_enhancements:
|
||
B1_rw_signal_checklist:
|
||
purpose: RW1~RW5 자동 계산 및 출력
|
||
current_status:
|
||
RW1: ✅ sector_flow RW1 컬럼 자동 계산 (2026-05-17). Prev_Rotation_Rank(W1)+W2 PropertiesService
|
||
캐시 기반. 2회 이상 실행 후 정확.
|
||
RW2: ✅ data_feed RW2 컬럼 자동 계산 (2026-05-17). Ret10D - ETF_Ret10D <= -5%p
|
||
RW3: ✅ sector_flow RW3 컬럼 자동 계산 (2026-05-17). 외국인+기관 5D 순매도 2주 연속 (현재+W1 비교).
|
||
RW4: ✅ data_feed RW4 컬럼 자동 계산 (2026-05-17). AvgTradeValue_5D/20D <= 0.60
|
||
RW5: ✅ data_feed RW5 컬럼 자동 계산 (2026-05-17). Close < MA20 AND < MA60
|
||
RW_Partial: ✅ data_feed RW_Partial = RW1+RW2+RW3+RW4+RW5 합계 (0~5)
|
||
fully_automated:
|
||
- RW1 (2회 이상 실행 후)
|
||
- RW2
|
||
- RW3 (현재+W1 기준)
|
||
- RW4
|
||
- RW5
|
||
note: RW1·RW3의 '2주 연속' 조건은 2회 이상 실행 후 W1/W2 데이터 축적 시 완전히 정확해짐.
|
||
B2_total_heat_estimation:
|
||
purpose: stop_price 미기록 시 ATR 기준 Total_Heat 추정
|
||
formula: "For each holding in account_snapshot:\n stop_price_est = entry_price\
|
||
\ - ATR20 × 1.5\n heat_contribution = (entry_price - stop_price_est) × quantity\
|
||
\ / total_asset × 100\nTotal_Heat_est = sum(heat_contribution)\n"
|
||
requirement: ATR20(data_feed), entry_price(account_snapshot), quantity(account_snapshot),
|
||
total_asset(account_snapshot) 필요
|
||
note: actual stop_price가 있으면 실제값 우선. 없으면 이 추정으로 HF005 체크 가능.
|
||
B3_expected_edge_checklist:
|
||
purpose: EXPECTED_EDGE_V1 계산 전 필수 입력 확인
|
||
required_fields:
|
||
- 'target_price: data_feed Target_Price (Naver 또는 Yahoo) ✓'
|
||
- 'entry_price: limit_price (entry_core.yaml limit_price_formula) ✓'
|
||
- 'stop_price: stop_price_est (B2 또는 실제값) △'
|
||
- 'bayesian_confidence_multiplier: performance 시트 기반 (S1) — 미구현 시 0.5× 기본'
|
||
- 'execution_cost_rate: 0.003 고정 ✓'
|
||
B4_c2_now_computable:
|
||
purpose: daily_leader_scan C2 바로 계산 가능
|
||
formula: Ret10D_종목(data_feed) - Ret10D_KOSPI(macro) >= 3%p
|
||
status: G2 완료로 계산 가능. LLM이 두 탭 조회 후 즉시 판단.
|
||
B5_mrs_now_readable:
|
||
purpose: MRS 자동 계산 결과 macro 탭에서 직접 읽기
|
||
location: macro 탭 Symbol='MRS_COMPUTED' 행 → Close=점수, Status='score=X/10 cash=Y%'
|
||
usage: LLM이 macro 탭을 읽으면 MRS 재계산 없이 즉시 확인 가능
|
||
B6_flow_credit_v1_auto:
|
||
purpose: FLOW_CREDIT_V1 자동 계산 — data_feed Flow_Credit 컬럼
|
||
status: DONE
|
||
implementation: '2026-05-17 구현 완료. runDataFeed 루프 내 자동 계산. fc_c1: close >= open
|
||
OR close > prevClose → 0.30 fc_c2: volume >= avgVolume5D × 1.20 → 0.30 fc_c3:
|
||
flow_ok AND (frg5 + inst5) > 0 → 0.40 Hard override: C1=0 AND C2=0 → 0 (C3 단독
|
||
충족은 물량받기로 간주)
|
||
|
||
'
|
||
output_column: data_feed Flow_Credit (0.00~1.00)
|
||
B7_trailing_stop_price_auto:
|
||
purpose: TRAILING_STOP_PRICE_V1 자동 계산 — account_snapshot 최고가 기반
|
||
status: DONE
|
||
implementation: '2026-05-18 account_snapshot highest_price_since_entry 읽기/쓰기 통합
|
||
완료. trailingStopPrice = highest_price_since_entry - ATR20 × 1.5 account_snapshot에
|
||
highest_price_since_entry 미입력 시 공백.
|
||
|
||
'
|
||
output_column: data_feed Trailing_Stop_Price (KRW 정수)
|
||
B8_ss001_score_auto:
|
||
purpose: SS001 종목 점수 자동 계산 — 6개 축 + 총점 + 등급
|
||
status: DONE
|
||
implementation: '2026-05-17 구현 완료. runDataFeed 루프 내 자동 계산. SS001_P: core_satellite
|
||
RS_Pct_20D → percentile=100-RS_Pct_20D → ≤30=25pt/30~60=15pt/>60=0pt SS001_V:
|
||
avgTradingValue5D/20D 비율 → ≥120%=15pt/80~120%=8pt/<80%=0pt SS001_F: Flow_Credit
|
||
→ ≥0.70=25pt/0.40~0.70=12pt/<0.40=0pt SS001_E: EPS_Revision_Status → UP=20pt/FLAT=10pt/DOWN=0pt
|
||
SS001_M: REGIME_PRELIM(전회 macro 결과) → RISK_ON/LEADER_CONCENTRATION=10pt/NEUTRAL=5pt/기타=0pt
|
||
SS001_VAL: KOSPI→PER/PBR vs 섹터중앙값(max 5pt), KOSDAQ→PEG 기반(max 12pt) SS001_Total:
|
||
6개 합산 (KOSPI max 100, KOSDAQ max 107) SS001_Grade: 100점 환산 ≥80=A / ≥65=B / ≥50=C
|
||
/ <50=D
|
||
|
||
'
|
||
output_columns:
|
||
- SS001_P
|
||
- SS001_V
|
||
- SS001_F
|
||
- SS001_E
|
||
- SS001_M
|
||
- SS001_VAL
|
||
- SS001_Total
|
||
- SS001_Grade
|
||
data_dependency:
|
||
SS001_P: core_satellite 탭 RS_Pct_20D 컬럼 (runCoreSatelliteFinalize 필요)
|
||
SS001_M: 전회 runMacro 실행 결과 (초회 실행 시 0점)
|
||
SS001_VAL: sector_flow Sector_Median_PE/PBR (runSectorFlow 필요)
|
||
limitation: SS001_P는 core_satellite 탭이 비어있으면 0점 처리. 처음 사용 시 runCoreSatellite 먼저
|
||
실행.
|
||
B9_peg_gate_auto:
|
||
purpose: PEG 게이트 자동 계산 (KOSDAQ 종목 전용)
|
||
status: DONE
|
||
implementation: '2026-05-17 구현 완료. KOSDAQ_TICKERS Set 상수 추가 (현재 비어있음 — 보유 종목 모두
|
||
KOSPI). KOSDAQ 종목에서 EPS_Growth_1Y_Pct > 0 이면: PEG = Forward_PE / EPS_Growth_1Y_Pct
|
||
PEG_Gate: PASS(≤1.5) / CAUTION(1.5~2.5) / REJECT(>2.5) EPS 성장률 미수집 시: Fallback
|
||
→ sector_median_PE 대비 Forward_PE 배수로 대체
|
||
|
||
'
|
||
output_columns:
|
||
- PEG
|
||
- PEG_Gate
|
||
B10_full_market_regime:
|
||
purpose: MARKET_REGIME_V1 완전 판정 — macro+sector_flow 통합
|
||
status: DONE
|
||
implementation: '2026-05-17 구현 완료. runMacro() 내에서 sector_flow 탭 읽기 추가. (runSectorFlow()가
|
||
sector_flow 기록 완료 후 runMacro()가 호출되므로 최신값 읽기 가능) 판정 우선순위: RISK_OFF > SECULAR_LEADER_RISK_ON
|
||
> LEADER_CONCENTRATION > RISK_ON > NEUTRAL > RISK_OFF_CANDIDATE RISK_OFF: MRS>=7
|
||
OR (VIX>=25 AND KOSPI<MA20) SECULAR_LEADER_RISK_ON: LEADER_CONCENTRATION + top1=반도체
|
||
+ VIX<22 + KOSPI>MA20 LEADER_CONCENTRATION: top2_sum>=100 AND top1_score>=55
|
||
AND top1_alertScore>=2 AND Tier1섹터 AND Ret20D>0 AND VIX<25 RISK_ON: VIX<18 AND
|
||
KOSPI>MA20 AND (MA20>=MA60 OR Ret20D>0) AND (sfFrg20>0 OR sfInst20>0 OR top2sum>=100)
|
||
NEUTRAL: MRS<=5 그 외 RISK_OFF_CANDIDATE: MRS 5~6
|
||
|
||
'
|
||
output: REGIME_PRELIM 행 Close 컬럼 (Symbol=REGIME_PRELIM 유지 — 하위 호환)
|
||
note: '이전 값이 ''RISK_ON_CANDIDATE'', ''RISK_OFF_CANDIDATE''이던 것이 ''RISK_ON'', ''RISK_OFF''로
|
||
변경됨. SS001_M 점수 계산이 이제 정상 작동 (이전엔 항상 0점이었음).
|
||
|
||
'
|
||
B11_net_return_feedback:
|
||
purpose: net_return_feedback 상태 자동 계산 — RISK_BUDGET_CASCADE_V1 입력
|
||
status: DONE
|
||
implementation: "2026-05-17 구현 완료. runMacro() 내 bayesianInfo(performance 탭) 재사용.\
|
||
\ 규칙 (spec/05_position_sizing.yaml:net_return_feedback):\n trades < 20건: NORMAL\
|
||
\ (규칙 미적용)\n ne <= -2%: REDUCED — base_risk 0.007→0.003 삭감 권고\n ne <= 0%:\
|
||
\ CAUTION — high_confidence 금지, multiplier 0.5× 강제\n 연속손실 ≥5건 (bayesian no_bet와\
|
||
\ 별개로): NORMAL→CAUTION 승격\n 그 외: NORMAL\n"
|
||
output: macro 탭 NET_RETURN_FEEDBACK 행 (Symbol=NET_RETURN_FEEDBACK, Close=상태값)
|
||
C1_orbit_gap_tracking:
|
||
purpose: orbit_gap 자동 계산 — 월별 목표궤도 vs 실제 자산 추이 추적
|
||
status: DONE
|
||
implementation: '2026-05-17 구현 완료. spec/01_objective_profile.yaml:orbit_monthly_tracker
|
||
구현. calcOrbitGap_(settings) 함수: 기하평균 보간으로 목표누적수익률 계산. orbit_gap(%) = ((target/start)^(elapsed/total)
|
||
- 1) - (current/start - 1) orbit_state: significantly_behind(>3%p) / mild_behind(1~3%p)
|
||
/ on_track / ahead_of_target(<-2%p) offensive_slot_adj: significantly_behind=+2,
|
||
mild_behind=+1, on_track=0, ahead=0 cash_floor_adj: significantly_behind=-2%p,
|
||
mild_behind=-1%p, on_track=0, ahead=+1%p runOrbitGap(): orbit_gap 탭에 현재 월 행
|
||
추가/갱신 (월 1회 독립 트리거) runMacro(): ORBIT_GAP + ORBIT_STATE 2개 행 macro 탭에 자동 기록
|
||
|
||
'
|
||
required_settings:
|
||
- orbit_start_asset_krw — 시작 자산 (1월 기준)
|
||
- 'orbit_target_asset_krw — 목표 자산 (예: 5억)'
|
||
- 'orbit_start_yyyymm — 추적 시작 연월 (예: 2026-01)'
|
||
- 'orbit_end_yyyymm — 목표 달성 기한 (예: 2028-12)'
|
||
- total_asset_krw — 현재 자산 (기존 settings 항목 재사용)
|
||
output:
|
||
macro_tab: ORBIT_GAP 행(Close=gap %p), ORBIT_STATE 행(Close=상태, Status=slot/cash
|
||
조정값)
|
||
orbit_gap_tab: Month/Start_Asset/Target_Asset/Actual_Asset/Target_Return_Pct/Actual_Return_Pct/Orbit_Gap_Pct/Orbit_State/Slot_Adj/Cash_Floor_Adj/Updated
|
||
api_exposure:
|
||
getMacroJson: orbit_gap_pct, orbit_state, orbit_slot_adj, orbit_cash_adj
|
||
getSummaryJson: macro_snapshot.orbit_gap_pct, orbit_state, orbit_slot_adj
|
||
limitation: settings 탭에 4개 orbit_* 파라미터 미입력 시 ORBIT_GAP=N/A 기록 (runOrbitGap 스킵)
|
||
C2_take_profit_ladder:
|
||
purpose: TAKE_PROFIT_LADDER_V1 자동 계산 — core/satellite 분리 익절 사다리
|
||
status: DONE
|
||
implementation: '2026-05-18 account_snapshot average_cost + holding_quantity +
|
||
position_type 기반으로 변경. core: TP1=+15%(25% 물량), TP2=+25%(잔여 40% 물량). satellite:
|
||
TP1=+10%(50% 물량), TP2=+20%(잔여 50% 물량). Time_Stop: stage_1=60일, stage_2=30일 (entry_date
|
||
기준 만료일 + 잔여일수).
|
||
|
||
'
|
||
output_columns:
|
||
data_feed:
|
||
- TP1_Price
|
||
- TP1_Qty
|
||
- TP2_Price
|
||
- TP2_Qty
|
||
- Time_Stop_Date
|
||
- Days_To_Time_Stop
|
||
required_account_snapshot_fields:
|
||
- average_cost
|
||
- holding_quantity
|
||
- position_type
|
||
- entry_date
|
||
- entry_stage
|
||
C3_position_monitoring:
|
||
purpose: 포지션 모니터링 컬럼 자동 계산 — 비중/수익률/PnL/스테이지/밴드
|
||
status: DONE
|
||
implementation: "2026-05-18 account_snapshot + 당일 종가 기반으로 변경. Weight_Pct: close\
|
||
\ × quantity / total_asset_krw × 100. Profit_Pct: (close - entry_price) / entry_price\
|
||
\ × 100. Unrealized_PnL: (close - entry_price) × quantity (KRW 정수). Stage2_Gate:\
|
||
\ stage_1 포지션에서 가격 +1.5% 이상 시 PASS, 아니면 PENDING. Band_Status: satellite 단일종목\
|
||
\ 7% 상한. OVERWEIGHT/IN_BAND/UNDERWEIGHT.\n core는 CORE_HIGH(>10%)/CORE_MID(3~10%)/CORE_LOW(<3%).\n"
|
||
output_columns:
|
||
data_feed:
|
||
- Weight_Pct
|
||
- Profit_Pct
|
||
- Unrealized_PnL
|
||
- Stage2_Gate
|
||
- Band_Status
|
||
D1_bucket_allocation_status:
|
||
purpose: 포트폴리오 버킷 할당 상태 자동 계산 — core/satellite/cash 합계 vs 목표 범위
|
||
status: DONE
|
||
implementation: '2026-05-17 구현 완료. runDataFeed 루프에서 버킷별 Weight_Pct 누산. calcBucketStatus_()
|
||
함수: _bucketSnapshot_ 기반 bucket-level 집계. 목표 범위 (spec/risk): core 60-72%, satellite
|
||
10-25%, cash 10-22%. cash_pct = max(0, 100 - core_pct - satellite_pct) (추정값
|
||
— account_snapshot 미연동). overall: BALANCED / core_UNDERWEIGHT | sat_OVERWEIGHT
|
||
등 파이프 구분.
|
||
|
||
'
|
||
output:
|
||
macro_tab: BUCKET_STATUS 행(Close=overall, Status=core/sat/cash 상세)
|
||
api_exposure:
|
||
getMacroJson: bucket_status, bucket_detail
|
||
getSummaryJson: macro_snapshot.bucket_status, bucket_detail
|
||
limitation: 'cash_pct는 account_snapshot 마켓밸류를 total_asset에서 뺀 추정값. 실제 현금은 account_snapshot
|
||
없이 확인 불가. runDataFeed 실행 없이 runMacro만 실행하면 N/A.
|
||
|
||
'
|
||
phase_4_backdata_collection:
|
||
B1_gas_backdata_feature_bank:
|
||
priority: HIGH
|
||
status: DONE
|
||
purpose: '매수/매도 뒷북과 설거지 패턴을 줄이기 위한 진입-청산 백데이터 원장. 사람 입력보다 GAS 자동 수집을 1순위로 두고,
|
||
사람이 입력한 performance 기록은 보조 검증용 fallback으로만 사용한다.
|
||
|
||
'
|
||
collection_priority:
|
||
1: GAS가 생성한 backdata_feature_bank 시트/JSON
|
||
2: performance 시트의 청산 완료 거래
|
||
3: 수동 보정값
|
||
required_signals:
|
||
- entry_stage
|
||
- entry_leader_scan_total
|
||
- entry_c1_score
|
||
- entry_c2_score
|
||
- entry_c3_score
|
||
- entry_c4_score
|
||
- entry_c5_score
|
||
- entry_mrs_score
|
||
- entry_close_vs_ma20_pct
|
||
- entry_volume_ratio_5d
|
||
- entry_flow_credit
|
||
- entry_breakout_score
|
||
- entry_late_chase_risk_score
|
||
- entry_follow_through_score
|
||
- pnl_pct
|
||
- holding_days
|
||
- max_adverse_excursion_pct
|
||
- max_favorable_excursion_pct
|
||
implementation_plan:
|
||
step_1:
|
||
action: GAS에서 daily setup snapshot을 backdata_feature_bank 시트로 자동 upsert
|
||
status: DONE
|
||
note: syncBackdataFeatureBank_() — gdc_01_fetch_fundamentals.gs:1128, gdf_02_harness_assembly.gs:146
|
||
step_2:
|
||
action: performance 시트 청산 결과와 join해 outcome label을 자동 부여
|
||
status: DONE
|
||
note: buildBackdataFeatureBankRowsV1_() — mapLatestPerformanceByTicker_ 기반
|
||
join
|
||
step_3:
|
||
action: convert_xlsx_to_json.py에서 backdata_feature_bank_json 우선 수집
|
||
status: DONE
|
||
note: src/quant_engine/convert_xlsx_to_json.py:synthesize_backdata_feature_bank()
|
||
구현
|
||
step_4:
|
||
action: backdata_feature_bank_table을 report/validation에 반영
|
||
status: DONE
|
||
note: render_operational_report.py:_backdata_feature_bank_table(), validate_harness_context.py
|
||
검증
|
||
fallback_policy:
|
||
manual_input: performance 시트 또는 수동 보정은 fallback일 뿐 primary source가 아니다.
|
||
missing_action: GAS 생성본이 없으면 fallback 기록과 함께 source_origin=FALLBACK_SYNTH로 남긴다.
|
||
implementation_note: '2026-06-14 구현 완료 확인. GAS(syncBackdataFeatureBank_) + Python(synthesize_backdata_feature_bank)
|
||
모두 구현됨. T+20 데이터 누적 후 ML 패턴 학습 품질 향상 예정.
|
||
|
||
'
|
||
phase_5_platform_transition:
|
||
P1_kis_core_api_collector:
|
||
priority: HIGH
|
||
status: DONE
|
||
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: DONE
|
||
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: DONE
|
||
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
|
||
notes: '`GatherTradingData.xlsx`는 runtime seed 재생성 fallback으로만 허용한다. collector
|
||
본문은 `GatherTradingData.json`만 사용하며, xlsx는 Prepare Raw Seed Snapshot 단계에서만
|
||
허용된다.
|
||
|
||
'
|
||
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: DONE
|
||
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: DONE
|
||
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
|
||
phase_wbs_7_8_etf_nav_automation:
|
||
status: BLOCKED_TECHNICAL_BARRIER
|
||
wbs_ref: WBS-7.8
|
||
deadline: '2026-12-31'
|
||
problem_statement: 'ETF NAV, 괴리율, 추적오차, AUM 자동 수집이 미구현. 현재는 etf_nav_manual 탭에 수동
|
||
입력만 가능.
|
||
|
||
'
|
||
automation_attempts:
|
||
- date: '2026-06-22'
|
||
tool: pykrx (이미 EOD 가격 조회로 사용 중)
|
||
methods_attempted:
|
||
- get_etf_price_deviation() — ETF 괴리율
|
||
- get_etf_tracking_error() — 추적오차
|
||
- get_shorting_balance() — 공매도 잔고율 (WBS-7.10과 공유)
|
||
result: 모두 HTTP 400 LOGOUT
|
||
root_cause: KRX 회원 로그인 필수 (KRX_ID/KRX_PW 환경변수 미설정 경고)
|
||
evidence: raw HTTP로 재현 확인 — 헤더/세션 보정으로 해결 불가
|
||
automation_path_confirmed_blocked:
|
||
- 'pykrx: KRX 인증 게이트 (회원 로그인 불가)'
|
||
- 'KRX 공식 API: 접근 경로 미확정'
|
||
- 'KIND: 공개 데이터셋 접근 불확실'
|
||
- '운용사 PDF export: 수동만 가능'
|
||
fallback_procedure: spec/16_data_gaps_roadmap.yaml:S5_etf_raw.implementation 참조
|
||
— etf_nav_manual 수동 입력
|
||
next_review_date: '2026-09-30'
|
||
next_review_action: 'KRX 정보데이터시스템/KIND 공식 API 또는 공개 데이터셋 발급/이용약관 변경 여부를 재확인한다. 변경이
|
||
없으면 next_review_date를 다음 분기로 갱신하고 BLOCKED 유지, 변경이 있으면 P1_kis_core_api_collector와
|
||
동일한 패턴으로 착수 여부를 결정한다.
|
||
|
||
'
|
||
implementation_note: '2026-06-22 WBS-7.8 기술장벽 최종 확정. 자동화 불가능하므로 운영절차를 명문화한다. etf_nav_manual
|
||
수동 경로 외에 대체 경로 없음.
|
||
|
||
'
|
||
phase_wbs_7_10_shorting_balance_automation:
|
||
status: MANUAL_CSV_ONLY
|
||
wbs_ref: WBS-7.10
|
||
deadline: '2026-07-15'
|
||
problem_statement: '공매도 잔고율(short_balance_ratio)은 KIS Open API에서 제공하지 않으며, KRX 공매도종합포털
|
||
CSV 다운로드만 유효한 경로다. 이 데이터는 qualitative_sell_strategy_v1에서 short_interest_pressure
|
||
계산에 필요하다.
|
||
|
||
'
|
||
data_source:
|
||
official: KRX 공매도종합포털 (data.krx.co.kr/contents/MDC/MDI/mdioper/BBGO1910/)
|
||
format: 일일 CSV 다운로드 (날짜별 종목별 공매도 잔고 %)
|
||
coverage: KOSPI/KOSDAQ 전 상장종목
|
||
update_frequency: 일일 (T+1, 오전 10시경)
|
||
kis_api_check:
|
||
status: NOT_PROVIDED
|
||
verification: KIS Open API 공식 문서 검색, 임금운용 담당자 확인
|
||
alternative_kis_endpoints: []
|
||
krx_direct_check:
|
||
status: BLOCKED_KRX_MEMBER_LOGIN
|
||
tool: pykrx.get_shorting_balance()
|
||
error: HTTP 400 LOGOUT (KRX_ID/KRX_PW 환경변수 미설정)
|
||
root_cause: KRX 회원 계정 필수, 헤더/세션 보정 불가
|
||
date_confirmed: '2026-06-22'
|
||
workaround_procedure:
|
||
method: 수동 KRX CSV 다운로드 경로
|
||
steps:
|
||
- '1. KRX 공매도종합포털 접속 (로그인 필요: 일반 계정, 증권회원사 계정, KRX 회원사 계정 모두 가능)'
|
||
- 2. '당일 공매도현황' 탭에서 종목 선택 또는 전체 다운로드
|
||
- '3. CSV 파일 저장: spec 문서에 기입된 경로 (예: Temp/shorting_balance_manual_YYYY-MM-DD.csv)'
|
||
- 4. build_qualitative_sell_inputs_v1.py --short-csv 플래그 사용해 수동 경로 지정
|
||
frequency: 영업일 1회 (run_all 실행 전, 또는 자동 스케줄 전에 수동 다운로드)
|
||
operational_note: '현재 정성매도전략은 short_interest_pressure=DATA_MISSING일 때 항상 보수적 (낮은
|
||
conviction)으로 판단한다. 공매도 데이터가 없으면 다른 4개 신호만 사용해 결정하므로, 영업 중단 가능성은 없다 — 다만 정밀도
|
||
제한.
|
||
|
||
'
|
||
cli_interface:
|
||
usage: python tools/build_qualitative_sell_inputs_v1.py --short-csv Temp/shorting_balance_manual_YYYY-MM-DD.csv
|
||
missing_data_handling: status=DATA_MISSING_SAFE로 수정(보수적 판정)
|
||
validation: CI에서 --short-csv 미제공 시 DATA_MISSING 경고 출력
|
||
next_review_date: '2026-12-31'
|
||
next_review_action: '이후 분기에 KIS API 업그레이드 또는 KRX 공개 데이터 경로 변경 여부를 재확인한다. 변경이 없으면
|
||
MANUAL_CSV_ONLY 상태 유지, 변경이 있으면 자동화 착수 여부를 결정한다.
|
||
|
||
'
|
||
implementation_note: '2026-06-22 WBS-7.10 기술장벽 최종 확정. 자동화 경로 불가능하므로 수동 CSV 운영절차를
|
||
governance/rules에 명문화한다.
|
||
|
||
'
|