diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index d7f9513..6c244c2 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -35,11 +35,11 @@ CoinTrader는 **Binance Futures 자동매매 봇**입니다. ``` main.py - └─ Config (SYMBOLS=XRPUSDT,TRXUSDT,DOGEUSDT) + └─ Config (SYMBOLS=XRPUSDT,SOLUSDT,DOGEUSDT) └─ RiskManager (공유 싱글턴, asyncio.Lock) └─ asyncio.gather( TradingBot(symbol="XRPUSDT", risk=shared_risk), - TradingBot(symbol="TRXUSDT", risk=shared_risk), + TradingBot(symbol="SOLUSDT", risk=shared_risk), TradingBot(symbol="DOGEUSDT", risk=shared_risk), ) ``` @@ -124,6 +124,10 @@ flowchart TD ### 2.1 진입 판단 (5단계 게이트) ``` +Gate 0: 킬스위치 확인 + └─ 해당 심볼이 킬 상태인가? → 킬이면 즉시 return (신규 진입 차단) + └─ Fast Kill: 8연속 순손실 / Slow Kill: 최근 15거래 PF < 0.75 + Gate 1: 추세 존재 확인 └─ ADX ≥ 25 인가? → 미만이면 HOLD (횡보장 진입 차단) @@ -144,7 +148,7 @@ Gate 5: 리스크 관리 └─ 동일 방향 포지션 2개 미만? └─ 같은 심볼 기존 포지션 없음? -→ 5개 게이트 모두 통과 → 주문 실행 +→ 6개 게이트 모두 통과 → 주문 실행 ``` ### 2.2 청산 메커니즘 @@ -333,13 +337,15 @@ ML 필터를 통과한 신호를 실제 주문으로 변환하고, 리스크 한 **리스크 제어:** -| 제어 항목 | 기준 | -|----------|------| -| 일일 최대 손실 | 기준 잔고의 5% | -| 최대 동시 포지션 | 3개 (전체 심볼 합산) | -| 동일 방향 제한 | 2개 (LONG 2개면 3번째 LONG 차단) | -| 같은 심볼 중복 | 차단 (1심볼 1포지션) | -| 최소 명목금액 | $5 USDT | +| 제어 항목 | 기준 | 방어 대상 | +|----------|------|-----------| +| 일일 최대 손실 | 기준 잔고의 5% | 단일 충격 (하루 급락) | +| 킬스위치 Fast Kill | 8연속 순손실 | 전략 급격 붕괴 | +| 킬스위치 Slow Kill | 최근 15거래 PF < 0.75 | 점진적 엣지 소실 (Slow Bleed) | +| 최대 동시 포지션 | 3개 (전체 심볼 합산) | 과노출 | +| 동일 방향 제한 | 2개 (LONG 2개면 3번째 LONG 차단) | 방향 편중 | +| 같은 심볼 중복 | 차단 (1심볼 1포지션) | 중복 진입 | +| 최소 명목금액 | $5 USDT | 거래소 제약 | **반대 시그널 재진입:** 보유 포지션과 반대 방향 신호 발생 시 기존 포지션을 즉시 청산하고, ML 필터 통과 시 반대 방향으로 재진입합니다. 재진입 중 User Data Stream 콜백이 신규 포지션 상태를 덮어쓰지 않도록 `_is_reentering` 플래그로 보호합니다. @@ -520,12 +526,13 @@ if onnx_changed or lgbm_changed: ``` [매주 일요일 크론탭] -[1/6] 데이터 수집 (fetch_history.py × 심볼 수, 최근 35일 Upsert) -[2/6] Walk-Forward 백테스트 (심볼별 → 합산 PF/승률/MDD) -[3/6] 운영 대시보드 API 조회 (GET /api/trades + GET /api/stats → 실전 거래 통계) -[4/6] 추이 분석 (이전 리포트에서 PF/승률/MDD 추이 로드) -[5/6] ML 재학습 체크 (누적 트레이드 ≥ 150, PF < 1.0, PF 3주 하락 → 2/3 충족 시 권장) -[6/6] PF < 1.0이면 파라미터 스윕 실행 → 상위 3개 대안 제시 +[1/7] 데이터 수집 (fetch_history.py × 심볼 수, 최근 35일 Upsert) +[2/7] Walk-Forward 백테스트 (심볼별 → 합산 PF/승률/MDD) +[3/7] 운영 대시보드 API 조회 (GET /api/trades + GET /api/stats → 실전 거래 통계) +[4/7] 추이 분석 (이전 리포트에서 PF/승률/MDD 추이 로드) +[5/7] 킬스위치 모니터링 (심볼별 연속 손실/15거래 PF → 2단계 경고 출력) +[6/7] ML 재학습 체크 (누적 트레이드 ≥ 150, PF < 1.0, PF 3주 하락 → 2/3 충족 시 권장) +[7/7] PF < 1.0이면 파라미터 스윕 실행 → 상위 3개 대안 제시 → Discord 알림 + results/weekly/report_YYYY-MM-DD.json 저장 ``` @@ -638,6 +645,9 @@ sequenceDiagram BOT->>NT: notify_close(TP, exit=2.4150, est=+7.00, net=+6.78, diff=-0.22) NT->>NT: Discord 웹훅 전송 + BOT->>BOT: _append_trade(net_pnl, "TP") [JSONL 파일에 기록] + BOT->>BOT: _check_kill_switch() [8연패/PF<0.75 검사] + BOT->>BOT: current_trade_side = None BOT->>BOT: _entry_price = None BOT->>BOT: _entry_quantity = None @@ -720,7 +730,7 @@ bash scripts/run_tests.sh # 래퍼 스크립트 실행 | 파일 | 레이어 | 역할 | |------|--------|------| | `main.py` | — | 진입점. 심볼별 `TradingBot` 생성 + 공유 `RiskManager` + `asyncio.gather()` | -| `src/bot.py` | 오케스트레이터 | 심볼별 독립 트레이딩 루프 | +| `src/bot.py` | 오케스트레이터 | 심볼별 독립 트레이딩 루프 + 듀얼 레이어 킬스위치 | | `src/config.py` | — | 환경변수 기반 설정 (`symbols` 리스트, `correlation_symbols`, 심볼별 `SymbolStrategyParams`) | | `src/data_stream.py` | Data | Combined WebSocket 캔들 수신·버퍼 관리 | | `src/indicators.py` | Signal | 기술 지표 계산 및 복합 신호 생성 | @@ -742,6 +752,8 @@ bash scripts/run_tests.sh # 래퍼 스크립트 실행 | `scripts/train_and_deploy.sh` | MLOps | 전체 파이프라인 (수집 → 학습 → 배포) | | `scripts/deploy_model.sh` | MLOps | 모델 파일 운영 서버 전송 | | `scripts/strategy_sweep.py` | MLOps | 전략 파라미터 그리드 스윕 (324개 조합) | -| `scripts/weekly_report.py` | MLOps | 주간 전략 리포트 (백테스트+대시보드API+추이+스윕+Discord) | +| `scripts/weekly_report.py` | MLOps | 주간 전략 리포트 (백테스트+킬스위치+대시보드API+추이+스윕+Discord) | +| `scripts/compare_symbols.py` | MLOps | 종목 비교 백테스트 (심볼별 파라미터 sweep) | +| `scripts/position_sizing_analysis.py` | MLOps | Robust Monte Carlo 포지션 사이징 분석 | | `scripts/run_backtest.py` | MLOps | 단일 백테스트 CLI | | `models/{symbol}/active_lgbm_params.json` | MLOps | 심볼별 승인된 LightGBM 파라미터 | diff --git a/CLAUDE.md b/CLAUDE.md index 29f1d27..bb5cb9c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -65,6 +65,8 @@ bash scripts/deploy_model.sh --symbol XRPUSDT 4. `src/exchange.py` + `src/risk_manager.py` — Dynamic margin, MARKET orders with SL/TP, daily loss limit (5%), same-direction limit 5. `src/user_data_stream.py` + `src/notifier.py` — Real-time TP/SL detection via WebSocket, Discord webhooks +**Dual-layer kill switch** (per-symbol, in `src/bot.py`): Fast Kill (8 consecutive net losses) + Slow Kill (last 15 trades PF < 0.75). Trade history persisted to `data/trade_history/{symbol}.jsonl`. Blocks new entries only; existing SL/TP exits work normally. Manual reset via `RESET_KILL_SWITCH_{SYMBOL}=True` env var + restart. + **Parallel execution**: Per-symbol bots run independently via `asyncio.gather()`. Each bot's `user_data_stream` also runs in parallel. **Model/data directories**: `models/{symbol}/` and `data/{symbol}/` for per-symbol models. Falls back to `models/` root if symbol dir doesn't exist. diff --git a/README.md b/README.md index 6a1f3d6..a1b58ff 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,12 @@ Binance Futures 자동매매 봇. 복합 기술 지표와 ML 필터(LightGBM / M - **ATR 기반 손절/익절**: 변동성에 따라 동적으로 SL/TP 계산, 환경변수로 배수 조절 - **반대 시그널 재진입**: 보유 포지션과 반대 신호 발생 시 즉시 청산 후 재진입 - **리스크 관리**: 동일 방향 포지션 제한, 일일 손실 한도(5%), 동적 증거금 비율 +- **듀얼 레이어 킬스위치**: Fast Kill(8연속 순손실) + Slow Kill(15거래 PF<0.75) — 심볼별 독립 차단, 기존 포지션 청산은 정상 작동 - **실시간 TP/SL 감지**: Binance User Data Stream으로 즉시 감지 -- **Discord 알림**: 진입·청산·오류 이벤트 실시간 웹훅 알림 +- **Discord 알림**: 진입·청산·킬스위치 발동·오류 이벤트 실시간 웹훅 알림 - **모니터링 대시보드**: 거래 내역, 수익 통계, 차트를 웹에서 조회 -- **주간 전략 리포트**: 자동 성능 측정, 추이 추적, ML 재학습 시점 판단 +- **주간 전략 리포트**: 자동 성능 측정, 추이 추적, 킬스위치 모니터링, ML 재학습 시점 판단 +- **종목 비교 분석**: 심볼별 파라미터 sweep + Robust Monte Carlo 포지션 사이징 --- @@ -48,7 +50,7 @@ cp .env.example .env # 필수 BINANCE_API_KEY=your_api_key BINANCE_API_SECRET=your_api_secret -SYMBOLS=XRPUSDT # 거래할 심볼 (쉼표 구분, 예: XRPUSDT,TRXUSDT,DOGEUSDT) +SYMBOLS=XRPUSDT,SOLUSDT,DOGEUSDT # 거래할 심볼 (쉼표 구분) # 권장 DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/... @@ -123,14 +125,15 @@ Discord 웹훅을 설정했다면 진입/청산 시 실시간 알림을 받게 **심볼별 오버라이드**: `{환경변수}_{심볼}` 형태로 심볼마다 독립 설정 가능. 미설정 시 전역 기본값 사용. ```env -# 예시: 2026-03-17 스윕 최적화 결과 +# 예시: 스윕 최적화 결과 ATR_SL_MULT_XRPUSDT=1.5 ATR_TP_MULT_XRPUSDT=4.0 ADX_THRESHOLD_XRPUSDT=30 -ATR_SL_MULT_TRXUSDT=2.0 -ATR_TP_MULT_TRXUSDT=4.0 -ADX_THRESHOLD_TRXUSDT=25 +ATR_SL_MULT_SOLUSDT=1.0 +ATR_TP_MULT_SOLUSDT=4.0 +ADX_THRESHOLD_SOLUSDT=20 +MARGIN_MAX_RATIO_SOLUSDT=0.08 ATR_SL_MULT_DOGEUSDT=2.0 ATR_TP_MULT_DOGEUSDT=2.0 @@ -158,10 +161,39 @@ ML 필터는 기술 지표 신호를 한 번 더 검증하여 오진입을 차 | `MARGIN_MIN_RATIO` | `0.20` | 최소 증거금 비율 (잔고 대비) | | `MARGIN_DECAY_RATE` | `0.0006` | 잔고 증가 시 증거금 비율 감소 속도 | -- **일일 손실 한도**: 기준 잔고의 5% 초과 시 당일 거래 중단 +- **일일 손실 한도**: 기준 잔고의 5% 초과 시 당일 거래 중단 (단일 충격 방어) +- **듀얼 레이어 킬스위치**: 구조적 엣지 소실에 의한 점진적 계좌 우하향(Slow Bleed) 방어 - **동적 증거금**: 잔고가 늘어날수록 비율을 선형으로 줄여 과노출 방지 - **포지션 복구**: 봇 재시작 시 기존 포지션 자동 감지 및 상태 복원 +### 킬스위치 + +일일 손실 한도는 단일 충격 방어용이지, 누적 승률 하락 방어용이 아닙니다. 매일 한도 근처까지 손실을 내고 멈추는 패턴이 반복되면 한 달 뒤 계좌의 30~40%가 조용히 증발합니다. 킬스위치는 이 Slow Bleed를 자동으로 차단합니다. + +| 레이어 | 조건 | 방어 대상 | +|--------|------|-----------| +| **Fast Kill** | 8연속 순손실 (net_pnl, 수수료 포함) | 급격한 전략 붕괴 | +| **Slow Kill** | 최근 15거래 Profit Factor < 0.75 | 점진적 엣지 소실 | + +**동작 방식:** +- 심볼별 독립 제어: SOL이 킬되어도 XRP/DOGE는 정상 운영 +- 진입만 차단: 기존 포지션의 SL/TP 청산은 정상 작동 (물린 상태 방치 방지) +- 거래 이력 persist: `data/trade_history/{symbol}.jsonl`에 매 청산마다 기록 +- 봇 재시작 시 소급 검증: 이력 파일에서 마지막 15건을 읽어 킬스위치 상태 복원 +- 수동 해제: `.env`에 `RESET_KILL_SWITCH_{SYMBOL}=True` 추가 후 봇 재시작 + +**주간 리포트 모니터링:** +``` +[킬스위치 모니터링] + XRP: 연속손실 2/8 | 15거래PF 1.42 + SOL: 연속손실 0/8 | 15거래PF -.-- (3건) + DOGE: 연속손실 6/8 ⚠ | 15거래PF 0.71 🔴 KILLED +``` + +| 환경변수 | 설명 | +|---------|------| +| `RESET_KILL_SWITCH_{SYMBOL}` | `True`로 설정 후 재시작하면 해당 심볼 킬스위치 해제. 해제 후 반드시 제거할 것 | + --- ## 대시보드 @@ -219,6 +251,8 @@ docker compose up -d | `ADX_THRESHOLD_{SYMBOL}` | — | | 심볼별 ADX 필터 오버라이드 | | `VOL_MULTIPLIER_{SYMBOL}` | — | | 심볼별 거래량 배수 오버라이드 | | `DASHBOARD_API_URL` | `http://10.1.10.24:8000` | | 대시보드 API 주소 (주간 리포트용) | +| `MARGIN_MAX_RATIO_{SYMBOL}` | — | | 심볼별 최대 증거금 비율 오버라이드 | +| `RESET_KILL_SWITCH_{SYMBOL}` | — | | `True`로 설정 후 재시작하면 킬스위치 해제 (해제 후 반드시 제거) | | `BINANCE_TESTNET_API_KEY` | — | | Testnet API 키 | | `BINANCE_TESTNET_API_SECRET` | — | | Testnet API 시크릿 | @@ -257,7 +291,9 @@ cointrader/ │ ├── train_and_deploy.sh # 전체 파이프라인 (--symbol / --all 지원) │ ├── tune_hyperparams.py # Optuna 하이퍼파라미터 자동 탐색 (--symbol 지원) │ ├── strategy_sweep.py # 전략 파라미터 그리드 스윕 (324개 조합) -│ ├── weekly_report.py # 주간 전략 리포트 (백테스트+대시보드API+추이+Discord) +│ ├── compare_symbols.py # 종목 비교 백테스트 (심볼별 파라미터 sweep) +│ ├── position_sizing_analysis.py # Robust Monte Carlo 포지션 사이징 분석 +│ ├── weekly_report.py # 주간 전략 리포트 (백테스트+킬스위치+대시보드API+추이+Discord) │ ├── run_backtest.py # 단일 백테스트 CLI │ ├── deploy_model.sh # 모델 파일 LXC 서버 전송 (--symbol 지원) │ └── run_tests.sh # 전체 테스트 실행 @@ -266,6 +302,7 @@ cointrader/ │ └── ui/ # React 프론트엔드 (Vite + Recharts) ├── models/ # 학습된 모델 저장 (심볼별 하위 디렉토리) ├── data/ # 과거 데이터 캐시 (심볼별 하위 디렉토리) +│ └── trade_history/ # 킬스위치용 실전 거래 이력 (심볼별 JSONL) ├── results/ │ └── weekly/ # 주간 리포트 JSON 저장 ├── logs/ # 로그 파일