From d4d7f31c659393056c89420abe2d8cf1319cbaf6 Mon Sep 17 00:00:00 2001 From: jongjae Date: Thu, 4 Jun 2026 10:47:01 +0900 Subject: [PATCH] =?UTF-8?q?[2026-06-04]=20=EB=AC=B8=EC=84=9C=20=EC=97=AD?= =?UTF-8?q?=ED=95=A0=20=EC=9E=AC=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 549 +++++++++++++++++++++++++---------------------------- CLAUDE.md | 550 +++++++++++++++++++++++++----------------------------- README.md | 186 ++++++++---------- 3 files changed, 587 insertions(+), 698 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 7da0872..b85d4f6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,337 +1,302 @@ -# StockBot v3.0 - Codex 운영 가이드 +# StockBot v3.0 - Codex Operating Guide -> 최종 수정: 2026-06-04 -> 인프라: 로컬 Windows → Synology NAS Docker 이전 예정 -> 현재 모드: 모의투자 (KIS_MOCK=true, DRY_RUN=true) +> Last updated: 2026-06-04 +> Runtime: local Windows now, planned Synology NAS Docker migration later +> Current mode: paper trading / dry run (`KIS_MOCK=true`, `DRY_RUN=true`) -## Current safety policy +This file is written for Codex. Keep it operational, explicit, and easy for an +agent to follow. Human-facing project background belongs in `README.md`. -- AI is for market review and proposals only; code decides entries and exits. -- Evening Codex must not edit `app/config.py` or execution/strategy/risk code directly. -- Parameter changes must be written to `reports/proposals/YYYY-MM-DD_strategy_proposal.md` with evidence and manual approval required. -- `FORCE_EXIT = "14:50"` remains immutable. +## Agent Role -## Current implementation status - 2026-06-04 +- When working alone: analyze, plan, implement, verify, and self-review. +- When collaborating with Claude Code: act as reviewer/evaluator, not as a + parallel implementer. +- If Claude Code is actively editing a file, do not edit that same file. +- Do not ask for the full conversation history during collaboration. Use only + the approved plan, relevant files, diff, test results, and acceptance criteria. +- Limit review loops: one pass for small work, at most two passes for medium + work. Split large work into phase gates. -- Mode: paper trading / dry-run focused. Real-cash trading is not approved yet. -- Approved strategy change applied: `ENTRY_START = "09:20"`. -- Applied runtime parameter: `MAX_HOLD_MIN = 90`. -- `FORCE_EXIT = "14:50"` remains unchanged. -- `avoid_sectors` runtime bug fixed: `main.py` now passes sector context into `check_entry()`. -- Sector handling now keeps a `ticker_sectors` cache when available and uses name-based hints for known avoid-sector cases. +## Solo Workflow + +1. Analyze the request and classify scope: small, medium, or large. +2. Write an explicit plan before implementation. +3. Implement one file at a time and keep the scope tight. +4. Run focused verification. +5. Perform the veteran self-review below. +6. If the score is below 90, fix the highest-leverage issues and review again. + +Use this exact self-review format: + +```text +Veteran role: +Overall score: <0-100> +Decision: PASS | FAIL + +Category scores: +- Correctness and requirement fit: /30 - +- Safety, security, and failure handling: /20 - +- Maintainability and architecture fit: /20 - +- Testability and verification: /15 - +- Scope control and operational readiness: /10 - +- Clarity of handoff and reviewer confidence: /5 - + +Blocking issues preventing 90+: +- + +Highest-leverage fixes: +- +``` + +## Safety Policy + +- AI is for market review, context generation, and proposals only. +- The code decides entries, exits, risk gates, and order behavior. +- Runtime ML model scores are observation-only. They may be logged and stored, + but must not block buys, resize positions, or override exits unless explicitly + approved later. +- Evening review must not directly edit `app/config.py`, `app/execution/`, + `app/strategy/`, or `app/risk/`. Write proposal reports instead. +- Strategy parameter changes must be written to + `reports/proposals/YYYY-MM-DD_strategy_proposal.md` with evidence and manual + approval requirements. +- `FORCE_EXIT = "14:50"` is immutable. +- Stop-loss checks must remain higher priority than profit-taking checks. +- Real-cash trading is not approved yet. + +## Current Implementation Status + +- Current mode is paper trading / dry-run focused. +- Approved strategy values: + - `ENTRY_START = "09:20"` + - `MAX_HOLD_MIN = 90` + - `FORCE_EXIT = "14:50"` unchanged +- `avoid_sectors` filtering is active at runtime. `main.py` passes sector + context into `check_entry()`. +- Sector handling keeps a `ticker_sectors` cache and uses name-based hints for + known avoid-sector cases. - Re-entry controls are active: - - `TIME`/`FORCE` cooldown is based on final exit time, not original entry time. - - `TP1`/`TP2` final exits block same-day re-entry for that ticker. - - Re-entry control state is restored from today's DB rows after bot restart. -- Duplicate execution guards are active: + - `TIME` and `FORCE` cooldown is based on final exit time, not entry time. + - Final `TP1`/`TP2` exits block same-day re-entry for that ticker. + - Re-entry control state is restored from today's DB rows after restart. +- Duplicate bot execution guards are active: - `app/main.py` uses `SingleInstanceLock` on `logs/stockbot.lock`. - - `scripts/start_bot.py` stops the PID-file process and scans for existing `app/main.py` processes before starting one new bot. + - `scripts/start_bot.py` stops the PID-file process and scans for existing + `app/main.py` processes before starting one new bot. - `scripts/run_morning.ps1` is the only owner of post-morning bot startup. - - `.claude/commands/morning.md` must not call `/start-bot` or `scripts/start_bot.py`; it only creates and sends morning context. + - `.claude/commands/morning.md` must not call `/start-bot` or + `scripts/start_bot.py`. - KIS stability hardening is active: - - Mode-specific request spacing in `KISClient` (`mock` more conservative than `real`). + - Mode-specific request spacing in `KISClient`. - Price lookups retry transient KIS timeout/rate-limit errors. - - DRY_RUN buy/sell paths can reuse the already-read quote as the simulated fill price to reduce extra API calls. -- Daily summary duplicate guard is active; summary Discord failures are logged without crashing settlement. -- Data layer: `entry_snapshots` and `post_entry_snapshots` are active for training data. -- Post-entry sampling: 60s, 180s, 300s, and 600s after successful entry. -- Training data export: `scripts/export_training_dataset.py`. -- External data collection: - - Daily market features: `scripts/collect_daily_features.py` with KIS fallback when pykrx fails. - - KIS minute bars: `scripts/collect_minute_data.py`, default ETF/ETN exclusion, multi-window collection from 09:30 to 14:00. - - External dataset builder: `scripts/build_external_training_dataset.py`, using prior daily OHLCV for breakout targets. -- ML engine: + - DRY_RUN buy/sell paths can reuse the already-read quote as the simulated + fill price to reduce extra API calls. +- Daily summary has a duplicate guard; Discord settlement-send failures are + logged without crashing settlement. +- Data layer: + - `entry_snapshots` are active. + - `post_entry_snapshots` sample 60s, 180s, 300s, and 600s after entry. + - Bot data export: `scripts/export_training_dataset.py`. +- External data and ML: + - Daily features: `scripts/collect_daily_features.py`, with KIS fallback when + pykrx fails. + - KIS minute bars: `scripts/collect_minute_data.py`, ETF/ETN excluded by + default, multi-window collection from 09:30 to 14:00. + - External dataset builder: `scripts/build_external_training_dataset.py`. - Training: `scripts/train_ai_model.py`. - - Model output: `models/scalping_model.joblib`. - - Metrics output: `models/scalping_model.metrics.json`. - Runtime loader: `app/ml/predictor.py`. -- Latest successful training run: 2026-06-02 18:36, 5,773 rows total (`external_training_dataset.csv` 5,720 + bot dataset 53). -- Latest metrics: `label_stop_loss` ROC-AUC 0.896, `label_win` ROC-AUC 0.715. -- Training features exclude future/outcome leakage columns such as `ret_*`, `mfe_*`, `mae_*`, `price_*`, `pnl`, and `exit_price`. -- AI runtime mode: observation only. If a model exists, entry-time scores are logged and saved to `entry_snapshots`; they do not block or resize trades. -- Training schedule: `StockBot_Training` runs at 16:00 on trading days via `scripts/run_training_pipeline.ps1`; latest successful full run was 2026-06-02 18:36. -- Latest daily review/proposal files exist through 2026-06-02. 2026-06-03 was skipped as a market holiday. -- Dependency install: - - `requirements.txt` includes `app/requirements.txt`. - - `scripts/install_dependencies.ps1` installs from `vendor/wheels` when available. - - `scripts/download_dependencies.ps1` builds the local wheelhouse. + - Latest successful training run: 2026-06-02 18:36. + - Latest rows: 5,773 total (`external_training_dataset.csv` 5,720 + bot + dataset 53). + - Latest metrics: `label_stop_loss` ROC-AUC 0.896, `label_win` ROC-AUC 0.715. +- Latest daily review/proposal files exist through 2026-06-02. +- 2026-06-03 was skipped as a market holiday. -## Current operational risks - 2026-06-04 +## Current Risks -- Model is still observation-only and is dominated by external pretraining rows; bot-trade labels are 53 rows. -- KIS minute-bar collection is verified for same-day windows, but historical depth and ticker coverage remain limited. +- The ML model is observation-only and still dominated by external pretraining + rows; bot-trade labels are only 53 rows. +- KIS minute data is verified for same-day windows, but historical depth and + ticker coverage are limited. - External minute data is pretraining data, not actual bot-trade data. -- pykrx daily feature collection can fail for same-day data; KIS fallback is active. -- KIS rate limits can still happen if multiple scripts/processes call KIS concurrently; runtime retries reduce but do not eliminate this. -- 2026-06-03 holiday training run logged a failure at the holiday-check step instead of a clean skip; inspect before relying on holiday automation noise level. -- 2026-06-04 morning duplicate execution happened before the `/morning` instruction fix; next scheduled morning run should be checked for exactly one context run and one `start_bot.py` startup. -- Real-cash mode still needs stronger fill, partial-fill, unfilled-order, cancel/replace, and recovery logic. -- Security cleanup is still needed: keep secrets out of tracked files and remote URLs; prefer environment variables for webhooks and credentials. -- Existing logs and older docs contain encoding damage; new operational notes should stay ASCII unless the file encoding is intentionally cleaned. +- pykrx daily feature collection can fail for same-day data; KIS fallback is + active. +- KIS rate limits can still happen if multiple scripts or processes call KIS at + the same time. +- The 2026-06-03 holiday training run logged a failure at the holiday-check + step instead of a clean skip. Inspect this before relying on holiday + automation noise level. +- The 2026-06-04 morning duplicate execution happened before the `/morning` + instruction fix. The next scheduled morning run should be checked for exactly + one context generation and one `start_bot.py` startup. +- Real-cash mode still needs stronger fill, partial-fill, unfilled-order, + cancel/replace, and recovery logic. +- Security cleanup is needed: keep webhooks, credentials, tokens, and remote + credentials out of tracked files and remote URLs. +- Older logs contain encoding damage. New operational notes should stay ASCII + unless the target file intentionally uses another encoding. ---- +## Automation Flow -## 프로젝트 개요 +```text +08:15 StockBot_Morning -> scripts/run_morning.ps1 -> /morning + Build data/daily_context.json. + After /morning exits, run_morning.ps1 calls python scripts/start_bot.py. -| 항목 | 내용 | -|------|------| -| 목표 | KIS API 기반 한국 주식 단타 자동매매 | -| 전략 | 변동성 돌파 (K=0.5) | -| 언어 | Python 3.11 | -| DB | SQLite (data/stockbot.db) | -| 알림 | Discord Webhook (거래 알림 + 코드 변경 알림 채널 분리) | -| AI | Codex headless (`Codex -p "/커맨드" --dangerously-skip-permissions`) | -| 코드 관리 | Gitea (NAS) — 파일 수정 후 확인 없이 자동 commit + push | - ---- - -## Codex 권한 및 자동화 설정 - -- Codex 환경변수는 `.codex/config.toml`에서 관리한다. -- Stop 훅은 `.codex/hooks.json`을 통해 `.claude/discord_notify.py`를 호출한다. -- 파일 수정 완료 후 확인 없이 커밋 + `git push origin master`까지 수행한다. -- 단, `.env`, 실행 중 생성 파일, 사용자 작업 중 파일은 커밋하지 않는다. -- 인코딩: `PYTHONUTF8=1`, `PYTHONIOENCODING=utf-8` 환경변수 설정 - ---- - -## 핵심 설계 원칙 (절대 불변) - -1. **14:50 강제 청산** — 하드코딩, 예외 없음 -2. **손절 우선** — AI 판단과 무관하게 손절 룰 항상 우선순위 1위 -3. **AI 역할 분리** — Codex는 장 전 분석 + 장 후 피드백만, 실시간 매매 개입 불가 -4. **검증 순서** — 모의투자 3개월 → 조건 충족 → 실거래 - ---- - -## 하루 자동화 흐름 - -``` -08:15 StockBot_Morning → run_morning.ps1 → Codex/Claude /morning - RSS+네이버 뉴스+KIS 수급 분석 → daily_context.json - /morning 종료 후 run_morning.ps1이 python scripts/start_bot.py 호출 -08:30 봇이 daily_context.json 로드 → Discord 전송 → 유니버스 30종목 확정 -08:50 목표가 계산 -09:00 아침 세션 시작 (변동성 돌파 신호 + AI 필터) - B안: 연속 손절 시 포지션 크기 자동 축소 (0회→1.0× / 1회→0.7× / 2회→0.5× / 3+→0.3×) -11:00 midday_context.json 미로드 시 신규 진입 일시 중단 -11:20 StockBot_Midday → run_midday.ps1 → Codex /midday - 오전 결과+시장 스냅샷 수집 → midday_context.json 저장 - 파일 생성 즉시 봇이 감지 → 점심 세션 자동 시작 -14:00 신규 진입 마감 -14:50 강제 전량 청산 (절대 불변) -15:10 일일 결산 → Discord 전송 -15:30 StockBot_Evening → run_evening.ps1 → Codex /evening - 결과 분석 + 리포트/제안서 저장 +08:30 Bot loads daily_context.json and builds the watch universe. +08:50 Bot calculates volatility breakout targets. +09:00 Morning trading session starts. +11:00 New entries pause if midday_context.json has not loaded. +11:20 StockBot_Midday -> scripts/run_midday.ps1 -> /midday + Build data/midday_context.json; bot detects it and starts lunch controls. +14:00 New entries stop; exits continue. +14:50 Force exit all positions. This time is immutable. +15:10 Daily settlement and Discord summary. +15:30 StockBot_Evening -> scripts/run_evening.ps1 -> /evening + Write daily report and proposal report when needed. +16:00 StockBot_Training -> scripts/run_training_pipeline.ps1 ``` -### 스케줄러 스크립트 주의사항 (scripts/run_*.ps1) -- 경로: `$PROJECT = Split-Path -Parent $PSScriptRoot` (한글 경로 인코딩 문제 방지) -- CLI 실행: `scripts/stockbot_env.ps1`의 `Resolve-StockBotClaude`가 `claude.cmd`를 우선 찾고 없으면 `codex.cmd`를 사용 -- 인코딩: `New-Object System.Text.UTF8Encoding $false` + UTF-8 BOM으로 저장 -- 봇 시작: `scripts/run_morning.ps1`이 `/morning` 완료 후 `python scripts/start_bot.py`를 직접 실행 -- 로그: `logs/morning.log`, `logs/midday.log`, `logs/evening.log`, `logs/training.log`, `logs/bot_stderr.log`, `logs/stockbot.log` +## Slash Command Responsibilities ---- +### `/morning` -## Codex 역할 상세 +1. Run `python app/ai/morning.py --print`. +2. Analyze collected news, KIS flow, sectors, and ticker-specific news. +3. Write `data/daily_context.json`. +4. Send the morning Discord summary. +5. Do not start the bot. Startup belongs only to `scripts/run_morning.ps1`. -### 장 전 분석 — `/morning` 슬래시 커맨드 -``` -1. python app/ai/morning.py --print (뉴스 크롤링 + KIS 수급 수집) -2. Codex가 데이터 분석 → 시장 분위기/섹터/boosted_tickers 판단 -3. data/daily_context.json 저장 -4. Discord로 분석 요약 전송 -5. 여기서는 봇을 시작하지 않음. 봇 시작은 run_morning.ps1만 담당. +### `/midday` + +1. Run `python app/ai/midday.py --print`. +2. Compare morning context with actual morning trades and market snapshot. +3. Write `data/midday_context.json`. +4. Send the midday Discord summary. + +### `/evening` + +1. Run `python app/ai/evening.py --print`. +2. Review trades, win rate, PnL, fees, exit distribution, overtrading, AI + filter quality, and execution quality. +3. Write `reports/daily/YYYY-MM-DD.md`. +4. If a strategy change is justified, write + `reports/proposals/YYYY-MM-DD_strategy_proposal.md`. +5. Do not directly edit runtime strategy/config/risk/execution code during + evening review. +6. Check live-readiness criteria. +7. Send a concise Discord summary. + +### `/start-bot` + +1. Run `python scripts/start_bot.py`. +2. The script stops existing PID-file and scanned `app/main.py` processes. +3. It starts exactly one detached `app/main.py` process. +4. It writes `logs/bot.pid` and sends the Discord start notification. + +## Important Files + +```text +app/main.py Main trading loop and runtime orchestration +app/config.py Strategy parameters +app/strategy/volatility_breakout.py Entry/exit signal logic +app/risk/manager.py L1-L5 risk controls and L3-B sizing +app/execution/kis_client.py KIS REST/WebSocket wrapper +app/execution/order_executor.py Order execution and trade persistence +app/db/models.py SQLite schema +app/db/repository.py DB access helpers +app/ai/morning.py Morning data collection +app/ai/midday.py Midday data collection +app/ai/evening.py Evening data collection +scripts/start_bot.py Deterministic single-bot startup +scripts/run_morning.ps1 Scheduler morning job +scripts/run_midday.ps1 Scheduler midday job +scripts/run_evening.ps1 Scheduler evening job +scripts/run_training_pipeline.ps1 Training pipeline ``` -### 장중 분석 — `/midday` 슬래시 커맨드 -``` -1. python app/ai/midday.py --print (오전 거래 결과 + 현재 시장 스냅샷 수집) -2. 오전 daily_context 예측 vs 실제 결과 비교 분석 -3. 점심 세션 파라미터 결정 (진입 허용 여부, 포지션 배율, 섹터 업데이트) -4. data/midday_context.json 저장 → 봇이 즉시 감지해 점심 세션 시작 -5. Discord로 장중 분석 전송 -``` +## Edit Boundaries -### 장 후 피드백 — `/evening` 슬래시 커맨드 -``` -1. python app/ai/evening.py --print (오늘 매매 내역 조회) -2. 승률/손익/이상패턴 분석 -3. app/config.py 파라미터 조정 (문제 명확할 때만) -4. reports/daily/날짜.md 저장 -5. 실전 전환 조건 5가지 체크 -6. Discord로 요약 전송 -``` +Freely editable when the task calls for it: -### 봇 시작 — `/start-bot` 슬래시 커맨드 -``` -1. python scripts/start_bot.py 실행 -2. PID 파일 + 프로세스 스캔으로 기존 app/main.py 종료 -3. app/main.py를 DETACHED_PROCESS로 백그라운드 시작 -4. logs/bot.pid 저장 + Discord "[모의투자] 자동매매 봇 시작" 알림 -``` +- `app/config.py` +- `app/strategy/volatility_breakout.py` +- `app/risk/manager.py` +- `reports/` +- Documentation files ---- +Requires explicit user approval: -## Discord 알림 구조 +- Structural changes to `app/main.py` +- `app/execution/` +- `app/db/` +- Database schema changes +- Real-cash trading behavior -| 채널 | 내용 | 발신 | -|------|------|------| -| 거래 알림 | 매수/매도/손절/결산 | `app/monitor/notifier.py` | -| 코드 변경 | 커밋 내용 + Push 완료 여부 | `.claude/discord_notify.py` (Stop 훅, `.codex/hooks.json`에서도 호출) | +Never edit or commit: -- 코드 변경 알림: **커밋이 있을 때만** 발송 (스케줄러 태스크 등 노이즈 없음) -- Discord 요청 시 반드시 `User-Agent: DiscordBot (stockbot, 1.0)` 헤더 포함 (Cloudflare 차단 방지) +- `.env` +- token files +- runtime DB files +- runtime logs +- `logs/stockbot.lock` +- files the user says they are currently editing ---- +Never change: -## 파일 구조 +- `FORCE_EXIT = "14:50"` +- stop-loss priority over profit-taking -``` -stockbot_v3/ -├── AGENTS.md -├── .env ← API 키 (Git 절대 제외) -├── .codex/ -│ ├── config.toml ← Codex 환경변수 설정 -│ └── hooks.json ← Stop 훅에서 .claude/discord_notify.py 호출 -├── .claude/ -│ ├── commands/ ← /morning, /midday, /evening, /start-bot 명령 -│ ├── settings.json ← Claude 권한 설정 -│ └── discord_notify.py ← 코드 변경 Discord 전송 -├── app/ -│ ├── main.py ← 메인 매매 루프 (승인 필요) -│ ├── config.py ← 전략 파라미터 (수정 가능) -│ ├── ai/ -│ │ ├── morning.py ← 장 전 데이터 수집 -│ │ ├── midday.py ← 장중 데이터 수집 -│ │ └── evening.py ← 장 후 데이터 수집 -│ ├── strategy/ -│ │ └── volatility_breakout.py ← 전략 로직 (수정 가능) -│ ├── execution/ -│ │ ├── kis_client.py ← KIS API 래퍼 (승인 필요) -│ │ └── order_executor.py ← 주문 실행 (승인 필요) -│ ├── risk/ -│ │ └── manager.py ← 리스크 관리 (수정 가능) -│ ├── monitor/ -│ │ └── notifier.py ← Discord Webhook -│ └── db/ -│ ├── models.py ← SQLite 스키마 (승인 필요) -│ └── repository.py ← DB 접근 (승인 필요) -├── scripts/ -│ ├── run_bot.ps1 ← 스케줄러용 봇 시작 -│ ├── run_morning.ps1 ← 스케줄러용 morning -│ ├── run_midday.ps1 ← 스케줄러용 midday (11:20) -│ ├── run_evening.ps1 ← 스케줄러용 evening -│ ├── run_training_pipeline.ps1 -│ ├── start_bot.py ← 단일 봇 시작/기존 프로세스 종료 -│ └── setup_scheduler.ps1 ← 스케줄러 전체 재등록 -├── reports/ -│ ├── daily/ ← 매일 자동 생성 -│ └── live_ready/ ← 실전 전환 조건 충족 시 생성 -├── data/ -│ ├── stockbot.db -│ ├── daily_context.json ← 매일 /morning이 갱신, 봇이 08:30에 로드 -│ ├── midday_context.json ← 매일 /midday가 갱신, 봇이 파일 감지 즉시 로드 -│ ├── news/ -│ └── market/ -└── logs/ - ├── stockbot.log ← 봇 메인 로그 (UTF-8) - ├── bot_stderr.log ← start_bot.py가 연결한 봇 stdout/stderr - ├── bot.pid ← 현재 봇 PID - ├── stockbot.lock ← 단일 실행 lock (실행 중 생성) - ├── morning.log ← /morning 실행 로그 - ├── midday.log ← /midday 실행 로그 - ├── evening.log ← /evening 실행 로그 - └── training.log ← 학습 파이프라인 로그 -``` +## Git Rules ---- +- Branch: `master`. +- Remote: `origin` on the NAS Gitea server. +- After file edits, commit and push to `origin master` without asking again, + unless the user says not to. +- Commit message format: `[YYYY-MM-DD] concise Korean or English summary`. +- Stage only the intended files. Do not include `.env`, runtime logs, lock files, + token files, DB files, or user-in-progress data files. -## 수정 범위 +## Risk Controls -### 자유롭게 수정 가능 -- `app/config.py` — 전략 파라미터 (TP1_PCT, TP2_PCT, SL_PCT, STRATEGY_K 등) -- `app/strategy/volatility_breakout.py` — 전략 로직 -- `app/risk/manager.py` — 리스크 기준값 (L1~L5) -- `app/ai/daily_context.json` — 매일 장 전 생성 -- `reports/` — 리포트 생성/저장 +| Level | Condition | Action | +|---|---|---| +| L1 | Single trade hits stop-loss | Exit immediately | +| L2 | Daily loss reaches -3% | Stop new entries for the day | +| L3-B | Consecutive stop-losses | Reduce position size, no full stop | +| L4 | Weekly loss reaches -7% | Stop until weekend review | +| L5 | Monthly loss reaches -15% | Retire strategy and review | -주의: 장후 자동 리뷰(`/evening`)에서는 파라미터를 직접 수정하지 않고 `reports/proposals/YYYY-MM-DD_strategy_proposal.md`에 제안서로 남긴다. +L3-B sizing: -### 승인 필요 (사용자 확인 후 수정) -- `app/main.py` — 구조 변경, 스케줄 변경 -- `app/execution/` — 주문 로직 변경 -- `app/db/` — 스키마 변경 +| Consecutive stop-loss count | Position multiplier | +|---|---| +| 0 | 1.0x | +| 1 | 0.7x | +| 2 | 0.5x | +| 3+ | 0.3x | -### 절대 금지 -- `FORCE_EXIT = "14:50"` 변경 -- 손절을 익절보다 후순위로 변경 -- `.env` 파일 직접 수정 (KIS_MOCK, DRY_RUN 포함) -- `.env` Git 커밋 +## Live-Cash Readiness ---- +All conditions must pass before real-cash mode: -## Git 규칙 +- At least 30 trading days of operation. +- Recent 30-day win rate above 48%. +- Recent 30-day MDD better than -10%. +- Recent 30-day Sharpe above 1.0. +- L3-B minimum multiplier events no more than twice per month. -- branch: `master` / remote: `origin` (Gitea NAS) -- 파일 수정 후 **자동으로** 커밋 + `git push origin master` -- 단, `.env`, 실행 중 생성 파일(`logs/stockbot.lock`, `logs/bot.pid`), 사용자가 수정 중인 데이터 파일은 커밋하지 않는다. -- 커밋 메시지: `[날짜] 변경내용 요약` -- `.env`는 절대 커밋 금지 +If all pass, create `reports/live_ready/YYYY-MM-DD_READY.md` and send Discord +notification. Switching to real-cash mode requires manual `.env` changes: +`KIS_MOCK=false`, `DRY_RUN=false`. ---- +## Next Checks -## 리스크 관리 (L1~L5) - -| 레벨 | 조건 | 동작 | Discord | -|------|------|------|---------| -| L1 | 1회 -1.5% | 즉시 손절 | [손절] | -| L2 | 일일 -3% | 당일 신규 진입 중단 | [경고] | -| L3-B | 연속 손절 | 포지션 크기 단계 축소 (전면 중단 없음) | [경고] | -| L4 | 주간 -7% | 주말까지 중단 | [경고] | -| L5 | 월간 -15% | 전략 폐기 + 재검토 | [긴급] | - -**L3-B 포지션 배율** (익절 시 한 단계 회복): - -| 연속 손절 | 포지션 크기 | -|-----------|------------| -| 0회 | 1.0× (정상) | -| 1회 | 0.7× | -| 2회 | 0.5× | -| 3회+ | 0.3× (최소) | - ---- - -## 실전 전환 조건 (claude_evening 자동 체크) - -| 조건 | 기준 | -|------|------| -| 누적 운영 | 30거래일 이상 | -| 승률 | 최근 30일 > 48% | -| MDD | 최근 30일 < -10% | -| 샤프지수 | 최근 30일 > 1.0 | -| L3-B 최소배율(0.3×) 도달 | 월 2회 이하 | - -전부 충족 시 → `reports/live_ready/날짜_READY.md` 생성 + Discord 🚀 알림 -전환 방법: `.env`에서 `KIS_MOCK=false`, `DRY_RUN=false` 로 변경 - ---- - -## 운영 모드 - -| KIS_MOCK | DRY_RUN | 동작 | -|----------|---------|------| -| true | true | 신호 확인만 ← **현재** | -| true | false | 모의투자 실주문 | -| false | false | 실거래 | - ---- - -## 다음 단계 - -- [ ] WebSocket 전환 — REST 폴링 → KIS WebSocket 실시간 시세 -- [ ] `/morning` 중복 시작 수정 후 다음 장전 자동 실행에서 단일 실행 여부 확인 -- [ ] 휴장일 training pipeline이 실패 로그 대신 정상 skip으로 끝나는지 확인/수정 -- [ ] Discord webhook/remote credential 환경변수화 및 노출 이력 회수 검토 -- [ ] NAS Docker 이전 (개발 완료 후 `git push` → NAS `git pull` → `docker-compose up -d`) +- Verify the next morning run has exactly one `/morning` context generation and + one `scripts/start_bot.py` startup. +- Fix the holiday training pipeline so market holidays end as clean skips. +- Move tracked webhook/credential material into environment variables and rotate + anything exposed. +- Continue WebSocket migration planning. +- Continue NAS Docker migration planning. diff --git a/CLAUDE.md b/CLAUDE.md index 9033b69..8cf1b9e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,338 +1,302 @@ -# StockBot v3.0 - Claude Code 운영 가이드 +# StockBot v3.0 - Claude Code Operating Guide -> 최종 수정: 2026-06-04 -> 인프라: 로컬 Windows → Synology NAS Docker 이전 예정 -> 현재 모드: 모의투자 (KIS_MOCK=true, DRY_RUN=true) +> Last updated: 2026-06-04 +> Runtime: local Windows now, planned Synology NAS Docker migration later +> Current mode: paper trading / dry run (`KIS_MOCK=true`, `DRY_RUN=true`) -## Current safety policy +This file is written for Claude Code. Keep it operational, explicit, and easy +for an agent to follow. Human-facing project background belongs in `README.md`. -- AI is for market review and proposals only; code decides entries and exits. -- Evening Claude must not edit `app/config.py` or execution/strategy/risk code directly. -- Parameter changes must be written to `reports/proposals/YYYY-MM-DD_strategy_proposal.md` with evidence and manual approval required. -- `FORCE_EXIT = "14:50"` remains immutable. +## Agent Role -## Current implementation status - 2026-06-04 +- When working alone: analyze, plan, implement, verify, and self-review. +- When collaborating with Codex: implement only the approved scope and provide + Codex with the approved plan, relevant files, diff, test results, and + acceptance criteria for review. +- Do not ask Codex for the entire conversation history during collaboration. +- Do not edit files that Codex is actively editing. +- Limit review loops: one pass for small work, at most two passes for medium + work. Split large work into phase gates. -- Mode: paper trading / dry-run focused. Real-cash trading is not approved yet. -- Approved strategy change applied: `ENTRY_START = "09:20"`. -- Applied runtime parameter: `MAX_HOLD_MIN = 90`. -- `FORCE_EXIT = "14:50"` remains unchanged. -- `avoid_sectors` runtime bug fixed: `main.py` now passes sector context into `check_entry()`. -- Sector handling now keeps a `ticker_sectors` cache when available and uses name-based hints for known avoid-sector cases. +## Solo Workflow + +1. Analyze the request and classify scope: small, medium, or large. +2. Write an explicit plan before implementation. +3. Implement one file at a time and keep the scope tight. +4. Run focused verification. +5. Perform the veteran self-review below. +6. If the score is below 90, fix the highest-leverage issues and review again. + +Use this exact self-review format: + +```text +Veteran role: +Overall score: <0-100> +Decision: PASS | FAIL + +Category scores: +- Correctness and requirement fit: /30 - +- Safety, security, and failure handling: /20 - +- Maintainability and architecture fit: /20 - +- Testability and verification: /15 - +- Scope control and operational readiness: /10 - +- Clarity of handoff and reviewer confidence: /5 - + +Blocking issues preventing 90+: +- + +Highest-leverage fixes: +- +``` + +## Safety Policy + +- AI is for market review, context generation, and proposals only. +- The code decides entries, exits, risk gates, and order behavior. +- Runtime ML model scores are observation-only. They may be logged and stored, + but must not block buys, resize positions, or override exits unless explicitly + approved later. +- Evening review must not directly edit `app/config.py`, `app/execution/`, + `app/strategy/`, or `app/risk/`. Write proposal reports instead. +- Strategy parameter changes must be written to + `reports/proposals/YYYY-MM-DD_strategy_proposal.md` with evidence and manual + approval requirements. +- `FORCE_EXIT = "14:50"` is immutable. +- Stop-loss checks must remain higher priority than profit-taking checks. +- Real-cash trading is not approved yet. + +## Current Implementation Status + +- Current mode is paper trading / dry-run focused. +- Approved strategy values: + - `ENTRY_START = "09:20"` + - `MAX_HOLD_MIN = 90` + - `FORCE_EXIT = "14:50"` unchanged +- `avoid_sectors` filtering is active at runtime. `main.py` passes sector + context into `check_entry()`. +- Sector handling keeps a `ticker_sectors` cache and uses name-based hints for + known avoid-sector cases. - Re-entry controls are active: - - `TIME`/`FORCE` cooldown is based on final exit time, not original entry time. - - `TP1`/`TP2` final exits block same-day re-entry for that ticker. - - Re-entry control state is restored from today's DB rows after bot restart. -- Duplicate execution guards are active: + - `TIME` and `FORCE` cooldown is based on final exit time, not entry time. + - Final `TP1`/`TP2` exits block same-day re-entry for that ticker. + - Re-entry control state is restored from today's DB rows after restart. +- Duplicate bot execution guards are active: - `app/main.py` uses `SingleInstanceLock` on `logs/stockbot.lock`. - - `scripts/start_bot.py` stops the PID-file process and scans for existing `app/main.py` processes before starting one new bot. + - `scripts/start_bot.py` stops the PID-file process and scans for existing + `app/main.py` processes before starting one new bot. - `scripts/run_morning.ps1` is the only owner of post-morning bot startup. - - `.claude/commands/morning.md` must not call `/start-bot` or `scripts/start_bot.py`; it only creates and sends morning context. + - `.claude/commands/morning.md` must not call `/start-bot` or + `scripts/start_bot.py`. - KIS stability hardening is active: - - Mode-specific request spacing in `KISClient` (`mock` more conservative than `real`). + - Mode-specific request spacing in `KISClient`. - Price lookups retry transient KIS timeout/rate-limit errors. - - DRY_RUN buy/sell paths can reuse the already-read quote as the simulated fill price to reduce extra API calls. -- Daily summary duplicate guard is active; summary Discord failures are logged without crashing settlement. -- Data layer: `entry_snapshots` and `post_entry_snapshots` are active for training data. -- Post-entry sampling: 60s, 180s, 300s, and 600s after successful entry. -- Training data export: `scripts/export_training_dataset.py`. -- External data collection: - - Daily market features: `scripts/collect_daily_features.py` with KIS fallback when pykrx fails. - - KIS minute bars: `scripts/collect_minute_data.py`, default ETF/ETN exclusion, multi-window collection from 09:30 to 14:00. - - External dataset builder: `scripts/build_external_training_dataset.py`, using prior daily OHLCV for breakout targets. -- ML engine: + - DRY_RUN buy/sell paths can reuse the already-read quote as the simulated + fill price to reduce extra API calls. +- Daily summary has a duplicate guard; Discord settlement-send failures are + logged without crashing settlement. +- Data layer: + - `entry_snapshots` are active. + - `post_entry_snapshots` sample 60s, 180s, 300s, and 600s after entry. + - Bot data export: `scripts/export_training_dataset.py`. +- External data and ML: + - Daily features: `scripts/collect_daily_features.py`, with KIS fallback when + pykrx fails. + - KIS minute bars: `scripts/collect_minute_data.py`, ETF/ETN excluded by + default, multi-window collection from 09:30 to 14:00. + - External dataset builder: `scripts/build_external_training_dataset.py`. - Training: `scripts/train_ai_model.py`. - - Model output: `models/scalping_model.joblib`. - - Metrics output: `models/scalping_model.metrics.json`. - Runtime loader: `app/ml/predictor.py`. -- Latest successful training run: 2026-06-02 18:36, 5,773 rows total (`external_training_dataset.csv` 5,720 + bot dataset 53). -- Latest metrics: `label_stop_loss` ROC-AUC 0.896, `label_win` ROC-AUC 0.715. -- Training features exclude future/outcome leakage columns such as `ret_*`, `mfe_*`, `mae_*`, `price_*`, `pnl`, and `exit_price`. -- AI runtime mode: observation only. If a model exists, entry-time scores are logged and saved to `entry_snapshots`; they do not block or resize trades. -- Training schedule: `StockBot_Training` runs at 16:00 on trading days via `scripts/run_training_pipeline.ps1`; latest successful full run was 2026-06-02 18:36. -- Latest daily review/proposal files exist through 2026-06-02. 2026-06-03 was skipped as a market holiday. -- Dependency install: - - `requirements.txt` includes `app/requirements.txt`. - - `scripts/install_dependencies.ps1` installs from `vendor/wheels` when available. - - `scripts/download_dependencies.ps1` builds the local wheelhouse. + - Latest successful training run: 2026-06-02 18:36. + - Latest rows: 5,773 total (`external_training_dataset.csv` 5,720 + bot + dataset 53). + - Latest metrics: `label_stop_loss` ROC-AUC 0.896, `label_win` ROC-AUC 0.715. +- Latest daily review/proposal files exist through 2026-06-02. +- 2026-06-03 was skipped as a market holiday. -## Current operational risks - 2026-06-04 +## Current Risks -- Model is still observation-only and is dominated by external pretraining rows; bot-trade labels are 53 rows. -- KIS minute-bar collection is verified for same-day windows, but historical depth and ticker coverage remain limited. +- The ML model is observation-only and still dominated by external pretraining + rows; bot-trade labels are only 53 rows. +- KIS minute data is verified for same-day windows, but historical depth and + ticker coverage are limited. - External minute data is pretraining data, not actual bot-trade data. -- pykrx daily feature collection can fail for same-day data; KIS fallback is active. -- KIS rate limits can still happen if multiple scripts/processes call KIS concurrently; runtime retries reduce but do not eliminate this. -- 2026-06-03 holiday training run logged a failure at the holiday-check step instead of a clean skip; inspect before relying on holiday automation noise level. -- 2026-06-04 morning duplicate execution happened before the `/morning` instruction fix; next scheduled morning run should be checked for exactly one context run and one `start_bot.py` startup. -- Real-cash mode still needs stronger fill, partial-fill, unfilled-order, cancel/replace, and recovery logic. -- Security cleanup is still needed: keep secrets out of tracked files and remote URLs; prefer environment variables for webhooks and credentials. -- Existing logs and older docs contain encoding damage; new operational notes should stay ASCII unless the file encoding is intentionally cleaned. +- pykrx daily feature collection can fail for same-day data; KIS fallback is + active. +- KIS rate limits can still happen if multiple scripts or processes call KIS at + the same time. +- The 2026-06-03 holiday training run logged a failure at the holiday-check + step instead of a clean skip. Inspect this before relying on holiday + automation noise level. +- The 2026-06-04 morning duplicate execution happened before the `/morning` + instruction fix. The next scheduled morning run should be checked for exactly + one context generation and one `start_bot.py` startup. +- Real-cash mode still needs stronger fill, partial-fill, unfilled-order, + cancel/replace, and recovery logic. +- Security cleanup is needed: keep webhooks, credentials, tokens, and remote + credentials out of tracked files and remote URLs. +- Older logs contain encoding damage. New operational notes should stay ASCII + unless the target file intentionally uses another encoding. ---- +## Automation Flow -## 프로젝트 개요 +```text +08:15 StockBot_Morning -> scripts/run_morning.ps1 -> /morning + Build data/daily_context.json. + After /morning exits, run_morning.ps1 calls python scripts/start_bot.py. -| 항목 | 내용 | -|------|------| -| 목표 | KIS API 기반 한국 주식 단타 자동매매 | -| 전략 | 변동성 돌파 (K=0.5) | -| 언어 | Python 3.11 | -| DB | SQLite (data/stockbot.db) | -| 알림 | Discord Webhook (거래 알림 + 코드 변경 알림 채널 분리) | -| AI | Claude Code headless (`claude -p "/커맨드" --dangerously-skip-permissions`) | -| 코드 관리 | Gitea (NAS) — 파일 수정 후 확인 없이 자동 commit + push | - ---- - -## Claude Code 권한 및 자동화 설정 - -- Claude 권한은 `.claude/settings.json`에서 관리한다. -- Codex 연동 환경변수/훅은 `.codex/config.toml`, `.codex/hooks.json`에서 관리한다. -- 파일 수정 완료 후 확인 없이 커밋 + `git push origin master`까지 수행한다. -- 단, `.env`, 실행 중 생성 파일, 사용자 작업 중 파일은 커밋하지 않는다. -- 인코딩: `PYTHONUTF8=1`, `PYTHONIOENCODING=utf-8` 환경변수 설정 - ---- - -## 핵심 설계 원칙 (절대 불변) - -1. **14:50 강제 청산** — 하드코딩, 예외 없음 -2. **손절 우선** — AI 판단과 무관하게 손절 룰 항상 우선순위 1위 -3. **AI 역할 분리** — Claude Code는 장 전 분석 + 장 후 피드백만, 실시간 매매 개입 불가 -4. **검증 순서** — 모의투자 3개월 → 조건 충족 → 실거래 - ---- - -## 하루 자동화 흐름 - -``` -08:15 StockBot_Morning → run_morning.ps1 → claude /morning - RSS+네이버 뉴스+KIS 수급 분석 → daily_context.json - /morning 종료 후 run_morning.ps1이 python scripts/start_bot.py 호출 -08:30 봇이 daily_context.json 로드 → Discord 전송 → 유니버스 30종목 확정 -08:50 목표가 계산 -09:00 아침 세션 시작 (변동성 돌파 신호 + AI 필터) - B안: 연속 손절 시 포지션 크기 자동 축소 (0회→1.0× / 1회→0.7× / 2회→0.5× / 3+→0.3×) -11:00 midday_context.json 미로드 시 신규 진입 일시 중단 -11:20 StockBot_Midday → run_midday.ps1 → claude /midday - 오전 결과+시장 스냅샷 수집 → midday_context.json 저장 - 파일 생성 즉시 봇이 감지 → 점심 세션 자동 시작 -14:00 신규 진입 마감 -14:50 강제 전량 청산 (절대 불변) -15:10 일일 결산 → Discord 전송 -15:30 StockBot_Evening → run_evening.ps1 → claude /evening - 결과 분석 + 리포트/제안서 저장 +08:30 Bot loads daily_context.json and builds the watch universe. +08:50 Bot calculates volatility breakout targets. +09:00 Morning trading session starts. +11:00 New entries pause if midday_context.json has not loaded. +11:20 StockBot_Midday -> scripts/run_midday.ps1 -> /midday + Build data/midday_context.json; bot detects it and starts lunch controls. +14:00 New entries stop; exits continue. +14:50 Force exit all positions. This time is immutable. +15:10 Daily settlement and Discord summary. +15:30 StockBot_Evening -> scripts/run_evening.ps1 -> /evening + Write daily report and proposal report when needed. +16:00 StockBot_Training -> scripts/run_training_pipeline.ps1 ``` -### 스케줄러 스크립트 주의사항 (scripts/run_*.ps1) -- 경로: `$PROJECT = Split-Path -Parent $PSScriptRoot` (한글 경로 인코딩 문제 방지) -- CLI 실행: `scripts/stockbot_env.ps1`의 `Resolve-StockBotClaude`가 `claude.cmd`를 우선 찾고 없으면 `codex.cmd`를 사용 -- 인코딩: `New-Object System.Text.UTF8Encoding $false` + UTF-8 BOM으로 저장 -- 봇 시작: `scripts/run_morning.ps1`이 `/morning` 완료 후 `python scripts/start_bot.py`를 직접 실행 -- 로그: `logs/morning.log`, `logs/midday.log`, `logs/evening.log`, `logs/training.log`, `logs/bot_stderr.log`, `logs/stockbot.log` +## Slash Command Responsibilities ---- +### `/morning` -## Claude Code 역할 상세 +1. Run `python app/ai/morning.py --print`. +2. Analyze collected news, KIS flow, sectors, and ticker-specific news. +3. Write `data/daily_context.json`. +4. Send the morning Discord summary. +5. Do not start the bot. Startup belongs only to `scripts/run_morning.ps1`. -### 장 전 분석 — `/morning` 슬래시 커맨드 -``` -1. python app/ai/morning.py --print (뉴스 크롤링 + KIS 수급 수집) -2. Claude가 데이터 분석 → 시장 분위기/섹터/boosted_tickers 판단 -3. data/daily_context.json 저장 -4. Discord로 분석 요약 전송 -5. 여기서는 봇을 시작하지 않음. 봇 시작은 run_morning.ps1만 담당. +### `/midday` + +1. Run `python app/ai/midday.py --print`. +2. Compare morning context with actual morning trades and market snapshot. +3. Write `data/midday_context.json`. +4. Send the midday Discord summary. + +### `/evening` + +1. Run `python app/ai/evening.py --print`. +2. Review trades, win rate, PnL, fees, exit distribution, overtrading, AI + filter quality, and execution quality. +3. Write `reports/daily/YYYY-MM-DD.md`. +4. If a strategy change is justified, write + `reports/proposals/YYYY-MM-DD_strategy_proposal.md`. +5. Do not directly edit runtime strategy/config/risk/execution code during + evening review. +6. Check live-readiness criteria. +7. Send a concise Discord summary. + +### `/start-bot` + +1. Run `python scripts/start_bot.py`. +2. The script stops existing PID-file and scanned `app/main.py` processes. +3. It starts exactly one detached `app/main.py` process. +4. It writes `logs/bot.pid` and sends the Discord start notification. + +## Important Files + +```text +app/main.py Main trading loop and runtime orchestration +app/config.py Strategy parameters +app/strategy/volatility_breakout.py Entry/exit signal logic +app/risk/manager.py L1-L5 risk controls and L3-B sizing +app/execution/kis_client.py KIS REST/WebSocket wrapper +app/execution/order_executor.py Order execution and trade persistence +app/db/models.py SQLite schema +app/db/repository.py DB access helpers +app/ai/morning.py Morning data collection +app/ai/midday.py Midday data collection +app/ai/evening.py Evening data collection +scripts/start_bot.py Deterministic single-bot startup +scripts/run_morning.ps1 Scheduler morning job +scripts/run_midday.ps1 Scheduler midday job +scripts/run_evening.ps1 Scheduler evening job +scripts/run_training_pipeline.ps1 Training pipeline ``` -### 장중 분석 — `/midday` 슬래시 커맨드 -``` -1. python app/ai/midday.py --print (오전 거래 결과 + 현재 시장 스냅샷 수집) -2. 오전 daily_context 예측 vs 실제 결과 비교 분석 -3. 점심 세션 파라미터 결정 (진입 허용 여부, 포지션 배율, 섹터 업데이트) -4. data/midday_context.json 저장 → 봇이 즉시 감지해 점심 세션 시작 -5. Discord로 장중 분석 전송 -``` +## Edit Boundaries -### 장 후 피드백 — `/evening` 슬래시 커맨드 -``` -1. python app/ai/evening.py --print (오늘 매매 내역 조회) -2. 승률/손익/이상패턴 분석 -3. app/config.py 파라미터 조정 (문제 명확할 때만) -4. reports/daily/날짜.md 저장 -5. 실전 전환 조건 5가지 체크 -6. Discord로 요약 전송 -``` +Freely editable when the task calls for it: -### 봇 시작 — `/start-bot` 슬래시 커맨드 -``` -1. python scripts/start_bot.py 실행 -2. PID 파일 + 프로세스 스캔으로 기존 app/main.py 종료 -3. app/main.py를 DETACHED_PROCESS로 백그라운드 시작 -4. logs/bot.pid 저장 + Discord "[모의투자] 자동매매 봇 시작" 알림 -``` +- `app/config.py` +- `app/strategy/volatility_breakout.py` +- `app/risk/manager.py` +- `reports/` +- Documentation files ---- +Requires explicit user approval: -## Discord 알림 구조 +- Structural changes to `app/main.py` +- `app/execution/` +- `app/db/` +- Database schema changes +- Real-cash trading behavior -| 채널 | 내용 | 발신 | -|------|------|------| -| 거래 알림 | 매수/매도/손절/결산 | `app/monitor/notifier.py` | -| 코드 변경 | 커밋 내용 + Push 완료 여부 | `.claude/discord_notify.py` (Stop 훅, `.codex/hooks.json`에서도 호출) | +Never edit or commit: -- 코드 변경 알림: **커밋이 있을 때만** 발송 (스케줄러 태스크 등 노이즈 없음) -- Discord 요청 시 반드시 `User-Agent: DiscordBot (stockbot, 1.0)` 헤더 포함 (Cloudflare 차단 방지) +- `.env` +- token files +- runtime DB files +- runtime logs +- `logs/stockbot.lock` +- files the user says they are currently editing ---- +Never change: -## 파일 구조 +- `FORCE_EXIT = "14:50"` +- stop-loss priority over profit-taking -``` -stockbot_v3/ -├── CLAUDE.md -├── AGENTS.md -├── .env ← API 키 (Git 절대 제외) -├── .codex/ -│ ├── config.toml ← Codex 환경변수 설정 -│ └── hooks.json ← Stop 훅에서 .claude/discord_notify.py 호출 -├── .claude/ -│ ├── commands/ ← /morning, /midday, /evening, /start-bot 명령 -│ ├── settings.json ← Claude 권한 설정 -│ └── discord_notify.py ← 코드 변경 Discord 전송 -├── app/ -│ ├── main.py ← 메인 매매 루프 (승인 필요) -│ ├── config.py ← 전략 파라미터 (수정 가능) -│ ├── ai/ -│ │ ├── morning.py ← 장 전 데이터 수집 -│ │ ├── midday.py ← 장중 데이터 수집 -│ │ └── evening.py ← 장 후 데이터 수집 -│ ├── strategy/ -│ │ └── volatility_breakout.py ← 전략 로직 (수정 가능) -│ ├── execution/ -│ │ ├── kis_client.py ← KIS API 래퍼 (승인 필요) -│ │ └── order_executor.py ← 주문 실행 (승인 필요) -│ ├── risk/ -│ │ └── manager.py ← 리스크 관리 (수정 가능) -│ ├── monitor/ -│ │ └── notifier.py ← Discord Webhook -│ └── db/ -│ ├── models.py ← SQLite 스키마 (승인 필요) -│ └── repository.py ← DB 접근 (승인 필요) -├── scripts/ -│ ├── run_bot.ps1 ← 스케줄러용 봇 시작 -│ ├── run_morning.ps1 ← 스케줄러용 morning -│ ├── run_midday.ps1 ← 스케줄러용 midday (11:20) -│ ├── run_evening.ps1 ← 스케줄러용 evening -│ ├── run_training_pipeline.ps1 -│ ├── start_bot.py ← 단일 봇 시작/기존 프로세스 종료 -│ └── setup_scheduler.ps1 ← 스케줄러 전체 재등록 -├── reports/ -│ ├── daily/ ← 매일 자동 생성 -│ └── live_ready/ ← 실전 전환 조건 충족 시 생성 -├── data/ -│ ├── stockbot.db -│ ├── daily_context.json ← 매일 /morning이 갱신, 봇이 08:30에 로드 -│ ├── midday_context.json ← 매일 /midday가 갱신, 봇이 파일 감지 즉시 로드 -│ ├── news/ -│ └── market/ -└── logs/ - ├── stockbot.log ← 봇 메인 로그 (UTF-8) - ├── bot_stderr.log ← start_bot.py가 연결한 봇 stdout/stderr - ├── bot.pid ← 현재 봇 PID - ├── stockbot.lock ← 단일 실행 lock (실행 중 생성) - ├── morning.log ← /morning 실행 로그 - ├── midday.log ← /midday 실행 로그 - ├── evening.log ← /evening 실행 로그 - └── training.log ← 학습 파이프라인 로그 -``` +## Git Rules ---- +- Branch: `master`. +- Remote: `origin` on the NAS Gitea server. +- After file edits, commit and push to `origin master` without asking again, + unless the user says not to. +- Commit message format: `[YYYY-MM-DD] concise Korean or English summary`. +- Stage only the intended files. Do not include `.env`, runtime logs, lock files, + token files, DB files, or user-in-progress data files. -## 수정 범위 +## Risk Controls -### 자유롭게 수정 가능 -- `app/config.py` — 전략 파라미터 (TP1_PCT, TP2_PCT, SL_PCT, STRATEGY_K 등) -- `app/strategy/volatility_breakout.py` — 전략 로직 -- `app/risk/manager.py` — 리스크 기준값 (L1~L5) -- `app/ai/daily_context.json` — 매일 장 전 생성 -- `reports/` — 리포트 생성/저장 +| Level | Condition | Action | +|---|---|---| +| L1 | Single trade hits stop-loss | Exit immediately | +| L2 | Daily loss reaches -3% | Stop new entries for the day | +| L3-B | Consecutive stop-losses | Reduce position size, no full stop | +| L4 | Weekly loss reaches -7% | Stop until weekend review | +| L5 | Monthly loss reaches -15% | Retire strategy and review | -주의: 장후 자동 리뷰(`/evening`)에서는 파라미터를 직접 수정하지 않고 `reports/proposals/YYYY-MM-DD_strategy_proposal.md`에 제안서로 남긴다. +L3-B sizing: -### 승인 필요 (사용자 확인 후 수정) -- `app/main.py` — 구조 변경, 스케줄 변경 -- `app/execution/` — 주문 로직 변경 -- `app/db/` — 스키마 변경 +| Consecutive stop-loss count | Position multiplier | +|---|---| +| 0 | 1.0x | +| 1 | 0.7x | +| 2 | 0.5x | +| 3+ | 0.3x | -### 절대 금지 -- `FORCE_EXIT = "14:50"` 변경 -- 손절을 익절보다 후순위로 변경 -- `.env` 파일 직접 수정 (KIS_MOCK, DRY_RUN 포함) -- `.env` Git 커밋 +## Live-Cash Readiness ---- +All conditions must pass before real-cash mode: -## Git 규칙 +- At least 30 trading days of operation. +- Recent 30-day win rate above 48%. +- Recent 30-day MDD better than -10%. +- Recent 30-day Sharpe above 1.0. +- L3-B minimum multiplier events no more than twice per month. -- branch: `master` / remote: `origin` (Gitea NAS) -- 파일 수정 후 **자동으로** 커밋 + `git push origin master` -- 단, `.env`, 실행 중 생성 파일(`logs/stockbot.lock`, `logs/bot.pid`), 사용자가 수정 중인 데이터 파일은 커밋하지 않는다. -- 커밋 메시지: `[날짜] 변경내용 요약` -- `.env`는 절대 커밋 금지 +If all pass, create `reports/live_ready/YYYY-MM-DD_READY.md` and send Discord +notification. Switching to real-cash mode requires manual `.env` changes: +`KIS_MOCK=false`, `DRY_RUN=false`. ---- +## Next Checks -## 리스크 관리 (L1~L5) - -| 레벨 | 조건 | 동작 | Discord | -|------|------|------|---------| -| L1 | 1회 -1.5% | 즉시 손절 | [손절] | -| L2 | 일일 -3% | 당일 신규 진입 중단 | [경고] | -| L3-B | 연속 손절 | 포지션 크기 단계 축소 (전면 중단 없음) | [경고] | -| L4 | 주간 -7% | 주말까지 중단 | [경고] | -| L5 | 월간 -15% | 전략 폐기 + 재검토 | [긴급] | - -**L3-B 포지션 배율** (익절 시 한 단계 회복): - -| 연속 손절 | 포지션 크기 | -|-----------|------------| -| 0회 | 1.0× (정상) | -| 1회 | 0.7× | -| 2회 | 0.5× | -| 3회+ | 0.3× (최소) | - ---- - -## 실전 전환 조건 (claude_evening 자동 체크) - -| 조건 | 기준 | -|------|------| -| 누적 운영 | 30거래일 이상 | -| 승률 | 최근 30일 > 48% | -| MDD | 최근 30일 < -10% | -| 샤프지수 | 최근 30일 > 1.0 | -| L3-B 최소배율(0.3×) 도달 | 월 2회 이하 | - -전부 충족 시 → `reports/live_ready/날짜_READY.md` 생성 + Discord 🚀 알림 -전환 방법: `.env`에서 `KIS_MOCK=false`, `DRY_RUN=false` 로 변경 - ---- - -## 운영 모드 - -| KIS_MOCK | DRY_RUN | 동작 | -|----------|---------|------| -| true | true | 신호 확인만 ← **현재** | -| true | false | 모의투자 실주문 | -| false | false | 실거래 | - ---- - -## 다음 단계 - -- [ ] WebSocket 전환 — REST 폴링 → KIS WebSocket 실시간 시세 -- [ ] `/morning` 중복 시작 수정 후 다음 장전 자동 실행에서 단일 실행 여부 확인 -- [ ] 휴장일 training pipeline이 실패 로그 대신 정상 skip으로 끝나는지 확인/수정 -- [ ] Discord webhook/remote credential 환경변수화 및 노출 이력 회수 검토 -- [ ] NAS Docker 이전 (개발 완료 후 `git push` → NAS `git pull` → `docker-compose up -d`) +- Verify the next morning run has exactly one `/morning` context generation and + one `scripts/start_bot.py` startup. +- Fix the holiday training pipeline so market holidays end as clean skips. +- Move tracked webhook/credential material into environment variables and rotate + anything exposed. +- Continue WebSocket migration planning. +- Continue NAS Docker migration planning. diff --git a/README.md b/README.md index b94a07d..3182c77 100644 --- a/README.md +++ b/README.md @@ -1,131 +1,91 @@ -# 단타 자동매매 시스템 v3.0 +# StockBot v3.0 -기획서 v3.0 기준 / KIS Open API / Synology NAS Docker -AI: Claude Code/Codex headless (장 전 분석 + 장중 점검 + 장 후 피드백) +KIS Open API를 이용한 한국 주식 단타 자동매매 프로젝트입니다. +현재는 실거래 전 검증 단계로, 모의투자와 DRY_RUN 중심으로 신호 품질과 +운영 안정성을 확인하고 있습니다. -## 운영 모드 +## 기획 의도 -| KIS_MOCK | DRY_RUN | 동작 | -|----------|---------|------| -| true | true | 신호 확인만 (주문 없음) ← 현재 | -| true | false | 모의투자 실제 주문 ← 3개월 검증 | -| false | false | 실거래 ← 조건 충족 후 | +이 프로젝트의 목표는 사람이 매일 반복해서 하던 단타 후보 탐색, 시장 분위기 +판단, 진입/청산 기록, 장후 복기를 자동화하는 것입니다. 다만 실시간 매매 판단을 +AI에게 맡기지는 않습니다. AI는 장 전/장중/장후 시장을 분석하고 제안서를 만드는 +역할만 하고, 실제 진입과 청산은 코드에 고정된 규칙이 결정합니다. -## 빠른 시작 +핵심 원칙은 세 가지입니다. -```bash -# 1. .env 설정 -cp .env.example .env -# .env 열어서 KIS 키, Discord Webhook URL 입력 +- 손절은 항상 최우선입니다. +- `14:50` 강제 청산은 변경하지 않습니다. +- 실거래 전에는 충분한 모의투자 기간과 성과 조건을 통과해야 합니다. -# 2. KIS 연결 테스트 -pip install aiohttp python-dotenv -python test_connection.py +## 전체 흐름 -# 3. 신호 확인 (DRY_RUN=true) -python app/main.py +하루 운영은 다음 흐름으로 설계되어 있습니다. -# 4. Docker 실행 (NAS) -docker-compose up -d -``` - -## 컨테이너 구성 - -| 컨테이너 | 역할 | 실행 시간 | -|---------|------|---------| -| stockbot-main | 매매 프로그램 | 상시 (09:00~15:00 활성) | -| stockbot-redis | 시세 캐시 | 상시 | -| stockbot-dashboard | Streamlit 모니터링 | 상시 (포트 8501) | -| claude-morning | 장 전 AI 분석 | 08:30 (실행 후 종료) | -| claude-evening | 장 후 AI 피드백 | 15:30 (실행 후 종료) | -| stockbot-killswitch | 긴급 청산 | 수동 트리거 | - -## 긴급 청산 - -```bash -docker-compose --profile emergency up kill-switch -# 또는 -python kill_switch/kill.py -``` - -# StockBot Current Status - 2026-06-04 - -This project is currently a paper-trading scalping bot with an AI training -pipeline in observation mode. - -Active: -- Windows Task Scheduler operation for morning, midday, evening, watchdog, and training jobs. -- Approved `ENTRY_START = "09:20"` after the 2026-05-28 evening review. -- Applied `MAX_HOLD_MIN = 90`. -- `FORCE_EXIT = "14:50"` remains unchanged. -- `avoid_sectors` filtering is active in runtime entry checks. -- Re-entry controls are active: - - TIME/FORCE cooldown is measured from final exit time. - - TP final exits block same-day ticker re-entry. - - Re-entry control state is restored from today's DB rows after restart. -- Duplicate bot startup guards are active: - - `app/main.py` uses `logs/stockbot.lock`. - - `scripts/start_bot.py` kills existing `app/main.py` processes before starting one new bot. - - `scripts/run_morning.ps1` is the only post-morning bot startup owner. - - `/morning` must not call `/start-bot` or `scripts/start_bot.py`. -- KIS stability hardening is active: - - Mode-specific request spacing. - - Retry for transient KIS timeout/rate-limit price errors. - - DRY_RUN simulated fills reuse the current quote to reduce extra KIS calls. -- Daily settlement has a duplicate-summary guard. -- Entry snapshots for model training. -- Post-entry snapshots at 1m, 3m, 5m, and 10m. -- Bot-data export to `data/training_dataset.csv`. -- External daily/minute data collection for pretraining. -- External daily collection falls back to KIS when pykrx same-day data fails. -- KIS minute collection excludes ETF/ETN by default and collects multiple windows from 09:30 to 14:00. -- RandomForest-based training engine. -- Optional AI entry scoring when `models/scalping_model.joblib` exists. -- Latest successful training run: 2026-06-02 18:36. -- Latest training rows: 5,773 total, including 5,720 external pretraining rows and 53 bot-trade rows. -- Latest metrics: `label_stop_loss` ROC-AUC 0.896, `label_win` ROC-AUC 0.715. -- Latest daily review/proposal files exist through 2026-06-02; 2026-06-03 was a market holiday. - -Not active yet: -- ML model scores do not block buys. -- ML model scores do not change position size. -- ML model scores do not override exits. -- Real-cash trading is not ready until fill, unfilled-order, and partial-fill handling is hardened. - -Current operational notes: -- On 2026-06-04, duplicate morning execution happened before the `/morning` instruction fix. The next scheduled morning run should show one context run and one `scripts/start_bot.py` startup. -- KIS rate limits can still happen when multiple scripts/processes call KIS concurrently. -- The 2026-06-03 holiday training run logged a failure at the holiday-check step instead of a clean skip; inspect before relying on holiday automation noise level. -- Keep secrets out of tracked files and remote URLs. Prefer environment variables for Discord webhooks and credentials. - -Daily schedule: - -| Time | Task | Purpose | +| 시간 | 흐름 | 내용 | |---|---|---| -| 08:15 | `StockBot_Morning` | Run `/morning`, build context, then `scripts/start_bot.py` starts exactly one bot | -| 09:00-15:10 | `StockBot_Watchdog` | Check/restart bot every 5 minutes | -| 11:20 | `StockBot_Midday` | Midday review and context update | -| 15:30 | `StockBot_Evening` | Daily review and proposal report | -| 16:00 | `StockBot_Training` | Collect data, export datasets, train model | +| 08:15 | 장 전 분석 | 뉴스, 수급, 업종 분위기를 분석해 `daily_context.json` 생성 | +| 08:30 | 봇 시작/준비 | 유니버스 선정, 목표가 계산, Discord 알림 | +| 09:00 | 오전 매매 | 변동성 돌파 조건과 AI 컨텍스트 필터를 함께 확인 | +| 11:20 | 장중 분석 | 오전 결과와 현재 시장을 비교해 `midday_context.json` 생성 | +| 14:00 | 신규 진입 종료 | 새 진입은 막고 보유 포지션 청산 감시만 계속 | +| 14:50 | 강제 청산 | 모든 포지션 정리 | +| 15:30 | 장후 복기 | 일일 리포트와 전략 제안서 작성 | +| 16:00 | 학습 파이프라인 | 거래 데이터와 외부 데이터를 모아 관찰용 모델 갱신 | -Useful commands: +## 현재 운영 상태 + +- 현재 모드: `KIS_MOCK=true`, `DRY_RUN=true` +- 전략: 변동성 돌파(`K=0.5`) +- 진입 시작: `09:20` +- 강제 청산: `14:50` +- DB: SQLite (`data/stockbot.db`) +- 알림: Discord Webhook +- AI/ML: 시장 분석과 관찰용 점수 기록까지만 사용 + +운영 모드는 아래처럼 나뉩니다. + +| KIS_MOCK | DRY_RUN | 의미 | +|---|---|---| +| true | true | 신호 확인만 수행, 주문 없음 | +| true | false | 모의투자 주문 수행 | +| false | false | 실거래 주문 수행 | + +현재 실거래는 승인되지 않았습니다. + +## 주요 구성 + +```text +app/ 매매 봇, 전략, 리스크, KIS API, DB, 알림 코드 +scripts/ 스케줄러, 봇 시작, 데이터 수집, 학습 스크립트 +data/ 로컬 실행 데이터와 SQLite DB +logs/ 실행 로그 +models/ 관찰용 ML 모델 산출물 +reports/daily/ 장후 일일 리포트 +reports/proposals/ 수동 승인이 필요한 전략 제안서 +``` + +## 자주 쓰는 명령 ```powershell python -m pip install -r requirements.txt -powershell -ExecutionPolicy Bypass -File scripts\install_dependencies.ps1 -powershell -ExecutionPolicy Bypass -File scripts\setup_scheduler.ps1 +python test_connection.py +python app/main.py python scripts\start_bot.py +powershell -ExecutionPolicy Bypass -File scripts\setup_scheduler.ps1 powershell -ExecutionPolicy Bypass -File scripts\run_training_pipeline.ps1 -python scripts\export_training_dataset.py -python scripts\train_ai_model.py -Get-Content logs\morning.log -Tail 80 -Get-Content logs\stockbot.log -Tail 80 ``` -Dependency portability: -- Root `requirements.txt` includes `app/requirements.txt`. -- `scripts/download_dependencies.ps1` downloads Windows/Python 3.11 wheels to `vendor/wheels`. -- `scripts/install_dependencies.ps1` installs from `vendor/wheels` first, then falls back to online pip. -- Raspberry Pi needs its own wheelhouse or online install because Windows wheels are not ARM/Linux compatible. +## 에이전트 운영 문서 ---- +- `AGENTS.md`: Codex가 읽는 운영 지침 +- `CLAUDE.md`: Claude Code가 읽는 운영 지침 + +두 파일은 에이전트가 정확하게 행동하기 위한 상세 규칙입니다. 일반적인 프로젝트 +개요는 이 README만 보면 됩니다. + +## 주의사항 + +- `.env`, 토큰, DB, 로그 파일은 Git에 올리지 않습니다. +- 전략 파라미터 변경은 원칙적으로 장후 제안서에 기록하고 사람이 승인합니다. +- `FORCE_EXIT = "14:50"`은 절대 변경하지 않습니다. +- 실거래 전에는 모의투자 결과, 손실 제한, 주문 안정성 검증이 필요합니다.