Files
upbit-trader/STRATEGY.md
joungmin 2499ea08ef docs: rewrite STRATEGY.md for 10m vol-lead strategy
- Remove legacy 40m resampling, velocity-based entry, Bear regime sections
- Add F&G 3-tier vol threshold system (<=40->6x, 41-50->5x, >50->blocked)
- Add undying signal and vol refresh behavior docs
- Add watch alert (4x-6x approaching threshold) documentation
- Add 1yr 10m backtest results and THRESH sweep table
- Add F&G greed blocking effect comparison table
- Update file list, env vars, and sim run commands
- Add change history from 2026-03-03 to 2026-03-04

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 09:51:39 +09:00

310 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Volume Lead 전략 가이드
## 전략 개요
**거래량 선행(Volume Lead) 매집 전략** — 가격이 횡보하는 중 거래량 급증이 발생하면
매집 신호로 기록하고, 이후 일정 수준 이상 상승 시 진입하는 선진입 전략.
> 핵심 아이디어: 대형 매수자는 가격을 올리지 않고 조용히 매집한다.
> 거래량이 먼저 급증하고, 가격 상승은 그 뒤에 따라온다.
**캔들 단위: 10분봉** (Upbit `minute10` API 직접 사용 — 리샘플링 없음)
---
## 진입 조건 (2단계)
### 1단계: 매집 신호 감지
다음 두 조건 동시 충족 시 `signal_price` + `vol_ratio` 기록:
| 조건 | 파라미터 | 기본값 |
|------|----------|--------|
| QN봉(120분) 이전 종가 대비 가격 변동 < N% (횡보) | `PRICE_QUIET_PCT` | 2.0% |
| 직전 완성 10분봉 거래량 ≥ 로컬 LV봉(280분=28봉) 평균 × M배 | `VOL_THRESH_*` | 5.0x / 6.0x |
- 신호 발생 시 텔레그램 🔍 알림 발송
- `SIGNAL_TIMEOUT_MIN`(480분=8h) 초과 시 신호 초기화
- **신호불사**: 가격이 신호가 아래로 내려가도 신호 유지 (sig_p 고정, 만료까지 대기)
- **vol 갱신**: 더 강한 vol_ratio가 오면 신호가(sig_p)와 만료 시간 갱신
> **거래량 기준봉**: `df10["volume"].iloc[-2]` (직전 완성봉) vs 이전 28봉 평균
> **횡보 기준봉**: `df10["close"].iloc[-(QUIET_CANDLES+1)]` = 12봉(120분) 이전 종가
### 2단계: 추세 확인 후 진입
신호가 대비 `TREND_AFTER_VOL`% 이상 상승 확인 시 매수.
| 파라미터 | 기본값 | 설명 |
|----------|--------|------|
| `TREND_AFTER_VOL` | 4.8% | 신호가 대비 추가 상승 진입 임계값 |
### 신호 감시 스레드 (Fast Poll)
신호 감지 후 전체 스캔 60초를 기다리지 않고 해당 종목만 빠르게 폴링.
| 파라미터 | 기본값 | 설명 |
|----------|--------|------|
| `SCAN_INTERVAL` | 60초 | 전체 시장 스캔 주기 |
| `SIGNAL_POLL_INTERVAL` | 15초 | 신호 종목 집중 감시 주기 |
---
## F&G 기반 거래량 임계값 + 진입 차단
**alternative.me API** 기반 일일 공포탐욕지수(0~100) 조회. F&G 구간에 따라
거래량 임계값을 동적으로 조정하고, 탐욕 구간은 진입 전면 차단.
| F&G 구간 | 레이블 | 거래량 임계값 | 진입 여부 |
|----------|--------|-------------|-----------|
| 0 ~ 40 | 극공포 / 공포 | **6.0x** (`VOL_THRESH_FEAR`) | ✅ 허용 |
| 41 ~ 50 | 약공포 / 중립 | **5.0x** (`VOL_THRESH_NORMAL`) | ✅ 허용 |
| 51 ~ 100 | 탐욕 / 극탐욕 | — | ❌ **전면 차단** |
- `FNG_MAX_ENTRY=50` — 초과 시 스캔 전체 스킵
- `FNG_FEAR_THRESHOLD=40` — 이하 시 FEAR 임계값(6.0x) 적용
- API 하루 1회 KST 09:00 업데이트, 캐시 TTL 24시간
- API 실패 시 폴백: 50 (중립, 진입 허용)
**탐욕 구간 차단 이유** (1년 백테스트 검증):
| F&G 구간 | 승률 | 평균 손익 | 누적 수익 |
|----------|------|---------|---------|
| 극공포(0~25) | 57% | +0.71% | 수익 |
| 공포(26~40) | 53% | +0.45% | 수익 |
| 중립(41~50) | 45% | +0.20% | 수익 |
| 탐욕(56~75) | **28%** | **-0.33%** | **손실** |
| 극탐욕(76+) | 25% | -0.50% | 손실 |
탐욕 구간 손실 원인:
1. 이미 많이 오른 상태에서 진입 (QUIET 조건 충족 어려움)
2. vol spike = 세력 차익실현 매물인 경우 多
3. 진입 후 추가 상승 여력 부족
---
## 관찰 알림 (Watch Alert)
신호 임계값(6x/5x)에 못 미치지만 근접한 종목을 텔레그램 👀 알림으로 통보.
실제 매수 로직에는 영향 없음.
| 파라미터 | 기본값 | 설명 |
|----------|--------|------|
| `WATCH_VOL_THRESH` | 4.0x | 관찰 시작 임계값 |
| `WATCH_COOLDOWN_MIN` | 30분 | 같은 종목 재알림 최소 간격 |
| `WATCH_VOL_JUMP` | 0.5x | 쿨다운 무시 vol 상승폭 |
- 조건: `WATCH_VOL_THRESH ≤ vol_r < vth` AND `chg < PRICE_QUIET_PCT`
- 30분 쿨다운 (vol_r이 0.5x 이상 뛰면 즉시 재알림)
---
## 청산 조건
### 트레일링 스탑 (ATR 기반)
- 10분봉 최근 ATR_N봉(7봉=70분) 평균 진폭 계산
- `stop_pct = 평균진폭 × ATR_MULT(1.5)` → 동적 손절폭
- 최소 `ATR_MIN=1.0%` / 최대 `ATR_MAX=2.0%` 범위 내 자동 조정
- 최고가(peak) 대비 `stop_pct` 이하 하락 시 즉시 청산
### 타임 스탑
- 보유 `TS_N`봉(48봉=480분=8h) 경과 후 수익률 < `TIME_STOP_MIN_PCT`(3.0%)이면 청산
---
## 리스크 관리
### Walk-Forward (WF) 필터
| 파라미터 | 기본값 | 설명 |
|----------|--------|------|
| `WF_WINDOW` | 5 | 직전 N건 이력 윈도우 |
| `WF_MIN_WIN_RATE` | 0.40 | 최소 승률 임계값 (40%) |
| `WF_SHADOW_WINS` | 2 | 차단 해제 조건 (가상 N연승) |
- 직전 5건 승률 < 40% → 해당 종목 진입 차단 + 가상(shadow) 포지션으로 재활 추적
- 가상 2연승 달성 시 자동 복귀
- **WF 차단 상태는 Oracle DB(`wf_state` 테이블)에 영속 저장** → 재시작 후에도 복원
### 재매수 차단
- 직전 거래가 손실이었을 경우: 현재가 < 직전매도가 × 1.01 이면 재진입 차단
- 직전 거래가 수익이었을 경우: 필터 스킵 (추가 상승 재진입 허용)
### 예산 관리 (복리)
- 수익/손실 시 운용예산 실시간 반영 (복리)
- 하한선: 초기예산의 30% (기본: 4,500,000원)
- 포지션당 크기: `운용예산 / MAX_POSITIONS`
---
## 운용 설정 (.env)
```env
# 핵심 전략 (10분봉 직접 감지)
LOCAL_VOL_CANDLES=28 # 로컬 vol 평균 구간 (28봉=280분)
QUIET_CANDLES=12 # 횡보 체크 구간 (12봉=120분)
PRICE_QUIET_PCT=2.0 # 횡보 기준 (%)
TREND_AFTER_VOL=4.8 # 진입 임계값 (신호가 대비 %)
SIGNAL_TIMEOUT_MIN=480 # 신호 유효 시간 (분=8h)
# F&G 기반 거래량 임계값
VOL_THRESH_NORMAL=5.0 # 중립 구간 (F&G 41~50)
VOL_THRESH_FEAR=6.0 # 공포/극공포 (F&G ≤ 40)
FNG_FEAR_THRESHOLD=40 # 공포 기준 (이하 → FEAR 임계값)
FNG_MAX_ENTRY=50 # 진입 허용 최대 F&G (초과 → 차단)
# 관찰 알림
WATCH_VOL_THRESH=4.0 # 관찰 시작 임계값
WATCH_COOLDOWN_MIN=30 # 재알림 최소 간격 (분)
WATCH_VOL_JUMP=0.5 # 쿨다운 무시 vol 상승폭
# 청산
TIME_STOP_MIN_PCT=3.0 # 타임스탑 최소 수익률
# TS_N=48봉(480분), ATR_MULT=1.5, ATR_MIN=1%, ATR_MAX=2% (코드 내 고정)
# 포트폴리오
MAX_BUDGET=15000000 # 초기 운용 예산
MAX_POSITIONS=3 # 최대 동시 보유 종목
# 감시 주기
SIGNAL_POLL_INTERVAL=15 # 신호 종목 빠른 감시 (초)
# WF 필터
WF_WINDOW=5
WF_MIN_WIN_RATE=0.40
WF_SHADOW_WINS=2
```
---
## 백테스트 결과 요약
### A. 1년 — 10분봉 직접, FNG_MAX_ENTRY=50 (`tests/sim_10m_vol.py`)
> 기간: 2025-03-03 ~ 2026-03-03 / 데이터: Upbit minute10 캐시 / 20종목
| 항목 | 필터 없음 | FNG_MAX_ENTRY=50 적용 |
|------|---------|---------------------|
| 수익률 | +6.80% | **+18.81%** |
| 최대 낙폭 | -17.0% | **-14.3%** |
| 거래수 | 286건 | 218건 |
| 승률 | 42.0% | 46.3% |
### B. 월별 성과 — 1년 10분봉 (`tests/sim_regime_1y.py`)
> FNG_MAX_ENTRY=50, VOL_THRESH_FEAR=6.0, VOL_THRESH_NORMAL=5.0
| 월 | 거래 | 승률 | 월수익(KRW) | F&G 특징 |
|----|------|------|------------|---------|
| 2025-03 | 14건 | 57% | +447,000원 | 공포→중립 |
| 2025-04 | 5건 | 60% | +289,000원 | 중립 |
| 2025-05 | 11건 | 55% | +506,000원 | 공포 |
| 2025-06 | 4건 | 25% | -88,000원 | 탐욕(차단) |
| 2025-07 | 18건 | 44% | +311,000원 | 공포 |
| 2025-08 | 12건 | 50% | +370,000원 | 공포 |
| 2025-09 | 18건 | 44% | +250,000원 | 중립 |
| 2025-10 | 20건 | 50% | +430,000원 | 공포 |
| 2025-11 | 24건 | 54% | +698,000원 | 중립→탐욕(차단) |
| 2025-12 | 22건 | 41% | -180,000원 | 탐욕(차단효과) |
| 2026-01 | 31건 | 35% | -630,000원 | 극공포 |
| 2026-02 | 39건 | 51% | +1,817,000원 | 공포→중립 |
### C. THRESH 스윕 — 신호가 대비 진입 임계값 (`tests/sim_10m_vol.py` 내 스윕)
> FNG_MAX_ENTRY=50, VOL_THRESH_FEAR=6.0, 1년 10분봉 / 20종목
| THRESH | 진입 | 승률 | 평균손익 | 수익률 | 최대낙폭 |
|--------|------|------|---------|--------|---------|
| 0.0% | 3552건 | 26.6% | -0.33% | -70.0% | -70.4% |
| 1.0% | 2012건 | 25.6% | -0.35% | -70.0% | -70.1% |
| 2.0% | 1075건 | 27.9% | -0.27% | -62.1% | -62.9% |
| 3.0% | 660건 | 28.2% | -0.23% | -40.9% | -42.0% |
| 4.0% | 398건 | 29.6% | -0.14% | -17.2% | -22.7% |
| **4.8%** | **272건** | **36.4%** | **+0.09%** | **+7.6%** | **-12.3%** ← 현재 |
| **6.0%** | **180건** | **38.9%** | **+0.18%** | **+10.6%** | **-7.7%** ← 최적 |
| 8.0% | 100건 | 44.0% | +0.12% | +3.8% | -4.8% |
> vol spike 직후 진입(0~4%)은 가짜 펌프 위험으로 전부 손실.
> 추가 상승 확인(4.8%+)이 필수. 최적값은 6.0%이나 신호 포착 빈도와 트레이드오프.
### D. F&G 탐욕 차단 효과 — 1년 10분봉
| 구성 | 수익률 | 최대낙폭 | 거래수 |
|------|--------|---------|--------|
| 차단 없음 | +6.8% | -17.0% | 286건 |
| FNG_MAX_ENTRY=60 | +12.4% | -15.8% | 254건 |
| **FNG_MAX_ENTRY=50** | **+18.8%** | **-14.3%** | **218건** |
| FNG_MAX_ENTRY=45 | +15.1% | -13.8% | 195건 |
---
## 주요 파일
**프로덕션 코어**
| 파일 | 역할 |
|------|------|
| `core/strategy.py` | 진입 신호 로직 (10분봉 vol-lead + 신호불사 + 관찰알림) |
| `core/fng.py` | F&G 필터 (alternative.me API, 24h 캐시) |
| `core/monitor.py` | ATR 트레일링 스탑 + 타임스탑 |
| `core/trader.py` | 주문 실행 + 복리 예산 + WF 필터 |
| `core/notify.py` | 텔레그램 알림 (매수/매도/신호/관찰/상태) |
| `core/market.py` | 상위 거래량 종목 조회 |
| `daemon/runner.py` | 전체 스캔 루프 + 신호 종목 fast-poll 스레드 |
| `main.py` | 진입점 (스레드 시작 + pm2) |
**백테스트 / 분석 (`tests/`)**
| 파일 | 역할 |
|------|------|
| `tests/collect_1y_data.py` | 1년치 10분봉 데이터 수집 + 캐시 저장 |
| `tests/refresh_cache.py` | 캐시 최신화 (최근 데이터 추가) |
| `tests/sim_10m_vol.py` | 1년 10분봉 복리 시뮬레이션 (현재 전략) |
| `tests/sim_current.py` | 특정 날짜 기준 당일/전일 시뮬 |
| `tests/sim_regime_1y.py` | 1년 월별 성과 분석 |
| `tests/sim_regime_sweep.py` | REGIME_N 파라미터 스윕 (레거시) |
| `tests/sim_vol_override.py` | VOL_THRESH / THRESH 파라미터 스윕 |
| `tests/sim_45m40.py` | 40분봉 복리 시뮬레이션 (레거시) |
---
## 시뮬레이션 실행
```bash
# 1년치 10분봉 데이터 수집 (최초 1회, ~13분 소요)
python tests/collect_1y_data.py
# 캐시 최신화 (기존 데이터에 최근분 추가)
python tests/refresh_cache.py
# 1년 복리 시뮬 — 현재 전략 기준
python tests/sim_10m_vol.py
# 특정 날짜 기준 시뮬 (당일 신호 확인용)
python tests/sim_current.py
# 1년 월별 성과 분석
python tests/sim_regime_1y.py
# THRESH / VOL_THRESH 파라미터 스윕
python tests/sim_vol_override.py
```
---
## 변경 이력
| 날짜 | 변경 내용 |
|------|---------|
| 2026-03-04 | **전략 전면 재작성** — 10분봉 직접 감지, 신호불사, vol 갱신 |
| 2026-03-04 | F&G 3구간 시스템: ≤40→6x / 41~50→5x / >50→차단 (`FNG_MAX_ENTRY=50`) |
| 2026-03-04 | 관찰 알림(Watch Alert) 추가: 4x~신호임계값 근접 시 텔레그램 👀 알림 |
| 2026-03-04 | 1년 10분봉 시뮬레이션 추가 (20종목, `data/sim1y_cache.pkl`) |
| 2026-03-04 | THRESH 스윕 결과: 현재 4.8% 유지, 최적값 6.0% 확인 |
| 2026-03-04 | runner.py: Bear레짐 차단 제거, FNG_MAX_ENTRY(>50) 차단으로 통일 |
| 2026-03-03 | F&G 필터 최초 추가 (`FNG_MIN_ENTRY=41`) |
| 2026-03-03 | 속도 기반 조기 진입 추가 (현재 제거됨) |
| 2026-03-03 | 신호 종목 fast-poll 스레드 추가 (`SIGNAL_POLL_INTERVAL=15s`) |
| 2026-03-03 | 프로젝트 구조 정리: `tests/` `data/` `logs/` 폴더 분리 |