ee3e799de1
주요 변경: - 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>
358 lines
25 KiB
YAML
358 lines
25 KiB
YAML
meta:
|
||
title: "은퇴자산포트폴리오 — 데이터 원천·완성도·검증 명세"
|
||
parent_file: "RetirementAssetPortfolio.yaml"
|
||
version: "2026-05-15-F1_modular"
|
||
language: "ko-KR"
|
||
timezone: "Asia/Seoul"
|
||
purpose: "메인 manifest에서 로드되는 구조화 규칙 명세 파일."
|
||
|
||
quant_feed_contract:
|
||
primary_raw_json:
|
||
file: "GatherTradingData.json"
|
||
source_workbook: "GatherTradingData.xlsx"
|
||
role: "provided_raw_analysis_data_json"
|
||
priority: "highest_user_provided_market_data"
|
||
schema_version: "2026-05-18-json-raw-data-v1"
|
||
required_paths:
|
||
- "data.data_feed"
|
||
- "data.sector_flow"
|
||
- "data.macro"
|
||
- "data.event_risk"
|
||
- "data.core_satellite"
|
||
conversion_tool: "tools/convert_xlsx_to_json.py"
|
||
usage_rule:
|
||
- "종목 후보, 가격, 수급, 섹터 흐름, 매크로, 이벤트 위험은 이 JSON을 1차 raw 데이터로 사용한다."
|
||
- "xlsx는 GAS/Google Sheets 원본·감사·JSON 재생성 소스이며 일반 LLM 분석에서 직접 파싱하지 않는다."
|
||
- "공개 웹 조회는 JSON 누락·오래됨·충돌 검산용 보조 소스다."
|
||
- "JSON 값과 웹 조회 값이 충돌하면 data_rule.conflict_action을 적용하고 평균값을 사용하지 않는다."
|
||
validation_tool: "tools/validate_data_sample_json.py"
|
||
mapping_file: "spec/14_raw_workbook_mapping.yaml"
|
||
account_snapshot_contract: "spec/15_account_snapshot_contract.yaml"
|
||
prohibition:
|
||
- "JSON이 제공된 상태에서 웹 데이터만으로 종목 점수·수량을 확정하지 않는다."
|
||
- "JSON에 없는 필드를 LLM이 임의 생성하지 않는다."
|
||
- "JSON 검증 실패 상태에서 BUY·SELL 수량을 확정하지 않는다."
|
||
source_priority:
|
||
0: "사용자 제공 raw 데이터: 'GatherTradingData.json'.data[core_satellite,event_risk,macro,sector_flow,data_feed]"
|
||
1: "AI 직접 공개 데이터 조회: Naver Finance, Yahoo Finance, KRX, OpenDART"
|
||
2: "사용자 제공 원자료: HTS, 증권사, FnGuide, KRX, 네이버금융 화면"
|
||
3: "부록 자동화 산출물: 공개 URL·기준시각·필드 의미 검증된 경우에만"
|
||
account_holdings_snapshot:
|
||
file: "사용자 캡처/원장 자료"
|
||
usage: "계좌별 보유수량·평단·평가금액·현금 raw 원장. Quantity·Avg_Cost·Cash_Available 없이 정수 주문수량 산출 금지."
|
||
prohibition:
|
||
- "공개 데이터로 보유수량·평단·현금을 추정하지 않는다."
|
||
- "ticker_master·data_feed.csv에 있다는 이유로 실제 보유 중이라고 단정하지 않는다."
|
||
- "자동투자 화면 월 적립금액을 잔고·보유수량으로 환산하지 않는다."
|
||
screen_type_separation:
|
||
canonical_ref: "spec/00_execution_contract.yaml:capture_read_ledger.screen_type_rule"
|
||
note: "[XREF / proposal_120] 이 섹션 대신 capture_read_ledger.screen_type_rule을 읽는다."
|
||
image_extraction_rules:
|
||
label_first_principle: "화면 내 숫자를 먼저 읽지 않는다. 숫자 왼쪽 또는 위쪽 라벨을 먼저 확인하고 계좌·항목을 특정한 뒤에만 값을 추출한다."
|
||
exclude_screens:
|
||
if_contains_any: ["투자내역 상세", "회차당 투자금액", "투자 회차", "모으기 신청일", "다음 투자(예정)일", "한도설정금액", "한도사용금액", "납입가능금액", "ISA 가입 정보", "isa 10년투자", "10년 연금저축", "매월 1일 투자"]
|
||
action: "CAPTURE_PROVIDED_BUT_NOT_HOLDINGS로 분류하고 예수금 판독 제외"
|
||
direct_cash_read:
|
||
rule: "총금액 - 평가금액 계산 방식은 사용"
|
||
required_confirmation:
|
||
- "어떤 계좌(일반계좌/ISA/연금저축)의 예수금인지 라벨로 먼저 확인"
|
||
- "'예수금' 또는 '주문가능금액' 라벨 확인 후 값 추출"
|
||
- "원화(원) 단위 확인"
|
||
validation: "예수금 >= 0 확인. 상식 범위 벗어나면 판독 재확인 요청."
|
||
|
||
direct_public_lookup:
|
||
steps:
|
||
- "KRX: 상장상태·시장구분·가격·거래대금·시가총액·투자자별 거래"
|
||
- "OpenDART: 공시 원문·실적·계약·증자·CB/BW·지분변동 촉매·리스크"
|
||
- "Naver Finance: 가격 보조·거래대금·외국인·기관 5D/20D 순매매"
|
||
- "Yahoo Finance: OHLC 보조·ATR20·20/60거래일 수익률"
|
||
rule: "모든 숫자에 기준일·기준시각·출처·데이터태그 필수. [웹확인:출처명] 또는 [계산값] 태그."
|
||
|
||
investor_flow_rules:
|
||
source: "'GatherTradingData.json'.data.data_feed, 'GatherTradingData.json'.data.core_satellite, Naver Finance frgn 또는 KRX 투자자별 거래 직접 조회"
|
||
accepted_fields: ["Frg_5D(sh)", "Inst_5D(sh)", "Frg_20D(sh)", "Inst_20D(sh)", "Ind_5D(sh)", "Flow_Rows", "Flow_Unit=shares", "Flow_OK"]
|
||
individual_flow:
|
||
field: "Ind_5D(sh) — 개인 5D 순매수(주식수)"
|
||
purpose: "과열 경보 및 수급 우위 확신도 보조 확인. A등급 gating 조건에는 포함하지 않는다."
|
||
scoring_rules:
|
||
high_conviction: "Frg_5D↑ + Inst_5D↑ + Ind_5D↓ → 스마트머니 집중·개인 이탈. 수급 우위 확신도 상향."
|
||
caution_signal: "Frg_5D↓ + Inst_5D↓ + Ind_5D↑ → 개인 쏠림 경계. 신규 진입 시 과열 위험 표시."
|
||
late_cycle: "외인·기관·개인 모두 순매수 → 추세 후반부 가능성. 추격매수 주의."
|
||
not_required: "Ind_5D(sh)가 DATA_MISSING이어도 Flow_OK 판정에는 영향 없음."
|
||
caution:
|
||
- "Flow_OK=Y가 아니면 외국인·기관 수급 점수 0점."
|
||
- "Flow_Rows<20이면 20D 수급 판단 금지."
|
||
- "주식 수 단위 수급을 금액 수급으로 임의 환산 금지."
|
||
- "Frg_20D(M), Inst_20D(M)은 legacy 더미 컬럼이므로 사용 금지."
|
||
- "Ind_5D(sh)는 보조 경보 필드다. 개인 순매수라는 이유만으로 A등급 하향 또는 매도 결정 금지."
|
||
active_quality_gate:
|
||
# [Q4 / 2026-05-15] C1/C2/C3 시간 기준 미명시로 LLM이 모두 5D로 오산출하거나
|
||
# C3의 5D 합산을 "당일" 수급으로 오독하는 할루시네이션 방지.
|
||
formula: "flow_credit = C1 × 0.30 + C2 × 0.30 + C3 × 0.40"
|
||
time_scope_summary: "C1·C2는 당일 단일 바 기준, C3는 최근 5거래일 누적 기준. 혼용 금지."
|
||
components:
|
||
C1_price_action:
|
||
time_scope: "당일 단일 바 (종가 vs 시가, 또는 종가 vs 전일 종가)"
|
||
definition: "당일 종가가 시가 이상(양봉) 또는 전일 대비 상승 시 1점, 미충족 시 0점"
|
||
weight: 0.30
|
||
C2_volume_action:
|
||
time_scope: "당일 거래량 vs 최근 5거래일 평균거래량 (AvgVolume_5D_shares 단위 — 주식 수. AvgTradeValue_5D_M 억원 단위 혼용 금지)"
|
||
definition: "당일 거래량이 최근 5일 평균의 120% 이상 시 1점, 미충족 시 0점"
|
||
weight: 0.30
|
||
C3_flow_action:
|
||
time_scope: "최근 5거래일 누적 순매수 (Frg_5D_sh + Inst_5D_sh 합산. 주식 수 단위)"
|
||
definition: "외국인+기관 합산 5D 순매수 양수 시 1점, 미충족 시 0점"
|
||
weight: 0.40
|
||
tier_threshold:
|
||
대형: "5D평균거래대금 >= 1,000억 → 기관 합산 순매수 50K주/일 이상 확인 권고"
|
||
중형: "5D평균거래대금 100억~1,000억 → 10K주/일 이상"
|
||
소형ETF: "5D평균거래대금 < 100억 → 2K주/일 이상"
|
||
pass_condition: # [P130] 예외 조건 구조화 — 문자열 매몰 제거
|
||
full_credit:
|
||
threshold: "flow_credit >= 0.70"
|
||
action: "수급 가점 100% 부여"
|
||
partial_credit:
|
||
threshold: "0.40 <= flow_credit < 0.70"
|
||
action: "수급 가점 30%만 인정"
|
||
override_to_reject:
|
||
condition: "C1 == 0 AND C2 == 0"
|
||
action: "reject 처리 (C3 단독 충족 = 물량 받기로 간주)"
|
||
reject:
|
||
threshold: "flow_credit < 0.40"
|
||
also_reject_if: "C1 == 0 AND C2 == 0 (flow_credit 수치 무관)"
|
||
action: "수급 점수 0점. kelly.brake_conditions 발동 검토."
|
||
prohibition:
|
||
- "주가 하락 중 기계적 순매수만 유입되는 '물량 받기' 종목을 A등급으로 추천 금지"
|
||
- "C3만 충족(C1·C2 모두 0점)인 경우 flow_credit 수치에 관계없이 reject 처리"
|
||
- "flow_credit 미산출 상태에서 수급 기반 A등급 부여 금지"
|
||
|
||
data_completeness_gate:
|
||
buy_ready: "identity·price_value·investor_flow(20D)·volatility_atr·momentum_value_surge 모두 OK, DATA_CONFLICT 없음 → A등급·즉시매수 검토"
|
||
watch_only: "identity·price_value만 OK → C-관찰까지"
|
||
field_status:
|
||
OK: "원시값·기준일·출처·단위 모두 확인"
|
||
PARTIAL: "일부 행·기간만 확인"
|
||
DATA_MISSING: "Plan A/B/C까지 모두 실패"
|
||
DATA_CONFLICT: "출처 간 수치 불일치"
|
||
NOT_APPLICABLE: "ETF·신규상장 등 구조적 미해당"
|
||
fallback_ladder:
|
||
ATR20: "Naver 일별시세(sise_day.naver) 21거래일 OHLC로 계산. Naver 실패 시 KRX 또는 보조 Yahoo로 전환. ATR20_OK=Y는 21거래일 OHLC 원시행 확인 시에만."
|
||
investor_flow: "Naver 실패 → KRX 투자자별 거래"
|
||
trading_value: "KRX 거래대금 또는 Close×Volume 계산값"
|
||
mandatory_collection_sequence: ["①종목코드·상장상태", "②가격·거래량·거래대금", "③5D 수급", "④20D 수급", "⑤21거래일 OHLC로 ATR20·MA20·Val_Surge 계산", "⑥52주 고저·목표가 참고", "⑦OpenDART 공시 촉매·리스크", "⑧필드 완성도 매트릭스 출력 후 등급·매매 판단"]
|
||
prohibition:
|
||
- "필드 완성도 매트릭스 없이 종목 등급 또는 매수·매도 결론 먼저 작성 금지."
|
||
- "로컬 파일 부재를 분석 중단 사유로 사용 금지."
|
||
- "자동화 실패와 공개 직접 조회 실패를 같은 의미로 사용 금지."
|
||
|
||
data_maturity_truth_gate:
|
||
objective: "데이터 형식 완성도와 실전 성숙도를 분리한다."
|
||
required_outputs:
|
||
- "data_integrity_score"
|
||
- "data_maturity_score"
|
||
- "pending_critical_category_count"
|
||
- "pending_critical_categories"
|
||
maturity_penalty_rule: "PENDING 카테고리는 분모 제외가 아니라 maturity penalty로 반영한다."
|
||
report_rule:
|
||
- "보고서 첫 섹션에 data_integrity_score와 data_maturity_score를 함께 표시한다."
|
||
- "data_integrity_score=100이어도 pending_critical_category_count>0이면 PASS_100 문구를 쓰지 않는다."
|
||
|
||
json_analysis_protocol:
|
||
purpose: "GatherTradingData.json에서 시장 raw 분석 데이터를 빠르게 파싱해 data_completeness_matrix와 판단 입력으로 사용."
|
||
python_parsing_baseline:
|
||
shell_rule: "PowerShell에서는 Bash heredoc 금지. '@ ... @ | python -' 형식으로 실행."
|
||
json_load_rule: "json.loads(Path('GatherTradingData.json').read_text(encoding='utf-8'))를 기본값으로 사용."
|
||
required_top_level: ["metadata", "data"]
|
||
required_schema_version: "2026-05-18-json-raw-data-v1"
|
||
required_paths: ["data.data_feed", "data.sector_flow", "data.macro", "data.event_risk", "data.core_satellite"]
|
||
code_column_rule:
|
||
text_columns: ["Ticker", "ETF_Code", "Proxy_Ticker", "Base_Ticker", "Constituent_Code", "ETF_Ticker", "Symbol", "ticker"]
|
||
normalization: "숫자로 읽힌 91160.0, 5930.0 등은 문자열화 후 6자리 zero-pad 적용."
|
||
validation_commands: ["npm run validate-data-sample", "npm run validate-specs"]
|
||
xlsx_refresh_rule: "xlsx 원본을 갱신했으면 npm run convert-data-json 실행 후 JSON을 다시 검증한다."
|
||
xlsx_analysis_protocol:
|
||
purpose: "xlsx는 HTS 잔고·거래내역 판독 또는 raw JSON 재생성 감사를 위한 보조 프로토콜이다. 시장 raw 일반 분석은 json_analysis_protocol을 우선한다."
|
||
python_parsing_baseline:
|
||
shell_rule: "PowerShell에서는 Bash heredoc 금지. '@ ... @ | python -' 형식으로 실행."
|
||
openpyxl_read_rule: "값 점검은 openpyxl.load_workbook(path, data_only=True, read_only=True)를 기본값으로 사용."
|
||
header_rows:
|
||
gas_output_sheets: "대부분 row1=updated 메타, row2=헤더, row3부터 데이터."
|
||
universe: "row1=헤더, row2부터 데이터."
|
||
settings: "key-value 구조. 일반 row2 헤더 시트로 오인 금지."
|
||
row_count_rule: "ws.max_row는 서식 범위 때문에 3000일 수 있으므로 데이터 행 수로 사용 금지. 첫 컬럼 또는 핵심 키 컬럼 non-empty 행만 센다."
|
||
code_column_rule:
|
||
text_columns: ["Ticker", "ETF_Code", "Proxy_Ticker", "Base_Ticker", "Constituent_Code", "ETF_Ticker", "Symbol"]
|
||
normalization: "숫자로 읽힌 91160.0, 5930.0 등은 문자열화 후 6자리 zero-pad 적용."
|
||
access_rule: "열 번호 하드코딩 금지. 헤더 행에서 header_map을 만든 뒤 컬럼명으로 접근."
|
||
validation_commands: ["npm run validate-xlsx-source", "npm run convert-data-json", "npm run validate-data-sample", "npm run validate-specs"]
|
||
temporary_sheet_rule: "cs_chunk_N은 core_satellite_status.Status=COMPLETE AND Coverage_Pct>=99.9일 때만 삭제 가능."
|
||
sheet_diet_policy:
|
||
canonical_required: ["data_feed", "sector_flow", "macro", "event_risk", "core_satellite"]
|
||
retained_support:
|
||
- "settings"
|
||
- "account_snapshot"
|
||
- "sector_universe"
|
||
- "sector_flow_history"
|
||
- "etf_nav_manual"
|
||
- "universe"
|
||
- "monthly_history"
|
||
- "performance"
|
||
deprecated_sheets:
|
||
- "positions"
|
||
- "chat_input"
|
||
- "etf_raw"
|
||
- "core_satellite_status"
|
||
- "orbit_gap"
|
||
- "asset_history"
|
||
transient_delete_when_complete: ["cs_chunk_N"]
|
||
rules:
|
||
- "orbit_gap·asset_history는 monthly_history(16컬럼)로 통합됐다."
|
||
- "etf_raw는 GAS in-memory map 전환으로 시트 쓰기 중단."
|
||
- "core_satellite_status는 ScriptProperties로 이전."
|
||
- "cs_chunk_N은 core_satellite 병합 완료 후 삭제해 workbook 비대화를 방지한다."
|
||
step_1_file_classification:
|
||
types:
|
||
holdings_xlsx: "보유종목·수량·평단·현금 포함 → CAPTURE_READ_OK"
|
||
transaction_xlsx: "거래내역·체결가·수수료 포함 → CAPTURE_READ_OK (거래 검증용)"
|
||
step_2_column_mapping:
|
||
label_first_principle: "셀 값보다 헤더 행(보통 1~3행)을 먼저 읽어 컬럼 의미를 확정."
|
||
required_columns_for_holdings: ["계좌명 또는 계좌번호", "종목명 또는 종목코드", "보유수량(주)", "평균단가(원/주)", "현재가(원/주)", "평가금액(원)", "예수금 또는 주문가능금액(원)"]
|
||
unit_validation:
|
||
quantity: "정수. 소수 발견 시 PARSE_FAILED."
|
||
price: "원/주. 단위 확인 불가 시 DATA_CONFLICT."
|
||
amount: "원. 총금액과 단가×수량 오차 1% 초과 시 DATA_CONFLICT."
|
||
step_3_data_validation:
|
||
cross_check:
|
||
- "평가금액 = 보유수량 × 현재가. 오차 0.5% 초과 시 DATA_CONFLICT."
|
||
- "예수금 = 총평가금액 - 보유종목 합산 평가금액 (단순 검증)."
|
||
hard_stop:
|
||
- "헤더 행 없거나 빈 파일 → PARSE_FAILED."
|
||
- "수량 열 전체 공백 → unknown_xlsx로 강등."
|
||
- "통화 단위가 달러($) → 환율 확인 전 금액 산출 금지."
|
||
step_4_ledger_integration:
|
||
rule: "유효성 검사 통과 후 capture_read_ledger에 기재."
|
||
ledger_row_format: "[파일화면, 계좌, 화면종류, 읽은값, 확신도, 주문표반영, 판독상태]"
|
||
step_5_prohibited:
|
||
- "research_xlsx의 컨센서스·목표가만으로 보유수량·평단 대체 금지."
|
||
- "xlsx의 수익률 컬럼을 실현수익률로 단정 금지 (미실현 포함 여부 불명)."
|
||
- "여러 xlsx가 동일 종목 다른 수량 제공 시 → DATA_CONFLICT, 최신 파일 우선 후 사용자 확인."
|
||
- "거래내역 xlsx를 잔고 xlsx로 오인 금지."
|
||
step_6_supplementary_types:
|
||
fnguide_consensus_xlsx: "컨센서스 참고용. 보유수량·주문수량 산출 금지."
|
||
trading_history_xlsx: "실현손익 검증용. 잔고 보유수량 추정 사용 금지."
|
||
|
||
ticker_master:
|
||
status: "dynamic_reference_from_latest_account_snapshot"
|
||
scope: "첨부 잔고·계좌 원장에서 확인된 보유 종목의 코드 매핑. 후보 유니버스나 고정 보유 목록 사용 금지."
|
||
refresh_rule: "최신 계좌 자료에 없는 종목은 보유종목으로 출력 금지. 최신 자료에 새 종목은 KRX 코드 확인 후 임시 매핑."
|
||
prohibited_use: ["있다는 이유로 보유 중 단정", "없다는 이유로 분석 제외", "위성 후보 추출 유니버스로 사용"]
|
||
|
||
data_rule:
|
||
canonical: true # [proposal_122 / 2026-05-15] 투자 판단 시 이 섹션의 rules가 최우선. data_snapshot_precedence·anti_hallucination보다 우선.
|
||
supersedes: ["data_snapshot_precedence.conflict_rule", "anti_hallucination.precedence"]
|
||
required_label: "모든 숫자에 기준시각·출처·데이터유형 표시"
|
||
data_tags: ["[사용자입력]", "[웹확인:출처명]", "[판독값]", "[계산값]", "[데이터누락]"]
|
||
priority: ["공식기관·거래소·중앙은행", "증권사·FnGuide", "네이버금융·포털"]
|
||
strict_unit_enforcement:
|
||
units: {shares: "주 (정수)", amount: "원 (정수)", ratio: "% (소수 2자리)", price: "원/주"}
|
||
allowed_transform:
|
||
- "amount = shares × price"
|
||
- "ratio = amount / capital × 100"
|
||
- "risk_amount = shares × (entry_price - stop_price)"
|
||
- "qty = floor(risk_amount_budget / risk_per_share)"
|
||
forbidden_transform:
|
||
- "shares + amount → 이종단위 합산 금지"
|
||
- "ratio + shares → 비율과 수량 혼합 금지"
|
||
- "price - ratio → 가격과 비율 뺄셈 금지"
|
||
hard_rule:
|
||
- "단위 미확인 시 해당 연산 결과는 산출 불가 처리. 주문수량 0주."
|
||
- "소수점 주 발생 시 floor() 적용. 반올림 금지."
|
||
rule: "모든 연산 시 단위(원, 주, %)를 교차 검증하며, 이종 단위(예: 수량과 금액)의 산술 연산 시도는 즉시 차단하고 산출 불가 처리한다."
|
||
raw_json_trade_value_rule:
|
||
preferred: "AvgTradeValue_5D_KRW, AvgTradeValue_20D_KRW"
|
||
legacy: "AvgTradeValue_5D_M, AvgTradeValue_20D_M"
|
||
legacy_unit: "million KRW"
|
||
transform: "legacy_value * 1000000"
|
||
prohibition: "AvgTradeValue_*_M을 억원 단위로 해석 금지."
|
||
rules:
|
||
- "첨부 이미지·잔고표·거래내역의 확인값만 사용. 불명확 숫자는 판독불가."
|
||
- "필수 입력 누락 시 정확한 수익률·계좌별 금액·매수수량·세후성과 산출 금지."
|
||
- "미확인 수치는 핵심 근거 제외, 점수 산정 시 0점."
|
||
- "기준시각이 다른 데이터는 직접 비교 금지."
|
||
- "사용자가 공개 화면에서 복사한 수치는 종목코드·항목명·단위·기준시각이 함께 있을 때만 [사용자입력]으로 인정."
|
||
freshness_gate:
|
||
price_max_age_trading_days: 1
|
||
flow_max_age_trading_days: 2
|
||
consensus_max_age_calendar_days: 14
|
||
macro_max_age_calendar_days: 3
|
||
stale_action: {price: "정수수량 산출 금지", flow: "수급 점수 0점", consensus: "실적 점수 50%만 인정", macro: "market_context 기반 가중 판단 금지"}
|
||
conflict_action: "DATA_CONFLICT 표시. A등급·즉시매수·정수수량 산출 금지."
|
||
alignment_gate:
|
||
purpose: "가격·수급·공시 기준시각이 혼재된 상태에서 매수 신호 산출을 차단한다."
|
||
required_fields: ["as_of_date(price)", "as_of_date(flow)", "as_of_date(disclosure)"]
|
||
alignment_rule: "주문 산출 시 price와 flow의 as_of_date 차이가 1거래일 초과이면 DATA_STALE 처리."
|
||
DATA_STALE_action:
|
||
- "정수 수량·손절가·익절가·기대수익비 산출 금지"
|
||
- "관찰가(진입 후보가) 표기만 허용"
|
||
- "다음 확인 출처와 갱신 예정 시각을 함께 표기"
|
||
exception: "macro 데이터는 시장 국면 판단에만 사용. 개별 종목 주문 산출에는 price/flow alignment 기준만 적용."
|
||
prohibition: "DATA_STALE 상태에서 최신 price와 구형 flow를 조합해 A등급 산출 금지."
|
||
|
||
anti_hallucination:
|
||
role: "supplementary" # [proposal_122 / 2026-05-15] 종목 진위 확인·수치 검증 용도로만 사용. 우선순위는 data_rule.
|
||
krx_listing_integrity:
|
||
required_before_recommendation: ["종목코드 또는 표준코드", "정식 종목명", "시장구분", "상장상태", "기준일", "데이터 출처"]
|
||
hard_reject: ["KRX 공식 종목마스터 미확인 상품", "AI 생성 유사 종목명·존재하지 않는 테마형 ETF명", "코드 없는 ETF 추천"]
|
||
historical_price_integrity:
|
||
required: ["OHLC 원시데이터 또는 차트의 기준일·주기·수정주가 여부", "고가/종가 기준 명시", "액면분할·병합·권리락 확인"]
|
||
rule: "두 출처의 고점이 다르면 DATA_CONFLICT 표시 후 수량 산출 보류. 추세 돌파 판단에는 종가 확인 필수."
|
||
mathematical_cross_check:
|
||
formula: "conflict_rate = abs(Source_A - Source_B) / max(abs(Source_A), abs(Source_B), 1)"
|
||
field_thresholds:
|
||
price: "0.005 (0.5%) — 호가 정밀도 기준. 초과 시 즉시 DATA_CONFLICT"
|
||
volume: "0.10 (10%) — 집계 단위 차이 허용 범위"
|
||
flow_5d: "0.15 (15%) — 기관/외국인 순매수 집계 오차 허용"
|
||
atr20: "0.10 (10%) — ATR 계산 기준일 차이 허용"
|
||
target_price: "0.20 (20%) — 컨센서스 목표가 분산 허용"
|
||
action:
|
||
pass: "임계치 이내 → source_priority 상위 소스 사용, 하위 소스는 보조 검산값으로 기록"
|
||
fail: "임계치 초과 → DATA_CONFLICT, 해당 종목 신규 매수·매도 수량 산출 금지"
|
||
fallback_rule:
|
||
- "두 소스 충돌 시 평균값 사용 금지. source_priority 상위 소스만 사용."
|
||
- "세 소스 이상 충돌 시 중앙값 대신 출처 신뢰도 우선순위 적용."
|
||
- "신뢰도 동률이면 DATA_CONFLICT로 보류 후 사용자 재확인 요청."
|
||
rule: "두 출처의 수치 오차율이 field_thresholds를 초과할 경우, DATA_CONFLICT 처리 및 수량 산출 보류. 기존 1% 단일 임계치는 field_thresholds로 대체."
|
||
precedence: "→ data_rule.priority 참조 (data_rule이 canonical)"
|
||
|
||
market_context:
|
||
required_fields:
|
||
macro: ["KOSPI", "KOSDAQ", "USD/KRW", "VIX", "미국 10년물", "미국 HY OAS", "국내 CP/CD 스프레드", "WTI/Brent"]
|
||
macro_sheets_source: "macro 탭 → Category=Index(KOSPI·KOSDAQ·S&P500), Category=Risk(VIX), Category=FX(USD/KRW), Category=Bond(미국10년물), Category=Commodity(WTI)"
|
||
leadership: ["주도섹터 1M/3M 상대수익률", "외국인·기관 5D/20D 수급", "거래대금", "52주 신고가"]
|
||
leadership_sheets_source: "sector_flow 탭 → Sector_Ret5D/Sector_Ret20D(상대수익률), SmartMoney_5D_KRW/SmartMoney_20D_KRW(수급), Alert_Level·Sector_Score(리더십판단)"
|
||
benchmark: ["KOSPI 시총 상위 비중", "삼성전자+SK하이닉스 KOSPI 비중", "포트폴리오 반도체 실질노출"]
|
||
benchmark_sheets_source: "data_feed 탭 → 삼성전자(005930)·SK하이닉스(000660) Frg_5D/Inst_5D로 수급 확인 후 비중 판단"
|
||
regime_response:
|
||
Risk-On: "분할 집행 허용, 추격매수 금지"
|
||
실적장세: "컨센서스 상향·수급 확인 종목 우선"
|
||
Risk-Off: "신규 위험자산 축소, cash_floor 상향"
|
||
Credit-Stress: "위성·중복 ETF·수급 이탈 종목부터 축소"
|
||
guardrails:
|
||
- "벤치마크 비중 없으면 주도주 초과비중 판단은 DATA_MISSING."
|
||
- "신용스프레드 데이터 없으면 credit stress 발동 금지."
|
||
- "뉴스 단독으로 위성 전량청산 금지. 가격·수급·신용 중 2개 이상 확인 필요."
|
||
|
||
liquidity_execution_audit:
|
||
required_fields: ["최근 5D/20D 평균거래대금", "주문금액", "주문금액/5D평균거래대금(%)", "호가단위·지정가", "예상 세금·수수료", "예상 순현금"]
|
||
pass_condition:
|
||
normal_stock: "주문금액이 5D 평균거래대금의 0.25% 이하"
|
||
etf: "주문금액이 5D 평균거래대금의 0.5% 이하이며 괴리율·스프레드 과도하지 않음"
|
||
hard_gate:
|
||
spread_unknown: "호가스프레드 미확인 시 신규매수 금지. 매도도 시장가 금지, 분할 지정가만 허용. 코어는 주문금액 50% 감액."
|
||
spread_too_wide: "예상 스프레드+슬리피지가 목표 기대수익의 20% 초과 시 A등급 금지."
|
||
volume_pressure: "주문수량이 20D 평균거래량의 1% 초과 시 최소 3회 분할 또는 보류."
|
||
thin_book: "호가 공백 3틱 이상 또는 장중 거래대금 급감 시 시장가 금지."
|
||
missing_policy:
|
||
- "평균거래대금 없으면 주문금액 제시 가능하나 체결가능성은 PARTIAL 표기."
|
||
- "예상금액은 지정가 하한 × 수량에서 세금·수수료 차감 전/후 분리."
|