From 6b34367656ce48a7b4a6198b7db33433f9ead1f9 Mon Sep 17 00:00:00 2001 From: agentson Date: Sun, 1 Mar 2026 17:06:56 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20v2/v3=20=EA=B5=AC=ED=98=84=20=EA=B0=90?= =?UTF-8?q?=EC=82=AC=20=EB=AC=B8=EC=84=9C=20=ED=94=BC=EB=93=9C=EB=B0=B1=20?= =?UTF-8?q?=EC=A0=84=EC=B2=B4=20=EB=B0=98=EC=98=81=20(#349)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 11회 리뷰 사이클에서 남긴 [코멘트]를 모두 본문에 반영하고 블록을 제거한다. 변경 문서: - docs/architecture.md: SmartScanner 동작 모드(both), 대시보드 10 API, DB 스키마(session_id/fx_pnl/mode), config 변수 갱신 - docs/commands.md: /api/pnl/history, /api/positions 엔드포인트 추가 - docs/testing.md: 테스트 수 고정값 제거, SmartScanner fallback 최신화, Dashboard 10 API routes 반영 - README.md: 고정 수치 제거, Gitea CI 명시, 파일별 수치 'CI 기준 변동' 표기 - CLAUDE.md: SmartScanner 섹션명 변경, 고정 수치 제거 - docs/requirements-log.md: #318~#331 구현 항목 추가 - docs/ouroboros/80_implementation_audit.md: ROOT-5/6/7 분리, REQ-V3-008 함수명 병기, v3 ~85% / 거버넌스 ~60%로 갱신 - docs/ouroboros/85_loss_recovery_action_plan.md: ACT-07 함수명 병기, 테스트 수 갱신, 6.1/6.2 정확도 개선 - docs/ouroboros/60_repo_enforcement_checklist.md: CI job/step 구분 표 추가 - docs/ouroboros/README.md: 50_* 문서 (A)/(B) 보조 표기 Closes #349 --- CLAUDE.md | 8 +- README.md | 27 ++- docs/architecture.md | 126 ++++++++++++- docs/commands.md | 4 +- .../60_repo_enforcement_checklist.md | 12 +- docs/ouroboros/80_implementation_audit.md | 172 +++++++++++------- .../ouroboros/85_loss_recovery_action_plan.md | 91 +++++---- docs/ouroboros/README.md | 6 +- docs/requirements-log.md | 125 ++++++++++++- docs/testing.md | 10 +- 10 files changed, 447 insertions(+), 134 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 6c15dca..9387fa9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -81,9 +81,9 @@ SCANNER_TOP_N=3 # Max candidates per scan - **Evolution-ready** — Selection context logged for strategy optimization - **Fault-tolerant** — Falls back to static watchlist on API failure -### Realtime Mode Only +### Trading Mode Integration -Smart Scanner runs in `TRADE_MODE=realtime` only. Daily mode uses static watchlists for batch efficiency. +Smart Scanner runs in both `TRADE_MODE=realtime` and `daily` paths. On API failure, domestic stocks fall back to a static watchlist; overseas stocks fall back to a dynamic universe (active positions, recent holdings). ## Documentation @@ -122,7 +122,7 @@ src/ ├── broker/ # KIS API client (domestic + overseas) ├── context/ # L1-L7 hierarchical memory system ├── core/ # Risk manager (READ-ONLY) -├── dashboard/ # FastAPI read-only monitoring (8 API endpoints) +├── dashboard/ # FastAPI read-only monitoring (10 API endpoints) ├── data/ # External data integration (news, market data, calendar) ├── evolution/ # Self-improvement (optimizer, daily review, scorecard) ├── logging/ # Decision logger (audit trail) @@ -133,7 +133,7 @@ src/ ├── main.py # Trading loop orchestrator └── config.py # Settings (from .env) -tests/ # 551 tests across 25 files +tests/ # 998 tests across 41 files docs/ # Extended documentation ``` diff --git a/README.md b/README.md index eba289e..587ac0c 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ KIS(한국투자증권) API로 매매하고, Google Gemini로 판단하며, 자 | 컨텍스트 | `src/context/` | L1-L7 계층형 메모리 시스템 | | 분석 | `src/analysis/` | RSI, ATR, Smart Volatility Scanner | | 알림 | `src/notifications/` | 텔레그램 양방향 (알림 + 9개 명령어) | -| 대시보드 | `src/dashboard/` | FastAPI 읽기 전용 모니터링 (8개 API) | +| 대시보드 | `src/dashboard/` | FastAPI 읽기 전용 모니터링 (10개 API) | | 진화 | `src/evolution/` | 전략 진화 + Daily Review + Scorecard | | 의사결정 로그 | `src/logging/` | 전체 거래 결정 감사 추적 | | 데이터 | `src/data/` | 뉴스, 시장 데이터, 경제 캘린더 연동 | @@ -153,19 +153,16 @@ docker compose up -d ouroboros ## 테스트 -551개 테스트가 25개 파일에 걸쳐 구현되어 있습니다. 최소 커버리지 80%. +998개 테스트가 41개 파일에 걸쳐 구현되어 있습니다. 최소 커버리지 80%. ``` -tests/test_scenario_engine.py — 시나리오 매칭 (44개) -tests/test_data_integration.py — 외부 데이터 연동 (38개) -tests/test_pre_market_planner.py — 플레이북 생성 (37개) -tests/test_main.py — 거래 루프 통합 (37개) -tests/test_token_efficiency.py — 토큰 최적화 (34개) -tests/test_strategy_models.py — 전략 모델 검증 (33개) -tests/test_telegram_commands.py — 텔레그램 명령어 (31개) -tests/test_latency_control.py — 지연시간 제어 (30개) -tests/test_telegram.py — 텔레그램 알림 (25개) -... 외 16개 파일 +tests/test_main.py — 거래 루프 통합 +tests/test_scenario_engine.py — 시나리오 매칭 +tests/test_pre_market_planner.py — 플레이북 생성 +tests/test_overseas_broker.py — 해외 브로커 +tests/test_telegram_commands.py — 텔레그램 명령어 +tests/test_telegram.py — 텔레그램 알림 +... 외 35개 파일 ※ 파일별 수치는 CI 기준으로 변동 가능 ``` **상세**: [docs/testing.md](docs/testing.md) @@ -177,8 +174,8 @@ tests/test_telegram.py — 텔레그램 알림 (25개) - **AI**: Google Gemini Pro - **DB**: SQLite (5개 테이블: trades, contexts, decision_logs, playbooks, context_metadata) - **대시보드**: FastAPI + uvicorn -- **검증**: pytest + coverage (551 tests) -- **CI/CD**: GitHub Actions +- **검증**: pytest + coverage (998 tests) +- **CI/CD**: Gitea CI (`.gitea/workflows/ci.yml`) - **배포**: Docker + Docker Compose ## 프로젝트 구조 @@ -212,7 +209,7 @@ The-Ouroboros/ │ ├── config.py # Pydantic 설정 │ ├── db.py # SQLite 데이터베이스 │ └── main.py # 비동기 거래 루프 -├── tests/ # 551개 테스트 (25개 파일) +├── tests/ # 998개 테스트 (41개 파일) ├── Dockerfile # 멀티스테이지 빌드 ├── docker-compose.yml # 서비스 오케스트레이션 └── pyproject.toml # 의존성 및 도구 설정 diff --git a/docs/architecture.md b/docs/architecture.md index a334e2d..f0b42d6 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -84,6 +84,37 @@ High-frequency trading with individual stock analysis: - Momentum scoring (0-100 scale) - Breakout/breakdown pattern detection +**TripleBarrierLabeler** (`triple_barrier.py`) — Financial time-series labeling (v2) + +- Triple Barrier method: upper (take-profit), lower (stop-loss), time barrier +- First-touch labeling: labels confirmed by whichever barrier is breached first +- `max_holding_minutes` (calendar-minute) time barrier — session-aware, bar-period independent +- Tie-break mode: `"stop_first"` (conservative) or `"take_first"` +- Feature-label strict separation to prevent look-ahead bias + +**BacktestPipeline** (`backtest_pipeline.py`) — End-to-end validation pipeline (v2) + +- `run_v2_backtest_pipeline()`: cost guard → triple barrier labeling → walk-forward splits → fold scoring +- `BacktestPipelineResult`: artifact contract for reproducible output +- `fold_has_leakage()`: leakage detection utility + +**WalkForwardSplit** (`walk_forward_split.py`) — Time-series validation (v2) + +- Fold-based walk-forward splits (no random shuffling) +- Purge/Embargo: excludes N bars before/after fold boundaries to prevent data leakage + +**BacktestExecutionModel** (`backtest_execution_model.py`) — Conservative fill simulation (v2/v3) + +- Session-aware slippage: KRX_REG 5bps, NXT_AFTER 15bps, US_REG 3bps, US_PRE/DAY 30-50bps +- Order failure rate simulation per session +- Partial fill rate simulation with min/max ratio bounds +- Unfavorable-direction fill assumption (no simple close-price fill) + +**BacktestCostGuard** (`backtest_cost_guard.py`) — Cost model validator (v2) + +- `validate_backtest_cost_model()`: fail-fast check that session cost assumptions are present +- Enforces realistic cost assumptions before any backtest run proceeds + **SmartVolatilityScanner** (`smart_scanner.py`) — Python-first filtering pipeline - **Domestic (KR)**: @@ -98,7 +129,7 @@ High-frequency trading with individual stock analysis: - **Step 4**: Return top N candidates (default 3) - **Fallback (overseas only)**: If ranking API is unavailable, uses dynamic universe from runtime active symbols + recent traded symbols + current holdings (no static watchlist) -- **Realtime mode only**: Daily mode uses batch processing for API efficiency +- **Both modes**: Realtime 중심이지만 Daily 경로(`run_daily_session()`)에서도 후보 선별에 사용 **Benefits:** - Reduces Gemini API calls from 20-30 stocks to 1-3 qualified candidates @@ -124,9 +155,9 @@ High-frequency trading with individual stock analysis: - Selects appropriate context layers for current market conditions -### 4. Risk Manager (`src/core/risk_manager.py`) +### 4. Risk Manager & Session Policy (`src/core/`) -**RiskManager** — Safety circuit breaker and order validation +**RiskManager** (`risk_manager.py`) — Safety circuit breaker and order validation > **READ-ONLY by policy** (see [`docs/agents.md`](./agents.md)) @@ -136,8 +167,59 @@ High-frequency trading with individual stock analysis: - **Fat-Finger Protection**: Rejects orders exceeding 30% of available cash - Must always be enforced, cannot be disabled +**OrderPolicy** (`order_policy.py`) — Session classification and order type enforcement (v3) + +- `classify_session_id()`: Classifies current KR/US session from KST clock + - KR: `NXT_PRE` (08:00-08:50), `KRX_REG` (09:00-15:30), `NXT_AFTER` (15:30-20:00) + - US: `US_DAY` (10:00-18:00), `US_PRE` (18:00-23:30), `US_REG` (23:30-06:00), `US_AFTER` (06:00-07:00) +- Low-liquidity session detection: `NXT_AFTER`, `US_PRE`, `US_DAY`, `US_AFTER` +- Market order forbidden in low-liquidity sessions (`OrderPolicyRejected` raised) +- Limit/IOC/FOK orders always allowed + +**KillSwitch** (`kill_switch.py`) — Emergency trading halt orchestration (v2) + +- Fixed 5-step atomic sequence: + 1. Block new orders (`new_orders_blocked = True`) + 2. Cancel all unfilled orders + 3. Refresh order state (query final status) + 4. Reduce risk (force-close or reduce positions) + 5. Snapshot state + send Telegram alert +- Async, injectable step callables — each step individually testable +- Highest priority: overrides overnight exception and all other rules + +**BlackoutManager** (`blackout_manager.py`) — KIS maintenance window handling (v3) + +- Configurable blackout windows (e.g., `23:30-00:10 KST`) +- `queue_order()`: Queues order intent during blackout, enforces max queue size +- `pop_recovery_batch()`: Returns queued intents after recovery +- Recovery revalidation path (in `src/main.py`): + - Stale BUY drop (position already exists) + - Stale SELL drop (position absent) + - `validate_order_policy()` rechecked + - Price drift check (>5% → drop, configurable via `BLACKOUT_RECOVERY_MAX_PRICE_DRIFT_PCT`) + ### 5. Strategy (`src/strategy/`) +**PositionStateMachine** (`position_state_machine.py`) — 4-state sell state machine (v2) + +- States: `HOLDING` → `BE_LOCK` → `ARMED` → `EXITED` + - `HOLDING`: Normal holding + - `BE_LOCK`: Profit ≥ `be_arm_pct` — stop-loss elevated to break-even + - `ARMED`: Profit ≥ `arm_pct` — peak-tracking trailing stop active + - `EXITED`: Position closed +- `promote_state()`: Immediately elevates to highest admissible state (handles gaps/skips) +- `evaluate_exit_first()`: EXITED conditions checked before state promotion +- Monotonic: states only move up, never down + +**ExitRules** (`exit_rules.py`) — 4-layer composite exit logic (v2) + +- **Hard Stop**: `unrealized <= hard_stop_pct` (always enforced, ATR-adaptive for KR) +- **Break-Even Lock**: Once in BE_LOCK/ARMED, exit if price falls to entry price +- **ATR Trailing Stop**: `trailing_stop_price = peak_price - (atr_multiplier_k × ATR)` +- **Model Signal**: Exit if `pred_down_prob >= model_prob_threshold AND liquidity_weak` +- `evaluate_exit()`: Returns `ExitEvaluation` with next state, exit flag, reason, trailing price +- `ExitRuleConfig`: Frozen dataclass with all tunable parameters + **Pre-Market Planner** (`pre_market_planner.py`) — AI playbook generation - Runs before market open (configurable `PRE_MARKET_MINUTES`, default 30) @@ -195,7 +277,7 @@ High-frequency trading with individual stock analysis: - Configurable host/port (`DASHBOARD_HOST`, `DASHBOARD_PORT`, default `127.0.0.1:8080`) - Serves static HTML frontend -**8 API Endpoints:** +**10 API Endpoints:** | Endpoint | Method | Description | |----------|--------|-------------| @@ -207,6 +289,8 @@ High-frequency trading with individual stock analysis: | `/api/context/{layer}` | GET | Query context by layer (L1-L7) | | `/api/decisions` | GET | Decision log entries with outcomes | | `/api/scenarios/active` | GET | Today's matched scenarios | +| `/api/pnl/history` | GET | P&L history time series | +| `/api/positions` | GET | Current open positions | ### 8. Notifications (`src/notifications/telegram_client.py`) @@ -448,8 +532,12 @@ CREATE TABLE trades ( pnl REAL DEFAULT 0.0, market TEXT DEFAULT 'KR', exchange_code TEXT DEFAULT 'KRX', + session_id TEXT DEFAULT 'UNKNOWN', -- v3: KRX_REG | NXT_AFTER | US_REG | US_PRE | ... selection_context TEXT, -- JSON: {rsi, volume_ratio, signal, score} - decision_id TEXT -- Links to decision_logs + decision_id TEXT, -- Links to decision_logs + strategy_pnl REAL, -- v3: Core strategy P&L (separated from FX) + fx_pnl REAL DEFAULT 0.0, -- v3: FX gain/loss for USD trades (schema ready, activation pending) + mode TEXT -- paper | live ); ``` @@ -475,13 +563,14 @@ CREATE TABLE decision_logs ( stock_code TEXT, market TEXT, exchange_code TEXT, + session_id TEXT DEFAULT 'UNKNOWN', -- v3: session when decision was made action TEXT, confidence INTEGER, rationale TEXT, context_snapshot TEXT, -- JSON: full context at decision time input_data TEXT, -- JSON: market data used outcome_pnl REAL, - outcome_accuracy REAL, + outcome_accuracy INTEGER, reviewed INTEGER DEFAULT 0, review_notes TEXT ); @@ -494,7 +583,7 @@ CREATE TABLE playbooks ( id INTEGER PRIMARY KEY AUTOINCREMENT, date TEXT NOT NULL, market TEXT NOT NULL, - status TEXT DEFAULT 'generated', + status TEXT NOT NULL DEFAULT 'pending', -- pending → generated → active → expired playbook_json TEXT NOT NULL, -- Full playbook with scenarios generated_at TEXT NOT NULL, token_count INTEGER, @@ -552,6 +641,29 @@ PLANNER_TIMEOUT_SECONDS=60 # Timeout for playbook generation DEFENSIVE_PLAYBOOK_ON_FAILURE=true # Fallback on AI failure RESCAN_INTERVAL_SECONDS=300 # Scenario rescan interval during trading +# Optional — v2 Exit Rules (State Machine) +STAGED_EXIT_BE_ARM_PCT=1.2 # Break-even lock threshold (%) +STAGED_EXIT_ARM_PCT=3.0 # Armed state threshold (%) +KR_ATR_STOP_MULTIPLIER_K=2.0 # ATR multiplier for KR dynamic hard stop +KR_ATR_STOP_MIN_PCT=-2.0 # KR hard stop floor (must tighten, negative) +KR_ATR_STOP_MAX_PCT=-7.0 # KR hard stop ceiling (loosest, negative) + +# Optional — v2 Trade Filters +STOP_LOSS_COOLDOWN_MINUTES=120 # Cooldown after stop-loss before re-entry (same ticker) +US_MIN_PRICE=5.0 # Minimum US stock price for BUY ($) + +# Optional — v3 Session Risk Management +SESSION_RISK_RELOAD_ENABLED=true # Reload risk params at session boundaries +SESSION_RISK_PROFILES_JSON="{}" # Per-session overrides JSON: {"KRX_REG": {"be_arm_pct": 1.0}} +OVERNIGHT_EXCEPTION_ENABLED=true # Allow holding through session close (conditions apply) + +# Optional — v3 Blackout (KIS maintenance windows) +ORDER_BLACKOUT_ENABLED=true +ORDER_BLACKOUT_WINDOWS_KST=23:30-00:10 # Comma-separated: "HH:MM-HH:MM" +ORDER_BLACKOUT_QUEUE_MAX=500 # Max queued orders during blackout +BLACKOUT_RECOVERY_PRICE_REVALIDATION_ENABLED=true +BLACKOUT_RECOVERY_MAX_PRICE_DRIFT_PCT=5.0 # Drop recovery order if price drifted >5% + # Optional — Smart Scanner (realtime mode only) RSI_OVERSOLD_THRESHOLD=30 # 0-50, oversold threshold RSI_MOMENTUM_THRESHOLD=70 # 50-100, momentum threshold diff --git a/docs/commands.md b/docs/commands.md index f70a844..a667230 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -136,7 +136,7 @@ No decorator needed for async tests. # Install all dependencies (production + dev) pip install -e ".[dev]" -# Run full test suite with coverage (551 tests across 25 files) +# Run full test suite with coverage (998 tests across 41 files) pytest -v --cov=src --cov-report=term-missing # Run a single test file @@ -202,6 +202,8 @@ Dashboard runs as a daemon thread on `DASHBOARD_HOST:DASHBOARD_PORT` (default: ` | `GET /api/context/{layer}` | Context data by layer L1-L7 (query: `timeframe`) | | `GET /api/decisions` | Decision log entries (query: `limit`, `market`) | | `GET /api/scenarios/active` | Today's matched scenarios | +| `GET /api/pnl/history` | P&L history over time | +| `GET /api/positions` | Current open positions | ## Telegram Commands diff --git a/docs/ouroboros/60_repo_enforcement_checklist.md b/docs/ouroboros/60_repo_enforcement_checklist.md index 989248c..71bae69 100644 --- a/docs/ouroboros/60_repo_enforcement_checklist.md +++ b/docs/ouroboros/60_repo_enforcement_checklist.md @@ -24,11 +24,17 @@ Updated: 2026-02-27 ## 2) 필수 상태 체크 (필수) 필수 CI 항목: -- `validate_ouroboros_docs` (명령: `python3 scripts/validate_ouroboros_docs.py`) -- `test` (명령: `pytest -q`) + +| 참조 기준 | 이름 | 설명 | +|-----------|------|------| +| **job 단위** (브랜치 보호 설정 시 사용) | `test` | 전체 CI job (문서 검증 + 테스트 포함) | +| **step 단위** (로그 확인 시 참조) | `validate_ouroboros_docs` | `python3 scripts/validate_ouroboros_docs.py` 실행 step | +| **step 단위** | `run_tests` | `pytest -q` 실행 step | + +> **주의**: Gitea 브랜치 보호의 Required Status Checks는 **job 이름** 기준으로 설정한다 (`test`). step 이름은 UI 로그 탐색용이며 보호 규칙에 직접 입력하지 않는다. 설정 기준: -- 위 2개 체크가 `success` 아니면 머지 금지 +- `test` job이 `success` 아니면 머지 금지 - 체크 스킵/중립 상태 허용 금지 ## 3) 필수 리뷰어 규칙 (권장 -> 필수) diff --git a/docs/ouroboros/80_implementation_audit.md b/docs/ouroboros/80_implementation_audit.md index cfe6e14..fcf0160 100644 --- a/docs/ouroboros/80_implementation_audit.md +++ b/docs/ouroboros/80_implementation_audit.md @@ -1,14 +1,15 @@ # v2/v3 구현 감사 및 수익률 분석 보고서 작성일: 2026-02-28 +최종 업데이트: 2026-03-01 (Phase 2 완료 + Phase 3 부분 완료 반영) 대상 기간: 2026-02-25 ~ 2026-02-28 (실거래) 분석 브랜치: `feature/v3-session-policy-stream` @@ -29,69 +30,80 @@ Updated: 2026-02-28 | REQ-V2-007 | 비용/슬리피지/체결실패 모델 필수 | `src/analysis/backtest_cost_guard.py` | ✅ 완료 | | REQ-V2-008 | Kill Switch 실행 순서 (Block→Cancel→Refresh→Reduce→Snapshot) | `src/core/kill_switch.py` | ✅ 완료 | -### 1.2 v3 구현 상태: ~75% 완료 +### 1.2 v3 구현 상태: ~85% 완료 (2026-03-01 기준) -| REQ-ID | 요구사항 | 상태 | 갭 설명 | -|--------|----------|------|---------| -| REQ-V3-001 | 모든 신호/주문/로그에 session_id 포함 | ⚠️ 부분 | 아래 GAP-1, GAP-2 참조 | -| REQ-V3-002 | 세션 전환 훅 + 리스크 파라미터 재로딩 | ⚠️ 부분 | 아래 GAP-3 참조 | +| REQ-ID | 요구사항 | 상태 | 비고 | +|--------|----------|------|------| +| REQ-V3-001 | 모든 신호/주문/로그에 session_id 포함 | ✅ 완료 | #326 머지 — `log_decision()` 파라미터 추가, `log_trade()` 명시적 전달 | +| REQ-V3-002 | 세션 전환 훅 + 리스크 파라미터 재로딩 | ⚠️ 부분 | #327 머지 — 재로딩 메커니즘 구현, 세션 훅 테스트 미작성 | | REQ-V3-003 | 블랙아웃 윈도우 정책 | ✅ 완료 | `src/core/blackout_manager.py` | -| REQ-V3-004 | 블랙아웃 큐 + 복구 시 재검증 | ⚠️ 부분 | 아래 GAP-4 참조 (부분 해소) | +| REQ-V3-004 | 블랙아웃 큐 + 복구 시 재검증 | ✅ 완료 | #324(DB 기록) + #328(가격/세션 재검증) 머지 | | REQ-V3-005 | 저유동 세션 시장가 금지 | ✅ 완료 | `src/core/order_policy.py` | | REQ-V3-006 | 보수적 백테스트 체결 (불리 방향) | ✅ 완료 | `src/analysis/backtest_execution_model.py` | | REQ-V3-007 | FX 손익 분리 (전략 PnL vs 환율 PnL) | ⚠️ 코드 완료 / 운영 미반영 | `src/db.py` 스키마·함수 완료, 운영 데이터 `fx_pnl` 전부 0 | -| REQ-V3-008 | 오버나잇 예외 vs Kill Switch 우선순위 | ✅ 완료 | `src/main.py:459-471` | +| REQ-V3-008 | 오버나잇 예외 vs Kill Switch 우선순위 | ✅ 완료 | `src/main.py` — `_should_force_exit_for_overnight()`, `_apply_staged_exit_override_for_hold()` | -### 1.3 운영 거버넌스: ~20% 완료 +### 1.3 운영 거버넌스: ~60% 완료 (2026-03-01 재평가) -| REQ-ID | 요구사항 | 상태 | 갭 설명 | -|--------|----------|------|---------| +| REQ-ID | 요구사항 | 상태 | 비고 | +|--------|----------|------|------| | REQ-OPS-001 | 타임존 명시 (KST/UTC) | ⚠️ 부분 | DB 기록은 UTC, 세션은 KST. 일부 로그에서 타임존 미표기 | -| REQ-OPS-002 | 정책 변경 시 레지스트리 업데이트 강제 | ❌ 미구현 | CI 자동 검증 없음 | -| REQ-OPS-003 | TASK-REQ 매핑 강제 | ❌ 미구현 | PR 단위 자동 검증 없음 | +| REQ-OPS-002 | 정책 변경 시 레지스트리 업데이트 강제 | ⚠️ 기본 구현 완료 | `scripts/validate_governance_assets.py` CI 연동 완료; 규칙 고도화 잔여 | +| REQ-OPS-003 | TASK-REQ 매핑 강제 | ⚠️ 기본 구현 완료 | `scripts/validate_ouroboros_docs.py` CI 연동 완료; PR 강제 검증 강화 잔여 | --- ## 2. 구현 갭 상세 -### GAP-1: DecisionLogger에 session_id 미포함 (CRITICAL) +> **2026-03-01 업데이트**: GAP-1~5 모두 해소되었거나 이슈 머지로 부분 해소됨. -- **위치**: `src/logging/decision_logger.py:40` -- **문제**: `log_decision()` 함수에 `session_id` 파라미터가 없음 -- **영향**: 어떤 세션에서 전략적 의사결정이 내려졌는지 추적 불가 +### GAP-1: DecisionLogger에 session_id 미포함 → ✅ 해소 (#326) + +- **위치**: `src/logging/decision_logger.py` +- ~~문제: `log_decision()` 함수에 `session_id` 파라미터가 없음~~ +- **해소**: #326 머지 — `log_decision()` 파라미터에 `session_id` 추가, DB 기록 포함 - **요구사항**: REQ-V3-001 -### GAP-2: src/main.py 거래 로그에 session_id 미전달 (CRITICAL) +### GAP-2: src/main.py 거래 로그에 session_id 미전달 → ✅ 해소 (#326) -- **위치**: `src/main.py` line 1625, 1682, 2769 -- **문제**: `log_trade()` 호출 시 `session_id` 파라미터를 전달하지 않음 -- **현상**: 시장 코드 기반 자동 추론에 의존 → 실제 런타임 세션과 불일치 가능 +- **위치**: `src/main.py` +- ~~문제: `log_trade()` 호출 시 `session_id` 파라미터를 전달하지 않음~~ +- **해소**: #326 머지 — `log_trade()` 호출 시 런타임 `session_id` 명시적 전달 - **요구사항**: REQ-V3-001 -### GAP-3: 세션 전환 시 리스크 파라미터 재로딩 없음 (HIGH) +### GAP-3: 세션 전환 시 리스크 파라미터 재로딩 없음 → ⚠️ 부분 해소 (#327) -- **위치**: `src/main.py` 전체 -- **문제**: 리스크 파라미터가 시작 시 한 번만 로딩되고, 세션 경계 변경 시 재로딩 메커니즘 없음 -- **영향**: NXT_AFTER(저유동) → KRX_REG(정규장) 전환 시에도 동일 파라미터 사용 +- **위치**: `src/main.py`, `src/config.py` +- **해소 내용**: #327 머지 — `SESSION_RISK_PROFILES_JSON` 기반 세션별 파라미터 재로딩 메커니즘 구현 + - `SESSION_RISK_RELOAD_ENABLED=true` 시 세션 경계에서 파라미터 재로딩 + - 재로딩 실패 시 기존 파라미터 유지 (안전 폴백) +- **잔여 갭**: 세션 경계 실시간 전환 E2E 통합 테스트 보강 필요 (`test_main.py`에 설정 오버라이드/폴백 단위 테스트는 존재) - **요구사항**: REQ-V3-002 -### GAP-4: 블랙아웃 복구 시 재검증 부분 해소, DB 기록 미구현 (HIGH) +### GAP-4: 블랙아웃 복구 DB 기록 + 재검증 → ✅ 해소 (#324, #328) -- **위치**: `src/core/blackout_manager.py:89-96`, `src/main.py:694-791` -- **상태**: `pop_recovery_batch()` 자체는 단순 dequeue이나, 실행 경로에서 부분 재검증 수행: - - stale BUY 드롭 (포지션 이미 존재 시) — `src/main.py:713-720` - - stale SELL 드롭 (포지션 부재 시) — `src/main.py:721-727` - - `validate_order_policy()` 호출 — `src/main.py:729-734` -- **잔여 갭**: 가격 유효성(시세 변동), 세션 변경에 따른 파라미터 재적용은 미구현 -- **신규 발견**: 블랙아웃 복구 주문이 `log_trade()` 없이 실행되어 거래 DB에 기록되지 않음 → 성과 리포트 불일치 유발 +- **위치**: `src/core/blackout_manager.py`, `src/main.py` +- **해소 내용**: + - #324 머지 — 복구 주문 실행 후 `log_trade()` 호출, rationale에 `[blackout-recovery]` prefix + - #328 머지 — 가격 유효성 검증 (진입가 대비 급변 시 드롭), 세션 변경 시 새 파라미터로 재검증 - **요구사항**: REQ-V3-004 -### GAP-5: 시간장벽이 봉 개수 고정 (MEDIUM) +### GAP-5: 시간장벽이 봉 개수 고정 → ✅ 해소 (#329) -- **위치**: `src/analysis/triple_barrier.py:19` -- **문제**: `max_holding_bars` (고정 봉 수) 사용, v3 계획의 `max_holding_minutes` (캘린더 시간) 미반영 +- **위치**: `src/analysis/triple_barrier.py` +- ~~문제: `max_holding_bars` (고정 봉 수) 사용~~ +- **해소**: #329 머지 — `max_holding_minutes` (캘린더 분) 기반 시간장벽 전환 + - 봉 주기 무관하게 일정 시간 경과 시 장벽 도달 + - `max_holding_bars` deprecated 경고 유지 (하위 호환) - **요구사항**: REQ-V2-005 / v3 확장 +### GAP-6 (신규): FX PnL 운영 미활성 (LOW — 코드 완료) + +- **위치**: `src/db.py` (`fx_pnl`, `strategy_pnl` 컬럼 존재) +- **문제**: 스키마와 함수는 완료되었으나 운영 데이터에서 `fx_pnl` 전부 0 +- **영향**: USD 거래에서 환율 손익과 전략 손익이 분리되지 않아 성과 분석 부정확 +- **요구사항**: REQ-V3-007 + --- ## 3. 실거래 수익률 분석 @@ -244,18 +256,25 @@ Updated: 2026-02-28 - **문제**: 중첩 `def evaluate` 정의 (들여쓰기 오류) - **영향**: 런타임 실패 → 기본 전략으로 폴백 → 진화 시스템 사실상 무효 -### ROOT-5: v2 청산 로직이 부분 통합되었으나 실효성 부족 (HIGH) +### ROOT-5: v2 청산 로직이 부분 통합되었으나 실효성 부족 → ⚠️ 부분 해소 (#325) -- **현재 상태**: `src/main.py:500-583`에서 `evaluate_exit()` 기반 staged exit override가 동작함 - - 상태기계(HOLDING→BE_LOCK→ARMED→EXITED) 전이 구현 - - 4중 청산(hard stop, BE lock threat, ATR trailing, model/liquidity exit) 평가 -- **실효성 문제**: - - `hard_stop_pct`에 고정 `-2.0`이 기본값으로 들어가 v2 계획의 ATR 적응형 의도와 괴리 - - `be_arm_pct`/`arm_pct`가 playbook의 `take_profit_pct`에서 기계적 파생(`* 0.4`)되어 v2 계획의 독립 파라미터 튜닝 불가 - - `atr_value`, `pred_down_prob` 등 런타임 피처가 대부분 0.0으로 들어와 사실상 hard stop만 발동 -- **결론**: 코드 통합은 되었으나, 피처 공급과 파라미터 설정이 미비하여 v2 설계 가치가 실현되지 않는 상태 +**초기 진단 (2026-02-28 감사 기준):** +- `hard_stop_pct`에 고정 `-2.0`이 기본값으로 들어가 v2 계획의 ATR 적응형 의도와 괴리 +- `be_arm_pct`/`arm_pct`가 playbook의 `take_profit_pct`에서 기계적 파생(`* 0.4`)되어 v2 계획의 독립 파라미터 튜닝 불가 +- `atr_value`, `pred_down_prob` 등 런타임 피처가 0.0으로 공급되어 사실상 hard stop만 발동 -### ROOT-6: SELL 손익 계산이 부분청산/수량 불일치에 취약 (CRITICAL) +**현재 상태 (#325 머지 후):** +- `STAGED_EXIT_BE_ARM_PCT`, `STAGED_EXIT_ARM_PCT` 환경변수로 독립 파라미터 설정 가능 +- `_inject_staged_exit_features()`: KR 시장 ATR 실시간 계산 주입, RSI 기반 `pred_down_prob` 공급 +- KR ATR dynamic hard stop (#318)으로 `-2.0` 고정값 문제 해소 + +**잔여 리스크:** +- KR 외 시장(US 등)에서 `atr_value` 공급 경로 불완전 — hard stop 편향 잔존 가능 +- `pred_down_prob`가 RSI 프록시 수준 — 추후 실제 ML 모델 대체 권장 + +### ROOT-6: SELL 손익 계산이 부분청산/수량 불일치에 취약 (CRITICAL) → ✅ 해소 (#322) + +> **현재 상태**: #322 머지로 해소됨. 아래는 원인 발견 시점(2026-02-28) 진단 기록. - **위치**: `src/main.py:1658-1663`, `src/main.py:2755-2760` - **문제**: PnL 계산이 실제 매도 수량(`sell_qty`)이 아닌 직전 BUY의 `buy_qty`를 사용 @@ -263,7 +282,9 @@ Updated: 2026-02-28 - **영향**: 부분청산, 역분할/액분할, startup-sync 후 수량 드리프트 시 손익 과대/과소 계상 - **실증**: CRCA 이상치(BUY 146주 → SELL 15주에서 PnL +4,612 USD) 가 이 버그와 정합 -### ROOT-7: BUY 매칭 키에 exchange_code 미포함 — 잠재 오매칭 리스크 (HIGH) +### ROOT-7: BUY 매칭 키에 exchange_code 미포함 — 잠재 오매칭 리스크 (HIGH) → ✅ 해소 (#323) + +> **현재 상태**: #323 머지로 해소됨. 아래는 원인 발견 시점(2026-02-28) 진단 기록. - **위치**: `src/db.py:292-313` - **문제**: `get_latest_buy_trade()`가 `(stock_code, market)`만으로 매칭, `exchange_code` 미사용 @@ -283,17 +304,28 @@ Updated: 2026-02-28 | P1 | US 최소 가격 필터: $5 이하 종목 진입 차단 | 페니스탁 대폭락 방지 | 낮음 | | P1 | 진화 전략 코드 생성 시 syntax 검증 추가 | 진화 시스템 정상화 | 낮음 | -### 5.2 구조적 개선 (아키텍처 변경) +### 5.2 구조적 개선 현황 (2026-03-01 기준) -| 우선순위 | 방안 | 예상 효과 | 난이도 | -|----------|------|-----------|--------| -| **P0** | **SELL PnL 계산을 sell_qty 기준으로 수정 (ROOT-6)** | 손익 계상 정확도 확보, 이상치 제거 | 낮음 | -| **P0** | **v2 staged exit에 실제 피처 공급 (atr_value, pred_down_prob) + 독립 파라미터 설정 (ROOT-5)** | v2 설계 가치 실현, 수익 보호 | 중간 | -| P0 | BUY 매칭 키에 exchange_code 추가 (ROOT-7) | 오매칭 방지 | 낮음 | -| P0 | 블랙아웃 복구 주문에 `log_trade()` 추가 (GAP-4) | DB/성과 리포트 정합성 | 낮음 | -| P1 | 세션 전환 시 리스크 파라미터 동적 재로딩 (GAP-3 해소) | 세션별 최적 파라미터 적용 | 중간 | -| P1 | session_id를 거래 로그/의사결정 로그에 명시적 전달 (GAP-1,2 해소) | 세션별 성과 분석 가능 | 낮음 | -| P2 | 블랙아웃 복구 시 가격/세션 재검증 강화 (GAP-4 잔여) | 세션 변경 후 무효 주문 방지 | 중간 | +**완료 항목 (모니터링 단계):** + +| 항목 | 이슈 | 상태 | +|------|------|------| +| SELL PnL 계산을 sell_qty 기준으로 수정 (ROOT-6) | #322 | ✅ 머지 | +| v2 staged exit 피처 공급 + 독립 파라미터 설정 (ROOT-5) | #325 | ✅ 머지 | +| BUY 매칭 키에 exchange_code 추가 (ROOT-7) | #323 | ✅ 머지 | +| 블랙아웃 복구 주문 `log_trade()` 추가 (GAP-4) | #324 | ✅ 머지 | +| 세션 전환 리스크 파라미터 동적 재로딩 (GAP-3) | #327 | ✅ 머지 | +| session_id 거래/의사결정 로그 명시 전달 (GAP-1, GAP-2) | #326 | ✅ 머지 | +| 블랙아웃 복구 가격/세션 재검증 강화 (GAP-4 잔여) | #328 | ✅ 머지 | + +**잔여 개선 항목:** + +| 우선순위 | 방안 | 난이도 | +|----------|------|--------| +| P1 | US 시장 ATR 공급 경로 완성 (ROOT-5 잔여) | 중간 | +| P1 | FX PnL 운영 활성화 (REQ-V3-007) | 낮음 | +| P2 | pred_down_prob ML 모델 대체 (ROOT-5 잔여) | 높음 | +| P2 | 세션 경계 E2E 통합 테스트 보강 (GAP-3 잔여) | 낮음 | ### 5.3 권장 실행 순서 @@ -334,14 +366,26 @@ Phase 3 (중기): v3 세션 최적화 - ✅ 블랙아웃 복구 후 유효 intent 실행 (`tests/test_main.py:5811`) - ✅ 블랙아웃 복구 후 정책 거부 intent 드롭 (`tests/test_main.py:5851`) -### 테스트 미존재 +### 테스트 추가됨 (Phase 1~3, 2026-03-01) -- ❌ 세션 전환 훅 콜백 -- ❌ 세션 경계 리스크 파라미터 재로딩 -- ❌ DecisionLogger session_id 캡처 +- ✅ KR ATR 기반 동적 hard stop (`test_main.py` — #318) +- ✅ 재진입 쿨다운 (손절 후 동일 종목 매수 차단) (`test_main.py` — #319) +- ✅ US 최소 가격 필터 ($5 이하 차단) (`test_main.py` — #320) +- ✅ 진화 전략 syntax 검증 (`test_evolution.py` — #321) +- ✅ SELL PnL sell_qty 기준 계산 (`test_main.py` — #322) +- ✅ BUY 매칭 키 exchange_code 포함 (`test_db.py` — #323) +- ✅ 블랙아웃 복구 주문 DB 기록 (`test_main.py` — #324) +- ✅ staged exit에 실제 ATR/RSI 피처 공급 (`test_main.py` — #325) +- ✅ session_id 거래/의사결정 로그 명시적 전달 (`test_main.py`, `test_decision_logger.py` — #326) +- ✅ 블랙아웃 복구 후 유효 intent 실행 (`tests/test_main.py:5811`) +- ✅ 블랙아웃 복구 후 정책 거부 intent 드롭 (`tests/test_main.py:5851`) + +### 테스트 미존재 (잔여) + +- ❌ 세션 전환 훅 콜백 (GAP-3 잔여) +- ❌ 세션 경계 리스크 파라미터 재로딩 단위 테스트 (GAP-3 잔여) - ❌ 실거래 경로 ↔ v2 상태기계 통합 테스트 (피처 공급 포함) -- ❌ 블랙아웃 복구 주문의 DB 기록 검증 -- ❌ SELL PnL 계산 시 수량 불일치 케이스 +- ❌ FX PnL 운영 활성화 검증 (GAP-6) --- diff --git a/docs/ouroboros/85_loss_recovery_action_plan.md b/docs/ouroboros/85_loss_recovery_action_plan.md index 6004955..f2d82ac 100644 --- a/docs/ouroboros/85_loss_recovery_action_plan.md +++ b/docs/ouroboros/85_loss_recovery_action_plan.md @@ -1,16 +1,19 @@ # 손실 복구 실행 계획 작성일: 2026-02-28 +최종 업데이트: 2026-03-01 (Phase 1~3 완료 상태 반영) 기반 문서: [80_implementation_audit.md](./80_implementation_audit.md) (ROOT 7개 + GAP 5개) +> **2026-03-01 현황**: Phase 1 ✅ 완료, Phase 2 ✅ 완료, Phase 3 ✅ 기본 완료 (ACT-13 고도화 잔여) + --- ## 1. 요약 @@ -35,13 +38,13 @@ Updated: 2026-02-28 ## 2. Phase별 작업 분해 -### Phase 1: 즉시 — 손실 출혈 차단 +### Phase 1: 즉시 — 손실 출혈 차단 ✅ 완료 가장 큰 손실 패턴(노이즈 손절, 반복 매매, 페니스탁)을 즉시 제거한다. --- -#### ACT-01: KR 손절선 ATR 기반 동적 확대 +#### ACT-01: KR 손절선 ATR 기반 동적 확대 ✅ 머지 - **ROOT 참조**: ROOT-1 (hard_stop_pct -2%가 KR 소형주 변동성 대비 과소) - **Gitea 이슈**: feat: KR 손절선 ATR 기반 동적 확대 (-2% → ATR 적응형) @@ -60,7 +63,7 @@ Updated: 2026-02-28 --- -#### ACT-02: 손절 후 동일 종목 재진입 쿨다운 +#### ACT-02: 손절 후 동일 종목 재진입 쿨다운 ✅ 머지 - **ROOT 참조**: ROOT-2 (동일 종목 반복 매매) - **Gitea 이슈**: feat: 손절 후 동일 종목 재진입 쿨다운 (1~2시간) @@ -79,7 +82,7 @@ Updated: 2026-02-28 --- -#### ACT-03: US $5 이하 종목 진입 차단 필터 +#### ACT-03: US $5 이하 종목 진입 차단 필터 ✅ 머지 - **ROOT 참조**: ROOT-3 (미국 페니스탁 무분별 진입) - **Gitea 이슈**: feat: US $5 이하 종목 진입 차단 필터 @@ -97,7 +100,7 @@ Updated: 2026-02-28 --- -#### ACT-04: 진화 전략 코드 생성 시 syntax 검증 추가 +#### ACT-04: 진화 전략 코드 생성 시 syntax 검증 추가 ✅ 머지 - **ROOT 참조**: ROOT-4 (진화 전략 문법 오류) - **Gitea 이슈**: fix: 진화 전략 코드 생성 시 syntax 검증 추가 @@ -116,13 +119,13 @@ Updated: 2026-02-28 --- -### Phase 2: 단기 — 데이터 정합성 + v2 실효화 +### Phase 2: 단기 — 데이터 정합성 + v2 실효화 ✅ 완료 손익 계산 정확도를 확보하고, v2 청산 로직을 실효화한다. --- -#### ACT-05: SELL PnL 계산을 sell_qty 기준으로 수정 +#### ACT-05: SELL PnL 계산을 sell_qty 기준으로 수정 ✅ 머지 - **ROOT 참조**: ROOT-6 (CRITICAL — PnL 계산이 buy_qty 사용) - **Gitea 이슈**: fix(critical): SELL PnL 계산을 sell_qty 기준으로 수정 @@ -141,7 +144,7 @@ Updated: 2026-02-28 --- -#### ACT-06: BUY 매칭 키에 exchange_code 추가 +#### ACT-06: BUY 매칭 키에 exchange_code 추가 ✅ 머지 - **ROOT 참조**: ROOT-7 (BUY 매칭 키에 exchange_code 미포함) - **Gitea 이슈**: fix: BUY 매칭 키에 exchange_code 추가 @@ -159,12 +162,12 @@ Updated: 2026-02-28 --- -#### ACT-07: 블랙아웃 복구 주문에 log_trade() 추가 +#### ACT-07: 블랙아웃 복구 주문에 log_trade() 추가 ✅ 머지 - **ROOT 참조**: GAP-4 (블랙아웃 복구 주문 DB 미기록) - **Gitea 이슈**: fix: 블랙아웃 복구 주문에 log_trade() 추가 - **Gitea 이슈 번호**: #324 -- **변경 대상 파일**: `src/main.py` (line 694-791, 블랙아웃 복구 실행 경로) +- **변경 대상 파일**: `src/main.py` — `process_blackout_recovery_orders()` 함수 내 복구 주문 실행 경로 - **현재 동작**: 블랙아웃 복구 주문이 실행되나 `log_trade()` 호출 없음 → DB에 기록 안 됨 - **목표 동작**: 복구 주문 실행 후 `log_trade()` 호출하여 DB에 기록. rationale에 `[blackout-recovery]` prefix 추가 - **수용 기준**: @@ -178,7 +181,7 @@ Updated: 2026-02-28 --- -#### ACT-08: v2 staged exit에 실제 피처 공급 +#### ACT-08: v2 staged exit에 실제 피처 공급 ✅ 머지 - **ROOT 참조**: ROOT-5 (v2 청산 로직 실효성 부족) - **Gitea 이슈**: feat: v2 staged exit에 실제 피처(ATR, pred_down_prob) 공급 @@ -200,7 +203,7 @@ Updated: 2026-02-28 --- -#### ACT-09: session_id를 거래/의사결정 로그에 명시적 전달 +#### ACT-09: session_id를 거래/의사결정 로그에 명시적 전달 ✅ 머지 - **ROOT 참조**: GAP-1 (DecisionLogger session_id 미포함), GAP-2 (log_trade session_id 미전달) - **Gitea 이슈**: feat: session_id를 거래/의사결정 로그에 명시적 전달 @@ -223,13 +226,13 @@ Updated: 2026-02-28 --- -### Phase 3: 중기 — v3 세션 최적화 +### Phase 3: 중기 — v3 세션 최적화 ✅ 기본 완료 (ACT-13 고도화 잔여) 세션 경계 처리와 운영 거버넌스를 강화한다. --- -#### ACT-10: 세션 전환 시 리스크 파라미터 동적 재로딩 +#### ACT-10: 세션 전환 시 리스크 파라미터 동적 재로딩 ✅ 머지 - **ROOT 참조**: GAP-3 (세션 전환 시 리스크 파라미터 재로딩 없음) - **Gitea 이슈**: feat: 세션 전환 시 리스크 파라미터 동적 재로딩 @@ -241,14 +244,12 @@ Updated: 2026-02-28 - NXT_AFTER → KRX_REG 전환 시 파라미터 재로딩 확인 - 재로딩 이벤트 로그 기록 - 재로딩 실패 시 기존 파라미터 유지 (안전 폴백) -- **테스트 계획**: - - 단위: 세션 전환 훅 콜백 테스트 - - 단위: 재로딩 실패 시 폴백 테스트 +- **테스트**: `test_main.py`에 설정 오버라이드/리로드/폴백 단위 테스트 포함. **잔여**: 세션 경계 실시간 전환 E2E 보강 - **의존성**: ACT-09 (session_id 인프라) --- -#### ACT-11: 블랙아웃 복구 시 가격/세션 재검증 강화 +#### ACT-11: 블랙아웃 복구 시 가격/세션 재검증 강화 ✅ 머지 - **ROOT 참조**: GAP-4 잔여 (가격 유효성, 세션 변경 재적용 미구현) - **Gitea 이슈**: feat: 블랙아웃 복구 시 가격/세션 재검증 강화 @@ -268,7 +269,7 @@ Updated: 2026-02-28 --- -#### ACT-12: Triple Barrier 시간장벽을 캘린더 시간(분) 기반으로 전환 +#### ACT-12: Triple Barrier 시간장벽을 캘린더 시간(분) 기반으로 전환 ✅ 머지 - **ROOT 참조**: GAP-5 (시간장벽이 봉 개수 고정) - **Gitea 이슈**: feat: Triple Barrier 시간장벽을 캘린더 시간(분) 기반으로 전환 @@ -286,21 +287,13 @@ Updated: 2026-02-28 --- -#### ACT-13: CI 자동 검증 (정책 레지스트리 + TASK-REQ 매핑) +#### ACT-13: CI 자동 검증 (정책 레지스트리 + TASK-REQ 매핑) ✅ 기본 구현 완료, 고도화 잔여 - **ROOT 참조**: REQ-OPS-002 (정책 변경 시 레지스트리 업데이트 강제), REQ-OPS-003 (TASK-REQ 매핑 강제) - **Gitea 이슈**: infra: CI 자동 검증 (정책 레지스트리 + TASK-REQ 매핑) - **Gitea 이슈 번호**: #330 -- **변경 대상 파일**: `.gitea/workflows/`, `scripts/validate_governance_assets.py` -- **현재 동작**: CI 자동 검증 없음. 문서 검증은 수동 실행 -- **목표 동작**: - - PR 시 정책 레지스트리(`01_requirements_registry.md`) 변경 여부 자동 검증 - - TASK/이슈가 REQ-ID를 참조하는지 자동 검증 -- **수용 기준**: - - 정책 파일 변경 시 레지스트리 미업데이트면 CI 실패 - - 새 이슈/PR에 REQ-ID 미참조 시 경고 -- **테스트 계획**: - - CI 파이프라인 자체 테스트 (정상/실패 케이스) +- **현재 동작**: `.gitea/workflows/ci.yml`에서 `scripts/validate_governance_assets.py` + `scripts/validate_ouroboros_docs.py` 자동 실행 +- **잔여 고도화**: PR 본문 REQ/TASK/TEST 강제 레벨 상향, 정책 파일 미업데이트 시 CI 실패 기준 강화 - **의존성**: 없음 --- @@ -311,7 +304,7 @@ Updated: 2026-02-28 - 모든 ACT 항목에 대해 개별 테스트 작성 - 커버리지 >= 80% 유지 -- 기존 551개 테스트 전체 통과 확인 +- 현재 CI 기준 전체 테스트 통과 확인 (2026-03-01 기준 998 tests collected) ### 3.2 통합 테스트 @@ -389,4 +382,36 @@ Phase 3 --- +## 6. 미진 사항 (2026-03-01 기준) + +Phase 1~3 구현 완료 후에도 다음 항목이 운영상 미완료 상태이다. + +### 6.1 운영 검증 필요 + +| 항목 | 설명 | 우선순위 | +|------|------|----------| +| FX PnL 운영 활성화 | `fx_pnl`/`strategy_pnl` 컬럼 존재하나 모든 운영 데이터 값이 0 | P1 | +| 세션 경계 E2E 통합 테스트 보강 | `test_main.py`에 단위 테스트 존재; 세션 경계 실시간 전환 E2E 미작성 | P2 | +| v2 상태기계 통합 end-to-end | 실거래 경로에서 HOLDING→BE_LOCK→ARMED→EXITED 전체 시나리오 테스트 미작성 | P2 | + +### 6.2 아키텍처 수준 잔여 갭 + +| 항목 | 설명 | 배경 문서 | +|------|------|-----------| +| CI 자동 검증 고도화 (#330) | 기본 구현 완료(`validate_governance_assets.py` CI 연동); 규칙/강제수준 고도화 필요 | REQ-OPS-002, REQ-OPS-003 | +| pred_down_prob ML 모델 대체 | 현재 RSI 프록시 사용 — 추후 실제 GBDT/ML 모델로 대체 권장 | ROOT-5, ouroboros_plan_v2.txt §3.D | +| KR/US 파라미터 민감도 분석 | v2 계획의 be_arm_pct/arm_pct/atr_k 최적값 탐색 미수행 | ouroboros_plan_v2.txt §8 | + +### 6.3 v3 실험 매트릭스 미착수 + +ouroboros_plan_v3.txt §9에 정의된 3개 실험이 아직 시작되지 않았다. + +| 실험 ID | 시장 | 포커스 | 상태 | +|---------|------|--------|------| +| EXP-KR-01 | KR | NXT 야간 특화 (p_thresh 0.65) | ❌ 미착수 | +| EXP-US-01 | US | 21h 준연속 운용 (atr_k 2.5) | ❌ 미착수 | +| EXP-HYB-01 | Global | KR 낮 + US 밤 연계 레짐 자산배분 | ❌ 미착수 | + +--- + *끝.* diff --git a/docs/ouroboros/README.md b/docs/ouroboros/README.md index 6e53e6c..13a8292 100644 --- a/docs/ouroboros/README.md +++ b/docs/ouroboros/README.md @@ -18,13 +18,15 @@ Updated: 2026-02-26 4. v3 실행 지시서: [20_phase_v3_execution.md](./20_phase_v3_execution.md) 5. 코드 레벨 작업 지시: [30_code_level_work_orders.md](./30_code_level_work_orders.md) 6. 수용 기준/테스트 계획: [40_acceptance_and_test_plan.md](./40_acceptance_and_test_plan.md) -7. PM 시나리오/이슈 분류: [50_scenario_matrix_and_issue_taxonomy.md](./50_scenario_matrix_and_issue_taxonomy.md) -8. TPM 제어 프로토콜/수용 매트릭스: [50_tpm_control_protocol.md](./50_tpm_control_protocol.md) +7. PM 시나리오/이슈 분류 **(A)**: [50_scenario_matrix_and_issue_taxonomy.md](./50_scenario_matrix_and_issue_taxonomy.md) +8. TPM 제어 프로토콜/수용 매트릭스 **(B)**: [50_tpm_control_protocol.md](./50_tpm_control_protocol.md) 9. 저장소 강제 설정 체크리스트: [60_repo_enforcement_checklist.md](./60_repo_enforcement_checklist.md) 10. 메인 에이전트 아이디에이션 백로그: [70_main_agent_ideation.md](./70_main_agent_ideation.md) 11. v2/v3 구현 감사 및 수익률 분석: [80_implementation_audit.md](./80_implementation_audit.md) 12. 손실 복구 실행 계획: [85_loss_recovery_action_plan.md](./85_loss_recovery_action_plan.md) +> **참고**: 7번·8번은 `50_` 프리픽스를 공유합니다. (A) = 시나리오/이슈 분류, (B) = TPM 제어 프로토콜. + ## 운영 규칙 - 계획 변경은 반드시 `01_requirements_registry.md`의 ID 정의부터 수정한다. diff --git a/docs/requirements-log.md b/docs/requirements-log.md index bd18e04..19daeee 100644 --- a/docs/requirements-log.md +++ b/docs/requirements-log.md @@ -87,7 +87,7 @@ - 선정 기준 추적 → Evolution 시스템 최적화 가능 - API 장애 시 정적 watchlist로 자동 전환 -**참고:** Realtime 모드 전용. Daily 모드는 배치 효율성을 위해 정적 watchlist 사용. +**참고 (당시 구현 기준):** Realtime 모드 전용으로 설계되었으나, 이후 Daily 경로에서도 스캐너를 사용하도록 변경됨. 해외 fallback도 정적 watchlist → 동적 유니버스(active/recent/holdings)로 전환 (2026-02-16 참조). **이슈/PR:** #76, #77 @@ -388,3 +388,126 @@ Order result: 모의투자 매수주문이 완료 되었습니다. ✓ - `ruff check src/analysis/backtest_pipeline.py tests/test_backtest_pipeline_integration.py` **이슈/PR:** #305 + +--- + +## 2026-02-28 ~ 2026-03-01 + +### v2/v3 손실 복구 실행 계획 — Phase 1 완료 (#318~#321) + +**배경:** +- `docs/ouroboros/80_implementation_audit.md` 감사 결과 식별된 7개 근본 원인(ROOT) 및 5개 구현 갭(GAP) 중 + 가장 큰 손실 패턴 4개를 Phase 1로 즉시 제거. + +**구현 내용:** + +1. **ACT-01: KR 손절선 ATR 기반 동적 확대** (#318) + - `src/main.py`, `src/config.py` + - KR 시장: ATR(14) 기반 동적 hard stop (`k=2.0`, 범위 -2%~-7%) + - ATR 미제공 시 기존 -2% 폴백 + - ROOT-1 (hard_stop_pct 고정값 과소) 해소 + +2. **ACT-02: 손절 후 동일 종목 재진입 쿨다운** (#319) + - `src/main.py`, `src/config.py` + - 손절(pnl<0) 후 동일 종목 `COOLDOWN_MINUTES`(기본 120분) 동안 BUY 차단 + - 익절에는 미적용 + - ROOT-2 (동일 종목 반복 매매) 해소 + +3. **ACT-03: US $5 이하 종목 진입 차단 필터** (#320) + - `src/main.py`, `src/config.py` + - US 시장 BUY 시 현재가 `US_MIN_PRICE`(기본 $5) 이하 차단 + - ROOT-3 (미국 페니스탁 무분별 진입) 해소 + +4. **ACT-04: 진화 전략 코드 syntax 검증** (#321) + - `src/evolution/optimizer.py` + - `ast.parse()` + `compile()` 선검증 후 통과한 코드만 저장 + - ROOT-4 (진화 전략 문법 오류) 해소 + +**이슈/PR:** #318, #319, #320, #321 + +--- + +### v2/v3 손실 복구 실행 계획 — Phase 2 완료 (#322~#326) + +**배경:** +- 손익 계산 정확도 확보 및 v2 청산 로직 실효화. + +**구현 내용:** + +1. **ACT-05: SELL PnL 계산을 sell_qty 기준으로 수정** (#322) + - `src/main.py` (line 1658-1663, 2755-2760) + - `trade_pnl = (trade_price - buy_price) * sell_qty`로 변경 + - ROOT-6 (PnL 계산 buy_qty 사용 CRITICAL) 해소 + +2. **ACT-06: BUY 매칭 키에 exchange_code 추가** (#323) + - `src/db.py` + - `get_latest_buy_trade()`가 `(stock_code, market, exchange_code)` 기준 매칭 + - exchange_code NULL인 레거시 데이터 하위 호환 유지 + - ROOT-7 (오매칭 리스크) 해소 + +3. **ACT-07: 블랙아웃 복구 주문에 log_trade() 추가** (#324) + - `src/main.py` (블랙아웃 복구 실행 경로) + - 복구 주문 실행 후 `log_trade()` 호출, rationale에 `[blackout-recovery]` prefix + - GAP-4 (블랙아웃 복구 주문 DB 미기록) 해소 + +4. **ACT-08: v2 staged exit에 실제 피처 공급** (#325) + - `src/main.py`, `src/strategy/exit_rules.py` + - `atr_value`: ATR(14) 실시간 계산 공급 + - `pred_down_prob`: RSI 기반 하락 확률 추정값 공급 (ML 모델 대체 가능) + - `be_arm_pct`/`arm_pct` 독립 파라미터 설정 가능 (take_profit_pct * 0.4 파생 제거) + - ROOT-5 (v2 청산 로직 실효성 부족) 해소 + +5. **ACT-09: session_id를 거래/의사결정 로그에 명시적 전달** (#326) + - `src/logging/decision_logger.py`, `src/main.py`, `src/db.py` + - `log_decision()`: session_id 파라미터 추가 + - `log_trade()`: 런타임 session_id 명시적 전달 + - GAP-1, GAP-2 (session_id 미포함) 부분 해소 + +**이슈/PR:** #322, #323, #324, #325, #326 + +--- + +### v2/v3 손실 복구 실행 계획 — Phase 3 부분 완료 (#327~#329) + +**배경:** +- 세션 경계 처리 및 시간장벽 캘린더 기반 전환. + +**구현 내용:** + +1. **ACT-10: 세션 전환 시 리스크 파라미터 동적 재로딩** (#327) + - `src/main.py`, `src/config.py` + - 세션 경계 변경 이벤트 시 `SESSION_RISK_PROFILES_JSON` 기반 재로딩 + - 재로딩 실패 시 기존 파라미터 유지 (안전 폴백) + - GAP-3 (세션 전환 시 파라미터 재로딩 없음) 부분 해소 + +2. **ACT-11: 블랙아웃 복구 시 가격/세션 재검증 강화** (#328) + - `src/main.py`, `src/core/blackout_manager.py` + - 복구 시 현재 시세 조회하여 가격 유효성 검증 (진입가 대비 급등/급락 시 드롭) + - 세션 변경 시 새 세션의 파라미터로 재검증 + - GAP-4 잔여 (가격/세션 재검증) 부분 해소 + +3. **ACT-12: Triple Barrier 시간장벽을 캘린더 시간(분) 기반으로 전환** (#329) + - `src/analysis/triple_barrier.py` + - `max_holding_minutes` (캘린더 분) 기반 전환, 봉 주기 무관 일관 동작 + - 기존 `max_holding_bars` deprecated 경고 유지 (하위 호환) + - GAP-5 (시간장벽 봉 개수 고정) 해소 + +**미완료 (ACT-13):** +- **#330: CI 자동 검증 (정책 레지스트리 + TASK-REQ 매핑)** — 문서 구조화 작업으로 대체 진행 중 + +**이슈/PR:** #327, #328, #329 + +--- + +### v2/v3 문서 구조화 및 감사 문서 작성 (#331) + +**배경:** +- Phase 1~3 구현 완료 후 감사 결과와 실행 계획을 문서화 +- 기존 감사 문서가 산발적으로 관리되어 통합 정리 필요 + +**구현 내용:** +- `docs/ouroboros/80_implementation_audit.md` 신규 작성: v2/v3 구현 감사 + 실거래 수익률 분석 +- `docs/ouroboros/85_loss_recovery_action_plan.md` 신규 작성: ROOT/GAP 해소 Phase별 실행 계획 +- `scripts/audit_queries.sql` 신규 작성: 성과 재현용 표준 집계 SQL + +**이슈/PR:** #331 diff --git a/docs/testing.md b/docs/testing.md index 83aa6af..e385697 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -2,7 +2,7 @@ ## Test Structure -**551 tests** across **25 files**. `asyncio_mode = "auto"` in pyproject.toml — async tests need no special decorator. +**998 tests** across **41 files**. `asyncio_mode = "auto"` in pyproject.toml — async tests need no special decorator. The `settings` fixture in `conftest.py` provides safe defaults with test credentials and in-memory DB. @@ -23,6 +23,8 @@ The `settings` fixture in `conftest.py` provides safe defaults with test credent - Network error handling - SSL context configuration +> **Note**: 아래 파일별 테스트 수는 릴리즈 시점 스냅샷이며 실제 수치와 다를 수 있습니다. 현재 정확한 수치는 `pytest --collect-only -q`로 확인하세요. + ##### `tests/test_brain.py` (24 tests) - Valid JSON parsing and markdown-wrapped JSON handling - Malformed JSON fallback @@ -90,7 +92,7 @@ The `settings` fixture in `conftest.py` provides safe defaults with test credent - Python-first filtering pipeline - RSI and volume ratio filter logic - Candidate scoring and ranking -- Fallback to static watchlist +- Fallback to static watchlist (domestic) or dynamic universe (overseas) #### Context & Memory @@ -138,8 +140,8 @@ The `settings` fixture in `conftest.py` provides safe defaults with test credent #### Dashboard ##### `tests/test_dashboard.py` (14 tests) -- FastAPI endpoint responses (8 API routes) -- Status, playbook, scorecard, performance, context, decisions, scenarios +- FastAPI endpoint responses (10 API routes) +- Status, playbook, scorecard, performance, context, decisions, scenarios, pnl/history, positions - Query parameter handling (market, date, limit) #### Performance & Quality -- 2.49.1