a4de0505a0
3개 contract 파일 추가 태깅: - spec/00_execution_contract.yaml (execution_slippage + snapshot_admin) - spec/08_scoring_rules.yaml (score_thresholds + qualitative_sell) - spec/09_decision_flow.yaml (execution_decision + routing_decision) 결과: 36/162 파일 (22.22% coverage) 목표: 50% 이상 (점진적 확장) CI gate: PASS
581 lines
34 KiB
YAML
581 lines
34 KiB
YAML
meta:
|
||
title: "은퇴자산포트폴리오 — 최상위 실행 계약"
|
||
parent_file: "RetirementAssetPortfolio.yaml"
|
||
version: "2026-05-18-F8_p4_keyword_lock"
|
||
language: "ko-KR"
|
||
timezone: "Asia/Seoul"
|
||
role: "canonical"
|
||
has_code_implementation: true
|
||
code_path: ["src/quant_engine/execution_slippage_store_v1.py", "tools/run_snapshot_admin_server_v1.py"]
|
||
purpose: >
|
||
기존 llm_compact_execution_contract에서 제공하던 최상위 안전 계약을
|
||
모듈형 구조에 맞게 복원한 단일 권위 파일.
|
||
이 파일은 모든 spec보다 먼저 적용한다.
|
||
|
||
source_of_truth:
|
||
priority: "highest"
|
||
rule: "이 파일의 master_prohibitions, hard_stops, capture_read_ledger가 모든 하위 전략·점수·수량·출력 규칙보다 우선한다."
|
||
conflict_resolution:
|
||
risk_vs_strategy: "위험 차단 규칙과 매수/증액 규칙이 충돌하면 위험 차단 규칙만 적용한다."
|
||
data_vs_output: "데이터·수량·현금 검산이 실패하면 출력 형식이 완성되어도 주문은 금지한다."
|
||
table_vs_text: "표/수치/공식과 서술형 설명이 충돌하면 표/수치/공식을 우선한다."
|
||
tie_rule: "동급 규칙 충돌 시 보류하고 다음 확인 출처를 출력한다."
|
||
|
||
proposal_policy:
|
||
canonical: true
|
||
purpose: "사용자 판단용 제안 레이어와 HTS 즉시 실행 레이어를 분리한다."
|
||
rule:
|
||
- "가격·수량 산출 입력이 충족되면 시장 개장 여부와 무관하게 제안표를 유지한다."
|
||
- "실행 차단은 validation_status와 별도 실행가능여부 컬럼으로만 표현한다."
|
||
- "사용자 판단용 제안표와 HTS 즉시 입력 주문표를 같은 표로 섞지 않는다."
|
||
allow_proposal_when:
|
||
- "holding_quantity 또는 final_qty 입력이 존재"
|
||
- "prices_json 또는 동등한 하네스 가격 입력이 존재"
|
||
- "sell_quantities_json 또는 buy_qty_inputs_json이 존재"
|
||
block_execution_when:
|
||
- "intraday_lock = true"
|
||
- "snapshot_execution_gate != ALLOW_EXECUTION"
|
||
- "validation_status != PASS"
|
||
execution_status:
|
||
proposal_only: "제안 가능 / 즉시 HTS 입력 금지"
|
||
execution_wait: "제안 가능 / 추가 확인 후 실행"
|
||
execution_ready: "제안 가능 / 즉시 실행 가능"
|
||
proposal_price_selection:
|
||
canonical: true
|
||
rule:
|
||
sell_or_trim:
|
||
trigger: "final_action in [SELL_READY, SELL, TRIM, EXIT_100, EXIT_FULL] 또는 sell_quantities_json 존재"
|
||
proposed_limit_price_krw: "prices_json.stop_price 우선"
|
||
proposed_take_profit_price_krw: "prices_json.tp1_price가 유효하면 병기, 없으면 tp2_price"
|
||
note: "방어적 제안가를 우선 표시한다."
|
||
take_profit:
|
||
trigger: "tp_trigger_gate=TRIGGERED 또는 tp1_state/tp2_state=PENDING and final_action includes TAKE_PROFIT"
|
||
proposed_limit_price_krw: "prices_json.tp1_price 우선, 없으면 tp2_price"
|
||
proposed_stop_price_krw: "prices_json.stop_price 병기"
|
||
buy:
|
||
trigger: "final_action includes BUY 또는 buy_qty_inputs_json.final_qty 존재"
|
||
proposed_limit_price_krw: "order_blueprint_json.limit_price_krw 우선, 없으면 buy_qty_inputs_json.entry_price_hint"
|
||
proposed_stop_price_krw: "prices_json.stop_price"
|
||
proposed_take_profit_price_krw: "prices_json.tp1_price 우선"
|
||
watch_or_hold:
|
||
trigger: "final_action in [WATCH, HOLD]"
|
||
proposed_limit_price_krw: "주문가가 아니라 참고 방어가로 prices_json.stop_price 사용"
|
||
note: "WATCH/HOLD는 HTS 주문가가 아니라 판단 참고용 가격임을 명시"
|
||
proposal_quantity_selection:
|
||
canonical: true
|
||
rule:
|
||
sell_or_trim:
|
||
trigger: "final_action in [SELL_READY, SELL, TRIM, EXIT_100, EXIT_FULL] 또는 sell_quantities_json 존재"
|
||
proposed_quantity: "sell_quantities_json.sell_qty 우선"
|
||
note: "보유수량 기반 매도 제안 수량"
|
||
buy:
|
||
trigger: "final_action includes BUY 또는 buy_qty_inputs_json.final_qty 존재"
|
||
proposed_quantity: "buy_qty_inputs_json.final_qty 우선"
|
||
note: "하네스 산출 신규 매수 수량"
|
||
watch_or_hold:
|
||
trigger: "final_action in [WATCH, HOLD]"
|
||
proposed_quantity: "sell_quantities_json.sell_qty 존재 시 참고 수량으로 표시, 없으면 null"
|
||
note: "즉시 주문 수량이 아니라 판단 참고 수량"
|
||
proposal_stop_ladder_selection:
|
||
canonical: true
|
||
rule:
|
||
stop1:
|
||
price: "prices_json.stop_price"
|
||
quantity: "core=보유/제안수량의 50%, satellite=보유/제안수량의 70%"
|
||
rationale: "spec/exit/stop_loss.yaml core/satellite quantity_rule의 1차 손절 물량"
|
||
stop2:
|
||
price: "stop1과 동일한 prices_json.stop_price"
|
||
quantity: "잔여 수량 전부"
|
||
rationale: "종가 회복 실패 시 잔여 청산 규칙을 사용자 판단용 제안표에 명시"
|
||
stop3:
|
||
price: "profit_preservation_json.auto_trailing_stop 우선, 없으면 protected_stop_price"
|
||
quantity: "tp_quantity_ladder_json.tp3_qty 우선, 없으면 잔여 러너 수량"
|
||
trigger: "profit_lock_stage != NORMAL 또는 trailing stop 유효"
|
||
rationale: "수익보전 구간의 러너 보호 스탑을 별도 표기"
|
||
prohibition:
|
||
- "stop2/stop3 가격을 차트 지지선·심리적 가격으로 임의 산출 금지"
|
||
- "profit_preservation/trailing 근거가 없으면 stop3를 비워 둔다"
|
||
prohibition:
|
||
- "실행 차단을 이유로 제안 수량·단가 자체를 숨기지 않는다."
|
||
- "제안표를 HTS 즉시 입력표처럼 오인되게 렌더링하지 않는다."
|
||
|
||
canonical_terms:
|
||
immediate_cash: "당일 출금 가능 현금"
|
||
settlement_cash: "D+2 추정현금성자산"
|
||
buy_power_cash: "즉시현금 + D+2 추정현금성자산 - 예약된 주문금액"
|
||
cash_floor: "즉시현금 기준 방어선"
|
||
total_heat: "Σ(entry_price - stop_price) × quantity / 총자산 × 100"
|
||
source_failure: ["TRANSPORT_BLOCKED", "FETCH_FAILED", "PARSE_FAILED", "SCHEMA_MISMATCH", "ROW_NOT_FOUND", "FIELD_MISSING"]
|
||
data_gap: ["DATA_MISSING", "PARTIAL", "NOT_APPLICABLE"]
|
||
|
||
master_prohibitions:
|
||
canonical: true
|
||
P1_no_quantity_without_holdings:
|
||
rule: "보유수량 미확인 상태에서 매도수량 숫자 기재 금지."
|
||
fail_action: "NO_SELL_QUANTITY"
|
||
P2_no_atr_extrapolation:
|
||
rule: "ATR20 미확인 상태에서 정수 매수수량 산출 금지."
|
||
fail_action: "NO_BUY_QUANTITY"
|
||
P3_no_risk_block_override:
|
||
rule: "목표수익률, 공격슬롯, 주도주 논리를 이유로 cash_floor, Total_Heat, hard stop, circuit breaker를 완화하거나 우회 금지."
|
||
fail_action: "BUY_BLOCKED"
|
||
P4_no_intraday_speculation:
|
||
rule: >
|
||
[Intraday_Analysis_Restriction] 모든 정규 분석과 주문 산출은 16:30 장마감 종가를 기준으로 한다.
|
||
제공된 캡처(account_snapshot)나 데이터의 시각이 15:30 이전(장중)일 경우,
|
||
종가 이탈이 확정되지 않았으므로 '신규 매수'와 '조건부 전량 매도(손절 포함)' 지시를 절대 금지한다.
|
||
장중에는 오직 'TRIM(부분 감축)'이나 '현금 확보' 등 보수적 방어 액션만 허용된다.
|
||
fail_action: "INTRADAY_PROHIBITED"
|
||
keyword_lock:
|
||
trigger_condition: "account_snapshot.timestamp < 15:30 KST OR data_feed.timestamp < 15:30 KST"
|
||
blocked_keywords: ["EXIT_100", "SELL_FULL", "전량매도", "전량 매도", "EXIT_FULL"]
|
||
blocked_actions: ["hard_stop 사유 EXIT_100", "time_exit 사유 EXIT_100", "신규 BUY 주문"]
|
||
allowed_actions_only: ["TRIM_25", "TRIM_33", "TRIM_50", "현금 확보", "CASH_RAISE"]
|
||
auto_action: >
|
||
timestamp < 15:30 KST 확인 즉시 해당 리포트의 모든 EXIT_100·SELL_FULL 주문행을
|
||
validation_status=INTRADAY_PROHIBITED로 강등하고 주문표에서 제거한다.
|
||
hard_stop·time_exit 사유가 있어도 예외 없이 적용.
|
||
사유 컬럼에 "P4:장중캡처 → EXIT_100 차단, TRIM만 허용" 표기 필수.
|
||
cash_floor_trim_auto: # [2026-05-19_HARNESS_AUDIT_V1] H4
|
||
rule_id: "P4_CASH_TRIM"
|
||
trigger: "intraday_lock=true AND cash_floor_status IN [TRIM_REQUIRED, HARD_BLOCK]"
|
||
purpose: >
|
||
장중 현금 부족 상황에서 종가 대기 없이 즉시 TRIM으로 현금 확보.
|
||
LLM 임의 배정 금지 — 아래 공식으로만 수량 산출.
|
||
formula:
|
||
cash_shortfall_krw: "(target_cash_pct/100 - current_cash_pct/100) × total_asset [CASH_RATIOS_V1 기반]"
|
||
trim_qty_per_stock: "min(floor(remaining_shortfall_krw / current_price), holding_quantity)"
|
||
assignment_order: "sell_priority_engine 1순위부터 계단식. 잔여 부족 시 2순위로 이동."
|
||
output_format: >
|
||
TRIM {종목명} {qty}주 / 지정가 {현재가} [TICK_OK: {price}원]
|
||
사유: "P4+현금부족 → TRIM 자동배정. 신규BUY/EXIT_100 차단 유지."
|
||
[CASH_RAISE_AUTO: {qty}주 → 예상확보 {proceeds}원 / 부족액 {shortfall}원 중 {recovered}원 해소]
|
||
prohibition:
|
||
- "서사 설명으로 trim_qty 임의 결정 금지"
|
||
- "trim_qty 없이 '현금 확보 권장'만 출력 금지"
|
||
- "1순위 소진 전 2순위 배정 금지"
|
||
violation_example:
|
||
wrong: "15:09 KST 캡처 기반으로 현대로템 280주 EXIT_100 생성 → P4 위반"
|
||
correct: "15:09 KST 캡처 → EXIT_100 BLOCKED. 필요 시 TRIM_50(140주) 생성 후 15:30 이후 재분석 대기"
|
||
P5_no_fractional_share:
|
||
rule: "소수점 매수 금지. 모든 주문 수량은 정수."
|
||
fail_action: "ROUND_DOWN_OR_NO_QUANTITY"
|
||
P6_no_a_grade_without_data:
|
||
rule: "핵심 데이터 완성도 매트릭스 없이 A등급·즉시매수·정수수량 산출 금지."
|
||
fail_action: "MAX_GRADE_C_OR_INSUFFICIENT_DATA"
|
||
P7_price_formula_id_required:
|
||
rule: >
|
||
모든 가격(손절가·익절가·trailing_stop·보호스탑 등) 산출 시
|
||
spec/13_formula_registry.yaml에 등록된 공식 ID(산출공식_ID)를 반드시 명시.
|
||
미등록 레이블(예: "profit_lock_ratchet", "차트 지지선", "심리적 지지선",
|
||
"임의 하향")로 가격을 생성하는 행위 절대 금지.
|
||
등록된 가격 공식 ID: STOP_PRICE_CORE_V1, TRAILING_STOP_PRICE_V1,
|
||
TAKE_PROFIT_LADDER_V1, TAKE_PROFIT_LADDER_V2, PROFIT_LOCK_RATCHET_V1.
|
||
fail_action: "PRICE_FORMULA_REQUIRED — 산출공식_ID 미기재 가격은 HTS 입력 불가"
|
||
hard_stops:
|
||
canonical: true
|
||
rules:
|
||
- id: "HS001_CAPTURE_LEDGER_REQUIRED"
|
||
rule: "capture_read_ledger 표 없이 계좌·종목별 최종 주문수량 확정 금지."
|
||
- id: "HS002_AUTO_INVEST_SCREEN_NOT_HOLDINGS"
|
||
rule: "자동투자/약정 화면을 보유수량·평단·현금으로 사용 금지."
|
||
- id: "HS003_DATA_MATRIX_REQUIRED"
|
||
rule: "데이터 완성도 매트릭스 없이 매수·매도 결론 확정 금지."
|
||
- id: "HS004_BUY_SET_REQUIRED"
|
||
rule: "매수제안은 지정가·수량·손절가·손절수량·익절가·익절수량 세트가 모두 있어야 유효."
|
||
- id: "HS005_FLOW_ROWS_20D_REQUIRED_FOR_A"
|
||
rule: "Flow_Rows<20이면 20D 수급 기반 A등급·즉시매수 판단 금지."
|
||
- id: "HS006_TOTAL_HEAT_REQUIRED"
|
||
rule: "Total_Heat 미산출 상태에서 신규 매수 수량 산출 금지."
|
||
- id: "HS007_HTS_SINGLE_PRICE_ONLY"
|
||
rule: >
|
||
HTS 조건부 주문은 단일 이탈 가격 1개만 허용.
|
||
"XX원 이탈 또는 YY원 회복 실패 시", "두 조건 중 하나 도달 시",
|
||
"A 조건과 B 조건 동시 충족 시" 등 다중·복합 조건 주문을 플레이북에 산출 금지.
|
||
복수 조건이 필요한 시나리오는 "[수동확인 필요: 다중조건 HTS 미지원]" 표기로만 제시.
|
||
keyword_lock: "주문 조건 텍스트에 '또는', '동시 충족', '실패 시', '회복 실패', '돌파 실패' 포함 시 해당 행 INVALID_MULTI_CONDITION 처리"
|
||
- id: "HS008_TICK_NORMALIZED_REQUIRED"
|
||
rule: >
|
||
플레이북의 모든 지정가(매수·손절·익절·trailing_stop)는 TICK_NORMALIZER_V1을 거친
|
||
KRX 호가 단위 정규화 값이어야 한다.
|
||
소수점 포함 가격 또는 호가 단위 불일치 가격(예: 144,568원, 25,886원)은
|
||
HTS 입력 불가 오류로 판단하고 해당 행을 INVALID_TICK으로 표시한 뒤 정규화 후 재산출한다.
|
||
tick_table_ref: "spec/13_formula_registry.yaml:formula_registry.formulas.TICK_NORMALIZER_V1.tick_table"
|
||
- id: "HS009_TP_VALIDITY_CHECK_REQUIRED"
|
||
rule: >
|
||
prices_json의 tp1_price·tp2_price가 null이거나 tp1_state·tp2_state가
|
||
TP1_ALREADY_TRIGGERED·TP2_ALREADY_TRIGGERED이면 해당 가격은 INVALID_TP_STALE로 처리한다.
|
||
prices_lock=true이더라도 TP_VALIDITY_CHECK_V1이 우선하며, LLM이 대체 TP 가격을
|
||
임의 산출하는 것은 이 규칙으로 절대 금지한다.
|
||
fail_action: "INVALID_TP_STALE — HTS 주문표 기재 금지. GAS 재실행 필요."
|
||
formula_ref: "spec/13_formula_registry.yaml:TP_VALIDITY_CHECK_V1"
|
||
- id: "HS010_WATCH_BLOCKED_NULL_REQUIRED"
|
||
rule: >
|
||
order_blueprint_json에서 validation_status != 'PASS'인 행(WATCH, BLOCKED,
|
||
INSUFFICIENT_DATA 포함)의 stop_price_krw·stop_quantity·take_profit_price_krw·
|
||
take_profit_quantity는 반드시 null이어야 한다.
|
||
LLM이 참고용이라도 WATCH 행과 동일 주문표에 가격·수량 숫자를 기재하면
|
||
HS010 위반으로 해당 표 전체가 BLOCKED_ORDER_TABLE로 처리된다.
|
||
fail_action: "BLOCKED_ORDER_TABLE — WATCH 감시원장을 별도 섹션으로 분리 필수."
|
||
- id: "HS011_NO_LLM_FORMULA_DEFINITION"
|
||
rule: >
|
||
LLM은 spec/13_formula_registry.yaml에 등록된 공식 ID만 인용할 수 있다.
|
||
대화 중 새 알고리즘명(V3, V4, ENGINE, REBALANCE, ACTIONABLE_ 등)을 즉석 정의하고
|
||
이에 기반한 구체적 원화 가격 또는 정수 수량을 산출하는 것을 절대 금지한다.
|
||
하네스 미구현 영역은 "DATA_MISSING — 하네스 업데이트 필요"로만 표시하고 LLM 대체 계산 금지.
|
||
fail_action: "INVALID_UNREGISTERED_FORMULA — HTS 입력 금지. 해당 숫자 전부 무효."
|
||
tag_requirement: # [2026-05-19_HARNESS_AUDIT_V1] H3
|
||
rule_id: "H3_TICK_TAG"
|
||
rule: >
|
||
TICK_NORMALIZER_V1 통과 후 모든 지정가 옆에 태그 필수 부착.
|
||
정규화 성공 → "[TICK_OK: {price}원]"
|
||
정규화 필요 → "[TICK_INVALID: {raw}원 → {normalized}원 재산출]"
|
||
missing_tag_action: >
|
||
태그 없는 가격은 자동 INVALID_TICK_UNTAGGED 처리. HTS 주문표 기재 금지.
|
||
검산_통과여부 = FAIL_NO_TICK_TAG.
|
||
|
||
|
||
# ── [2026-05-18_CONFLICT_RESOLUTION_V1] 매도 신호/수량 분리 원칙 ──────────────
|
||
# AGENTS.md Direction-A와 동일 규칙을 spec 레벨로 명시하여 grey zone 해소.
|
||
# 충돌 상황: spec/14_raw_workbook_mapping.yaml에 Sell_Qty 필드가 존재하지만
|
||
# GAS(Google Apps Script)는 이 필드를 의도적으로 blank로 남긴다 — 오류가 아니다.
|
||
signal_quantity_separation:
|
||
canonical: true
|
||
rule_id: "SQS001"
|
||
gas_role: >
|
||
GAS(gas_data_feed.gs)는 매도 신호 생성 전용 엔진이다.
|
||
GAS 출력 = Sell_Signal(종류) + Sell_Price(지정가) + Sell_Ratio_Pct(비율%).
|
||
GAS는 절대 매도수량(Sell_Qty 정수)을 산출하지 않는다.
|
||
agent_role: >
|
||
에이전트(LLM)가 account_snapshot(HTS 이미지 캡처) 잔고를 읽어
|
||
최종 정수 매도수량을 산출한다.
|
||
공식: Sell_Qty = floor(Sell_Ratio_Pct × holding_quantity)
|
||
holding_quantity는 반드시 capture_read_ledger 판독값 사용.
|
||
workbook_sell_qty_field_intent:
|
||
field: "Sell_Qty (spec/14_raw_workbook_mapping.yaml)"
|
||
normal_value: "blank (GAS 미기재가 정상)"
|
||
filled_when: "에이전트가 account_snapshot 판독 후 최종 수량 확인 시 기재 가능"
|
||
prohibition:
|
||
- "Sell_Qty=blank 또는 Sell_Qty=None을 GAS 오류로 처리 금지"
|
||
- "Sell_Qty=blank를 이유로 사용자에게 수동 입력 요구 금지"
|
||
- "GAS가 이미 Sell_Qty를 채웠다고 가정하고 account_snapshot 판독 생략 금지"
|
||
conflict_resolution: >
|
||
AGENTS.md와 이 규칙이 충돌하면 이 spec이 우선한다(source_of_truth.priority=highest).
|
||
AGENTS.md는 보조 운영 지침이고 00_execution_contract는 canonical 실행 계약이다.
|
||
|
||
|
||
# ── [2026-05-18_ROUTING_OPTIMIZATION_V1] stop_price 단일 조회 체인 ──────────
|
||
# 문제: stop_price를 찾을 때 AI가 account_snapshot → deprecated positions 탭으로
|
||
# 루프하는 판단 지연이 발생. 아래 3단계 체인으로 라우팅을 단일화한다.
|
||
stop_price_routing_chain:
|
||
canonical: true
|
||
rule_id: "SPRC001"
|
||
purpose: >
|
||
보유 포지션의 stop_price 조회는 오직 아래 3단계 순서를 따른다.
|
||
positions 탭 참조는 체인의 어느 단계에도 존재하지 않는다.
|
||
chain:
|
||
step_1_account_snapshot:
|
||
source: "account_snapshot.stop_price (HTS 캡처 원장)"
|
||
condition: "값이 존재하고 > 0 이며 < average_cost"
|
||
result: "이 값을 stop_price로 확정. 추정·계산 없이 직접 사용."
|
||
step_2_atr_calculation:
|
||
source: "ATR 공식 추정"
|
||
condition: "step_1이 없거나(blank/0) ATR20이 data_feed에 존재할 때"
|
||
formula: "stop_price_est = max(average_cost * 0.92, average_cost - ATR20 * 1.5)"
|
||
output_tag: "(ATR추정)"
|
||
result: "추정값임을 명시하고 사용."
|
||
step_3_fallback:
|
||
source: "고정 % 폴백"
|
||
condition: "step_1·step_2 모두 불가(ATR20도 DATA_MISSING)"
|
||
formula: "stop_price_est = average_cost * 0.92"
|
||
output_tag: "(DATA_MISSING 폴백)"
|
||
result: "DATA_MISSING 표기 필수. HTS 입력 불가 표시."
|
||
dead_end:
|
||
positions_tab: >
|
||
DEPRECATED. 이 체인의 어느 단계에서도 positions 탭을 조회하지 않는다.
|
||
(spec/15_account_snapshot_contract.yaml:positions_tab 참조)
|
||
prohibition:
|
||
- "step_1 미확인 상태에서 step_2 추정값을 '확정' stop_price로 표시 금지"
|
||
- "positions 탭에 stop_price를 입력하라고 사용자에게 요구 금지"
|
||
- "account_snapshot에 stop_price가 없다는 이유로 분석 전체를 중단 금지"
|
||
|
||
capture_read_ledger:
|
||
canonical: true
|
||
purpose: "계좌·보유·현금 판독의 단일 원장. 이 표 없이 최종 주문수량 확정 금지."
|
||
columns: ["파일/화면", "계좌", "화면종류", "읽은값", "확신도", "주문표반영", "판독_상태"]
|
||
status_values:
|
||
CAPTURE_READ_OK: "캡처/원장에서 읽었고 주문 산출에 반영 가능"
|
||
CAPTURE_PROVIDED_BUT_NOT_HOLDINGS: "캡처는 있으나 자동투자/약정 화면이라 잔고 산출 불가"
|
||
CAPTURE_READ_FAILED: "캡처가 있으나 판독 실패 또는 구조화 미완료"
|
||
NOT_PROVIDED: "해당 화면/원장 미제공"
|
||
screen_type_rule:
|
||
auto_investment_screen: "자동투자 설정·약정 이체일·월 적립금액·ISA 한도 화면. 보유수량·평단·현금 판독 금지."
|
||
holdings_screen: "보유종목 목록·수량·평단·현금·평가손익 화면. 주문 산출에 직접 사용 가능."
|
||
hard_stop:
|
||
- "CAPTURE_READ_FAILED 항목이 있으면 해당 계좌 전체 주문수량 산출 보류"
|
||
- "NOT_PROVIDED 계좌는 신규 매수·매도 주문수량 산출 금지"
|
||
- "CAPTURE_PROVIDED_BUT_NOT_HOLDINGS 수치를 잔고·보유수량·현금으로 사용 금지"
|
||
|
||
|
||
# ── [2026-05-18_CONFLICT_RESOLUTION_V1] T+1 시초가 갭 주문표 재유효성 검사 ──
|
||
# 배경: 모든 분석은 전일 16:30 마감 데이터 기준이나, 주문은 익일 09:00 이후 집행된다.
|
||
# 미 증시 급락·지정학 이벤트 등으로 갭 개장 시 전일 계산된 지정가·손절가는 이미 무의미.
|
||
t1_open_gap_revalidation:
|
||
canonical: true
|
||
rule_id: "T1GAP001"
|
||
purpose: >
|
||
익일 시초가가 전일 종가 대비 ±3% 이상 갭이 발생하면
|
||
전일 산출된 모든 가격·수량 기반 주문표를 자동 무효화(INVALID_STALE)하고
|
||
당일 실시간 데이터 기준 재산출을 의무화한다.
|
||
trigger:
|
||
formula: "gap_pct = (open_price_D1 - close_price_D0) / close_price_D0 * 100"
|
||
threshold_gap_up: "gap_pct >= +3.0%"
|
||
threshold_gap_down: "gap_pct <= -3.0%"
|
||
actions:
|
||
on_gap_up:
|
||
order_table_status: "INVALID_STALE_GAP_UP"
|
||
required_actions:
|
||
- "전일 산출된 손절가·익절가·매수지정가 전량 무효 처리"
|
||
- "당일 시초가·ATR20 기준 가격 재산출 후 새 주문표 생성"
|
||
- "stop_loss.tiered_ladder tier_1 이미 돌파 여부 확인 (gap_up > tier_1_target → 즉시 익절 판단)"
|
||
output_tag: "[T+1 GAP_UP 재산출 필요] — 전일 주문표 무효"
|
||
on_gap_down:
|
||
order_table_status: "INVALID_STALE_GAP_DOWN"
|
||
required_actions:
|
||
- "전일 손절가 이미 하회 여부 확인"
|
||
- "stop_loss.gap_down 규칙 즉시 적용: 09:00~09:15 15~30분 저가·거래대금·회복 여부 기록"
|
||
- "전일 매수 지정가 전량 무효. 당일 갭하락 반응 확인 후 재진입 여부 판단"
|
||
output_tag: "[T+1 GAP_DOWN 재산출 필요] — 전일 주문표 무효"
|
||
holding_price_validity: # [2026-05-18_ROUTING_OPTIMIZATION_V1] 보유주 가격 유효성
|
||
purpose: >
|
||
갭 발생 시 신규 주문 무효화뿐 아니라 보유주의 전일 산출 stop_price·
|
||
trailing_stop 기준가도 무효화된다. 갭하락 후 전일 가격으로 손절을
|
||
집행하는 오류를 방지한다.
|
||
rule: >
|
||
t1_open_gap_revalidation 발동 시 모든 보유 포지션의
|
||
stop_price·trailing_stop_price·take_profit tier 가격은 STALE_PRICE 상태로
|
||
전환. 재산출 전 HTS 조건부 주문 집행 금지.
|
||
existing_holding_gap_down_procedure:
|
||
xref: "spec/exit/stop_loss.yaml:stop_loss.gap_down"
|
||
summary: >
|
||
갭하락 보유주 → 09:00~09:15 15~30분 관찰 후 판단.
|
||
전일 stop_price 도달 여부와 무관하게 즉시 전량 시장가 매도 금지.
|
||
high_beta_exception 조건(갭 -5%+거래대금 300%) 충족 시만 50% 선 축소 허용.
|
||
|
||
on_normal_open:
|
||
condition: "abs(gap_pct) < 3.0%"
|
||
order_table_status: "VALID_WITH_REVIEW"
|
||
note: "1~3% 갭은 유효. 단 ATR20 기준 손절가·익절가가 여전히 의미있는지 확인 후 집행."
|
||
scope:
|
||
applies_to: ["매수 지정가", "손절 지정가", "익절 지정가 (tier_1/tier_2)", "trailing_stop 기준가"]
|
||
does_not_apply_to: ["섹터 진단·국면 판단 (가격 무관한 수급/거시 분석)"]
|
||
gap_measurement_source: "data_feed.Open (당일 시초가) vs data_feed.PrevClose (전일 종가)"
|
||
missing_policy:
|
||
open_price_missing: "GAP_CHECK_SKIPPED — 갭 여부 확인 불가. 전일 주문표를 REVIEW_REQUIRED로 표시."
|
||
prohibition:
|
||
- "open_price 미확인 상태에서 전일 주문표를 유효한 것으로 간주하고 즉시 집행 금지"
|
||
- "갭 발생 시 09:00~09:15 사이 전량 시장가 매도·매수 금지 (stop_loss.gap_down 준수)"
|
||
- "갭 재산출 없이 '어제 계획대로 집행' 지시 금지"
|
||
output_requirement: >
|
||
분석 보고서 상단 블록0(국면 요약) 또는 블록1(주문 검산) 직전에
|
||
[T+1 갭 점검] 행을 출력:
|
||
형식: "시초가 {open}원 / 전일종가 {prev_close}원 / 갭 {gap_pct:+.1f}% → 주문표 상태: {status}"
|
||
|
||
order_validation_contract:
|
||
output_rendering_gate:
|
||
rule: "사람용 보고서도 주문 산출 전 반드시 capture_read_ledger와 단계 검산 결과를 먼저 표로 출력한다."
|
||
sequence:
|
||
step_pre: > # [2026-05-19_HARNESS_AUDIT_V1] H1
|
||
formula_audit_trail (QEH_AUDIT_BLOCK) — 모든 주문 출력 전 필수 선행.
|
||
TOTAL_HEAT_V1 / CASH_RATIOS_V1 / SELL_PRIORITY_V1 검산 표 없으면 주문표 전체 BLOCKED (FAT001).
|
||
step_0: "sell_priority_precheck (SELL/TRIM 후보 2개 이상 또는 현금 부족 시 선행 필수)"
|
||
step_1: "capture_read_ledger"
|
||
step_2: "data_completeness_matrix"
|
||
step_3: "order_quantity_4stage_gate"
|
||
step_4: "HTS 입력 가능 주문표 또는 산출금지 사유"
|
||
prohibition:
|
||
- "capture_read_ledger 없이 계좌 총자산·현금·보유수량·평단·매도수량 숫자를 본문 문장에 단독 기재 금지"
|
||
- "4단계 검산 결과 없이 즉시 실행 주문표 출력 금지"
|
||
- "검산 표 밖의 산문 요약으로 주문수량·현금·보유수량 근거를 대체 금지"
|
||
- "sell_priority_decision_table 없이 복수 매도 후보 중 특정 종목을 1차 대상으로 확정 금지"
|
||
stages:
|
||
stage_0_sell_priority_precheck:
|
||
# spec: spec/risk/portfolio_exposure.yaml:sell_priority_engine
|
||
activation:
|
||
- "SELL/TRIM/EXIT 후보가 2개 이상 동시 존재"
|
||
- "현금 < 목표 (cash_floor.trim_required_when 충족)"
|
||
- "REGIME_TRIM_50 발동"
|
||
required_actions:
|
||
- "GAS ?view=sell_priority 결과를 sell_priority_decision_table로 출력한다"
|
||
- "ETF 중복노출 합산 확인: 반도체(SK하이닉스+KODEX반도체+KODEX AI반도체) 총노출 계산"
|
||
- "Sell_Priority_Score 순위표에서 tier 1→2→3→4 순서 확인"
|
||
table_output_required: >
|
||
sell_priority_decision_table은 보고서에 독립된 섹션·표 형태로 먼저 출력해야 한다.
|
||
텍스트 요약("1순위: 삼성E&A, 2순위: ...")으로 대체하는 것은 이 단계를 충족하지 않는다.
|
||
fail: >
|
||
이 단계 없이 개별 종목 SELL/TRIM 수량을 확정하는 행위는
|
||
validation_status=BLOCKED_SELL_PRIORITY_REQUIRED로 처리하고
|
||
주문표의 모든 SELL/TRIM 행을 보류한다.
|
||
text_summary_substitution_ban: "sell_priority_decision_table을 텍스트 서술로 대체 금지. 표가 없으면 SELL 주문표 전체 BLOCKED."
|
||
core_leader_protection: >
|
||
SK하이닉스·삼성전자(직접 코어 주도주)는 sell_priority_engine tier=9(마지막 순위).
|
||
이 종목이 상위 순위에 나타나면 반드시 tier 1~4 후보가 모두 소진된 이후임을 확인한다.
|
||
상승추세 중 core leader를 먼저 매도하려면 hard_stop 또는 명확한 thesis 훼손 근거 필수.
|
||
stage_1_capture_ledger:
|
||
check: "capture_read_ledger 모든 계좌 분류 완료"
|
||
fail: "CAPTURE_READ_FAILED 또는 NOT_PROVIDED 계좌는 주문수량 보류"
|
||
stage_2_cash_check:
|
||
check: "매수 주문금액 합산 <= 주문가능현금 확인값"
|
||
fail: "현금 확인값 없으면 매수금액 산출 금지"
|
||
stage_3_holding_check:
|
||
check: "매도수량 <= 확인된 보유수량"
|
||
fail: >
|
||
보유수량 미확인이면 매도수량 미산출.
|
||
HTS 캡처(보유종목 화면) 미제공 시 수량 칸을 '미산출' 또는 '캡처확인후기재'로만 표시.
|
||
보유수량을 기억·추정·이전 대화에서 재사용하는 행위 금지.
|
||
stage_4_open_order_check:
|
||
check: "동일 계좌·종목 미체결 주문 여부 확인"
|
||
fail: "중복주문 방지 검산 불가 표시 후 수동 확인"
|
||
final_order_table_columns:
|
||
- "계좌"
|
||
- "종목명"
|
||
- "현재보유수량"
|
||
- "평단"
|
||
- "현재가"
|
||
- "주문구분"
|
||
- "지정가"
|
||
- "수량"
|
||
- "손절가"
|
||
- "손절수량"
|
||
- "익절가"
|
||
- "익절수량"
|
||
- "주문금액"
|
||
- "tick_status" # [TICK_OK: {price}원] 또는 [TICK_INVALID → 재산출] — H3/HS008 의무
|
||
- "검산_통과여부"
|
||
|
||
|
||
# ── [2026-05-19_HARNESS_AUDIT_V1] H1 — 공식 검산 표 강제화 ─────────────────
|
||
formula_audit_trail:
|
||
canonical: true
|
||
rule_id: "FAT001"
|
||
version: "2026-05-19_HARNESS_AUDIT_V1"
|
||
purpose: >
|
||
모든 분석 보고서 최상단에 주문표보다 먼저 출력하는 공식 검산 원장.
|
||
LLM의 '대략' 계산 습성을 차단하고 공식 ID 기반 결정론적 산출을 보장한다.
|
||
QEH_AUDIT_BLOCK이 없으면 주문표 전체 BLOCKED.
|
||
required_output_block:
|
||
id: "QEH_AUDIT_BLOCK"
|
||
columns: ["공식_ID", "입력값_요약", "결과값", "발동게이트"]
|
||
mandatory_formulas:
|
||
- id: "TOTAL_HEAT_V1"
|
||
gate_check: "< 7% → ALLOW / 7~10% → HALVE / >= 10% → BLOCK_NEW_BUY"
|
||
missing_action: "BLOCK_NEW_BUY 자동 발동 + DATA_MISSING 표기"
|
||
- id: "CASH_RATIOS_V1"
|
||
gate_check: "current_cash_pct vs target_cash_pct → PASS / CASH_RAISE_REQUIRED(-Xp)"
|
||
missing_action: "현금 판정 불가 → 매수 보류"
|
||
- id: "SELL_PRIORITY_V1"
|
||
condition: "SELL/TRIM 후보 존재 또는 cash_floor_status != PASS 시"
|
||
gate_check: "1순위 종목 + Score + tier 표시"
|
||
optional_formulas_when_applicable:
|
||
- "POSITION_SIZE_V1 — 매수 수량 산출 시"
|
||
- "STOP_PRICE_CORE_V1 — 손절가 산출 시"
|
||
- "TAKE_PROFIT_LADDER_V2 — 익절 사다리 산출 시"
|
||
- "MARKET_RISK_SCORE_V1 — 국면 진단 시"
|
||
- "RISK_BUDGET_CASCADE_V1 — 리스크 예산 계산 시"
|
||
- "TICK_NORMALIZER_V1 — 모든 지정가 출력 전"
|
||
enforcement:
|
||
- "QEH_AUDIT_BLOCK 없이 주문표 출력 → INVALID_MISSING_AUDIT. 전체 BLOCKED."
|
||
- "TOTAL_HEAT_V1 결과 없이 신규 BUY 주문 → BLOCKED (HS006 연동)"
|
||
- "CASH_RATIOS_V1 결과 없이 현금 판정 → BLOCKED (P3 연동)"
|
||
- "공식 ID 명시 없는 가격·수량 → PRICE_FORMULA_REQUIRED (P7 연동)"
|
||
- "표에 기재된 공식 ID와 실제 사용 공식 불일치 → CRITICAL_FORMULA_MISMATCH"
|
||
llm_role: "공식 결과를 표에 복사·기재. 재계산·재해석·임의 조정 금지."
|
||
|
||
# ── [2026-05-20_HARNESS_V5] LLM 계산 화이트리스트 ──────────────────────────
|
||
llm_computation_whitelist:
|
||
canonical: true
|
||
rule_id: "LCW001"
|
||
version: "2026-05-20_HARNESS_V5"
|
||
purpose: >
|
||
LLM이 수행할 수 있는 계산과 절대 수행할 수 없는 계산을 명시한다.
|
||
하네스(GAS 확정 값)가 존재하는 영역에서 LLM의 재계산·재해석을 원천 차단한다.
|
||
이 규칙은 P7, HS011, FAT001보다 상위에서 계산 행위 자체를 규율한다.
|
||
|
||
allowed:
|
||
text_and_narrative:
|
||
- "공식 결과값에 대한 텍스트 요약 및 해석 (숫자 재산출 없이)"
|
||
- "하네스 출력 JSON 값을 인용·복사해 보고서에 표시"
|
||
- "spec/13_formula_registry.yaml에 등록된 공식 ID 인용 및 적용 조건 서술"
|
||
- "게이트 상태 레이블(PASS/BLOCKED/WATCH 등) 인용 및 조치 권고"
|
||
- "여러 게이트 결과를 조합해 종합 판단 서술 (개별 숫자 재산출 없이)"
|
||
simple_lookups:
|
||
- "가격·수량 비교 (단순 대소 비교: close >= tp1_price 등)"
|
||
- "비율 단순 적용: floor(Sell_Ratio_Pct × holding_quantity) — holding_quantity는 반드시 캡처 판독값"
|
||
- "정수 반올림 처리: ROUND_DOWN for share quantities"
|
||
|
||
forbidden:
|
||
price_calculations:
|
||
rule: "모든 가격은 GAS 확정값 또는 등록된 공식 ID 기반. LLM 임의 계산 절대 금지."
|
||
examples:
|
||
- "stop_price, trailing_stop_price 직접 계산"
|
||
- "take_profit tier 가격 직접 계산"
|
||
- "ATR 기반 가격 추정 (GAS ATR20 미제공 시 DATA_MISSING으로만 표시)"
|
||
- "rebound_trigger_price = prevClose + 0.5×ATR20 직접 계산"
|
||
fail_action: "FORBIDDEN_LLM_PRICE_CALC — 해당 가격 무효. HTS 입력 불가."
|
||
|
||
quantity_calculations:
|
||
rule: "포지션 사이즈, 매수 수량, 분할 트랜치 수량은 GAS POSITION_SIZE_V1 결과만 사용."
|
||
examples:
|
||
- "ATR 기반 포지션 사이즈 직접 계산"
|
||
- "리스크 예산 기반 수량 직접 계산"
|
||
- "smart_cash_raise_qty 직접 계산"
|
||
- "트랜치 수량 임의 산출"
|
||
fail_action: "FORBIDDEN_LLM_QTY_CALC — 해당 수량 무효. GAS 재실행 필요."
|
||
|
||
cash_and_ratio_calculations:
|
||
rule: "현금 비율, Heat 수치, 포트폴리오 가중치는 GAS 확정값만 사용."
|
||
examples:
|
||
- "total_heat_pct 직접 계산"
|
||
- "cash_shortfall_krw 직접 계산"
|
||
- "position weight % 직접 계산"
|
||
- "settlement_cash_d2_krw 추정"
|
||
fail_action: "FORBIDDEN_LLM_CASH_CALC — 해당 수치 무효. GAS 재실행 후 재인용."
|
||
|
||
harness_gate_overrides:
|
||
rule: "GAS 확정 게이트 상태를 LLM이 재판단·완화·우회 절대 금지."
|
||
examples:
|
||
- "BLOCKED_LATE_CHASE → 서사로 BUY 허용 유도"
|
||
- "WHIPSAW_SUSPECTED → 매도 진행 서술"
|
||
- "ROUTE_D 이외 경로에서 전량매도 권고"
|
||
- "CRITICAL health_label을 CAUTION으로 임의 완화"
|
||
fail_action: "FORBIDDEN_GATE_OVERRIDE — 해당 분석 전체 BLOCKED. 재실행 필요."
|
||
|
||
score_recalculation:
|
||
rule: "모든 스코어(breakout_quality_score, anti_whipsaw_score, t1_forced_sell_risk_score 등)는 GAS 계산 결과만 인용."
|
||
examples:
|
||
- "breakout_quality_score 직접 계산"
|
||
- "distribution_risk_score 재계산"
|
||
- "late_chase_risk_score 조정"
|
||
- "portfolio_health_score 재산출"
|
||
fail_action: "FORBIDDEN_SCORE_RECALC — 스코어 무효. 공식 ID 인용 또는 DATA_MISSING 표기."
|
||
|
||
enforcement:
|
||
- "FORBIDDEN 항목 위반 발견 시 해당 숫자·결론 전체 BLOCKED으로 처리"
|
||
- "LCW001 위반이 주문표에 반영되면 주문표 전체 INVALID_LCW_VIOLATION"
|
||
- "위반된 계산 대신 'GAS 재실행 필요' 또는 'DATA_MISSING — 하네스 업데이트 필요' 표기"
|
||
cross_refs:
|
||
- "master_prohibitions.P7_price_formula_id_required"
|
||
- "hard_stops.HS011_NO_LLM_FORMULA_DEFINITION"
|
||
- "formula_audit_trail.FAT001"
|
||
- "spec/13b_harness_formulas.yaml:ANTI_WHIPSAW_HOLD_GATE_V1"
|
||
- "spec/13b_harness_formulas.yaml:SMART_CASH_RAISE_V2"
|
||
- "spec/13_formula_registry.yaml:BREAKOUT_QUALITY_GATE_V2"
|
||
|
||
|
||
compatibility_aliases:
|
||
old_paths:
|
||
"llm_compact_execution_contract.non_negotiable_tables.capture_read_ledger.screen_type_rule": "spec/00_execution_contract.yaml:capture_read_ledger.screen_type_rule"
|
||
"llm_compact_execution_contract.master_prohibitions": "spec/00_execution_contract.yaml:master_prohibitions"
|
||
"llm_compact_execution_contract.hard_stops": "spec/00_execution_contract.yaml:hard_stops"
|
||
rule: "기존 경로가 문서에 남아 있으면 위 alias로 해석하되, 신규 수정 시 새 경로로 교체한다."
|