Files
myProfile/uploads/learning/종합기획서_단타자동매매_6a041d60084271.93225085.txt
T
2026-05-31 21:05:59 +09:00

537 lines
18 KiB
Plaintext
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.
# 단타 자동매매 시스템 종합 기획서
> 버전: v1.0
> 기준: 한국 주식 (코스피/코스닥) / KIS Open API / Synology NAS Docker
> 원칙: 규칙 기반 완전 자동화, 인간 판단 개입 0
---
## 0. 설계 원칙 (절대 불변)
1. **감정 0** — 모든 진입/청산은 코드가 결정. 예외 없음
2. **손절 우선** — 수익 극대화보다 손실 제한이 먼저
3. **단순함 우선** — 복잡한 전략보다 단순하고 견고한 전략
4. **검증 후 실거래** — 백테스트 → 모의투자 3개월 → 소액 실거래 순서 필수
5. **14:50 전량 청산** — 오버나이트는 절대 없음. 하드코딩
---
## 1. 시스템 전체 구조
```
┌─────────────────────────────────────────────────────────┐
│ Synology NAS (Docker) │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ stockbot │ │ kill-switch │ ← 별도 컨테이너 │
│ │ (메인) │ │ (긴급중단) │ │
│ └──────┬───────┘ └──────────────┘ │
│ │ │
│ ┌──────▼───────────────────────────────────┐ │
│ │ asyncio Event Loop │ │
│ │ ┌─────────┐ ┌─────────┐ ┌───────────┐ │ │
│ │ │Universe │ │Strategy │ │ Risk │ │ │
│ │ │Scanner │ │Engine │ │ Manager │ │ │
│ │ └─────────┘ └─────────┘ └───────────┘ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌───────────┐ │ │
│ │ │ Data │ │ Order │ │ Notifier │ │ │
│ │ │Collector│ │Executor │ │(Telegram) │ │ │
│ │ └─────────┘ └─────────┘ └───────────┘ │ │
│ └───────────────────────┬──────────────────┘ │
│ │ │
│ ┌───────────────────────▼──────────────────┐ │
│ │ SQLite (체결/포지션/로그) │ │
│ │ Redis (실시간 시세 캐시) │ │
│ └──────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ Streamlit Dashboard (포트 8501) │ │
│ └──────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│ │
KIS WebSocket KIS REST API
(실시간 시세) (주문/잔고)
```
---
## 2. 기술 스택 (확정)
| 항목 | 선택 | 이유 |
|------|------|------|
| 언어 | Python 3.11 | 생태계, KIS 예제 코드 모두 Python |
| 비동기 | asyncio + aiohttp | 초당 20건 rate limit 정밀 제어 |
| DB | SQLite | NAS 메모리 절약, 단일 파일 백업 용이 |
| 캐시 | Redis 7 (Docker) | 실시간 시세 캐시, TTL 관리 |
| 스케줄러 | APScheduler 3.x (AsyncIOScheduler) | 장 시작/마감 이벤트 트리거 |
| 알림 | python-telegram-bot | 단일 채널, 신뢰성 높음 |
| 대시보드 | Streamlit | 설치 단순, NAS 내부망 접근 |
| 컨테이너 | Docker Compose | Synology Container Manager 호환 |
| 백테스트 | vectorbt | pandas 기반, 분봉 데이터 처리 빠름 |
| 데이터 수집 | pykrx + KIS REST | 과거 분봉 백필 |
---
## 3. 디렉토리 구조
```
/volume1/docker/stockbot/
├── docker-compose.yml
├── .env ← API 키 전용 (Git 제외)
├── app/
│ ├── main.py ← 진입점, asyncio 루프
│ ├── config.py ← 전략 파라미터 전용
│ │
│ ├── data/
│ │ ├── collector.py ← KIS WebSocket 시세 수신
│ │ ├── universe.py ← 종목 풀 갱신 (08:30)
│ │ └── backfill.py ← 과거 분봉 백필 스크립트
│ │
│ ├── strategy/
│ │ ├── base.py ← 전략 추상 클래스
│ │ └── volatility_breakout.py ← 전략 A (유일한 실전 전략)
│ │
│ ├── risk/
│ │ └── manager.py ← 손절/일일한도/강제청산
│ │
│ ├── execution/
│ │ ├── kis_client.py ← KIS REST/WebSocket 래퍼
│ │ └── order_executor.py ← 주문 전송, 재시도, 슬리피지
│ │
│ ├── monitor/
│ │ ├── notifier.py ← 텔레그램 알림
│ │ └── dashboard.py ← Streamlit 대시보드
│ │
│ └── db/
│ ├── models.py ← SQLite 스키마
│ └── repository.py ← DB 접근 레이어
├── kill_switch/
│ └── kill.py ← 긴급 전량 청산 단독 실행
├── backtest/
│ ├── run_backtest.py ← vectorbt 백테스트 실행
│ └── results/ ← 백테스트 결과 저장
├── data/
│ ├── stockbot.db ← SQLite DB
│ └── universe_cache.json ← 당일 종목 풀 캐시
└── logs/
└── trades.log ← 영구 보관 (세금 신고용)
```
---
## 4. 전략 (확정: 전략 A 단독)
### 변동성 돌파 전략 (Volatility Breakout)
**선정 이유:**
- 래리 윌리엄스 실전 검증, 30년 이상 데이터 기반
- 룰이 단순 → 과적합 위험 최소
- 분봉 적용 시 한국 장 오전 변동성과 궁합 최적
- 진입 조건이 명확 → 자동화 구현 난이도 낮음
**핵심 파라미터 (config.py에서 관리)**
```python
STRATEGY_K = 0.5 # 변동성 계수 (0.4~0.6 안정 구간)
ENTRY_START = "09:00" # 진입 허용 시작
ENTRY_END = "14:30" # 진입 허용 마감
FORCE_EXIT = "14:50" # 강제 청산 시각 (하드코딩)
TP1_PCT = 0.02 # 1차 익절 +2% (50% 매도)
TP2_PCT = 0.03 # 2차 익절 +3% (전량)
SL_PCT = 0.015 # 손절 -1.5% (즉시 시장가)
MAX_HOLD_MIN = 120 # 최대 보유시간 120분 (무수익 시 청산)
```
**진입 로직**
```
목표가 = 당일 시가 + (전일 고가 - 전일 저가) × K
진입 조건 (전부 충족 시):
1. 현재가 >= 목표가
2. 현재 시각 ENTRY_START ~ ENTRY_END
3. 당일 KOSPI 등락률 > -1.0% ← 시장 약세 차단
4. 전일 거래대금 >= 100억
5. 시가총액 1,000억 ~ 3조
6. VI 미발동 종목
7. 당일 보유 종목 수 < 2 ← 동시 최대 2종목
8. 일일 누적 손실 < -3% ← 손실 한도 미도달
```
**청산 로직 (우선순위 순)**
```
1순위: 강제 청산 → 14:50 시장가 전량
2순위: 손절 → 현재가 <= 매수가 × (1 - SL_PCT) → 시장가
3순위: 1차 익절 → 현재가 >= 매수가 × (1 + TP1_PCT) → 50% 지정가
4순위: 2차 익절 → 현재가 >= 매수가 × (1 + TP2_PCT) → 전량 지정가
5순위: 시간 청산 → 보유 후 MAX_HOLD_MIN 경과, 수익 없을 시 시장가
```
---
## 5. 종목 유니버스 선정 (Universe)
매일 08:30 자동 갱신.
**1차 필터 (정적)**
| 조건 | 기준 |
|------|------|
| 시장 | 코스피 + 코스닥 |
| 시가총액 | 1,000억 ~ 3조 |
| 상장 기간 | 6개월 이상 |
| 제외 | 관리종목, 거래정지, 우선주, 스팩, ETF, ETN |
**2차 필터 (동적, 전일 기준)**
| 조건 | 기준 |
|------|------|
| 전일 거래대금 | 100억 이상 |
| 5일 평균 거래대금 | 50억 이상 |
| 전일 등락률 | -3% ~ +15% |
| 일봉 60일 이평선 | 현재가 위 |
**결과: 최대 30종목** (KIS WebSocket 안정성 기준으로 50 → 30 축소)
---
## 6. 리스크 관리
### 포지션 규칙
| 항목 | 값 |
|------|-----|
| 1종목 최대 비중 | 총자산 × 20% |
| 동시 보유 최대 | 2종목 |
| 분할매수 | 1차 10%, 신호 유지 시 2차 10% |
### 손실 한도 (계층별 자동 중단)
| 레벨 | 조건 | 동작 |
|------|------|------|
| L1 | 1회 매매 -1.5% | 즉시 손절 |
| L2 | 일일 누적 -3% | 당일 신규 진입 중단 |
| L3 | 3연속 손절 | 당일 매매 중단 |
| L4 | 주간 누적 -7% | 주말까지 중단 + 텔레그램 경고 |
| L5 | 월간 누적 -15% | 자동 전략 폐기 + 백테스트 재요청 |
### 안전장치
- VI(변동성완화장치) 발동 → 즉시 해당 종목 청산
- 호가 스프레드 > 0.5% → 진입 금지
- 매수 후 5분 미체결 → 주문 취소
- WebSocket 끊김 → 보유 포지션 즉시 시장가 청산
- API 오류 10건/분 → kill-switch 컨테이너 자동 실행
---
## 7. KIS API 운용
### 초당 20건 제한 대응 전략
```
WebSocket (실시간 시세) : 30종목 구독 → REST 호출 없음
REST (주문/잔고) : 주문 시에만 호출
REST (분봉 조회) : 신호 확인용, 1초 간격 제한
asyncio Semaphore(20) 로 초당 20건 보장
배치 처리: 30종목 ÷ 20건 = 1.5초/1회전
```
### WebSocket 구독 항목
- 실시간 체결가 (H0STCNT0)
- 실시간 호가 (H0STASP0)
- VI 발동/해제 (H0STVI0)
### 주문 타입 결정
| 상황 | 주문 타입 |
|------|----------|
| 진입 | 시장가 (빠른 체결 우선) |
| 1차 익절 | 지정가 (목표가 미리 걸기) |
| 2차 익절 | 지정가 |
| 손절 | 시장가 (슬리피지 감수) |
| 강제청산 | 시장가 |
---
## 8. 스케줄 타임라인
```
08:00 │ 시스템 기동, DB 연결 확인
08:30 │ Universe 갱신 (pykrx 전일 데이터)
08:50 │ WebSocket 연결, 30종목 구독 시작
│ 당일 시가 기반 목표가 계산
09:00 │ ─────────── 진입 허용 시작 ───────────
│ 1분봉 루프 시작 (asyncio, 1초 단위)
11:30 │ 신규 진입 일시 중단 (점심)
13:00 │ 신규 진입 재개
14:30 │ 신규 진입 마감
14:50 │ ─────────── 강제 청산 ───────────────
│ 보유 포지션 전량 시장가 매도
15:00 │ WebSocket 연결 종료
15:10 │ 당일 결산 로그 생성
15:20 │ 텔레그램 일일 결산 알림 발송
15:30 │ 시스템 대기 (다음 날 08:00까지)
```
---
## 9. DB 스키마 (SQLite)
```sql
-- 체결 내역
CREATE TABLE trades (
id INTEGER PRIMARY KEY AUTOINCREMENT,
date TEXT NOT NULL, -- YYYY-MM-DD
ticker TEXT NOT NULL,
entry_time TEXT NOT NULL, -- HH:MM:SS
exit_time TEXT,
entry_price REAL NOT NULL,
exit_price REAL,
quantity INTEGER NOT NULL,
side TEXT NOT NULL, -- BUY / SELL
exit_reason TEXT, -- TP1/TP2/SL/FORCE/TIME
pnl REAL,
fee REAL,
slippage REAL,
strategy TEXT DEFAULT 'VB'
);
-- 일일 요약
CREATE TABLE daily_summary (
date TEXT PRIMARY KEY,
total_trades INTEGER,
win_trades INTEGER,
lose_trades INTEGER,
gross_pnl REAL,
total_fee REAL,
net_pnl REAL,
max_drawdown REAL,
trading_stopped INTEGER DEFAULT 0 -- L2 발동 여부
);
-- 포지션 (장중 현황)
CREATE TABLE positions (
ticker TEXT PRIMARY KEY,
entry_time TEXT,
entry_price REAL,
quantity INTEGER,
tp1_done INTEGER DEFAULT 0,
target_price REAL,
stop_price REAL
);
```
---
## 10. 알림 설계 (텔레그램)
| 이벤트 | 메시지 형식 |
|--------|-----------|
| 진입 | `[매수] 삼성전자 74,000원 / 목표 75,480 / 손절 72,890` |
| 1차 익절 | `[익절1] 삼성전자 +2.1% / 잔여 50%` |
| 손절 | `[손절] 삼성전자 -1.5% / 즉시 청산` |
| 강제 청산 | `[14:50 강제청산] 전 포지션 청산 완료` |
| L2 발동 | `[경고] 일일 손실 -3% 도달. 오늘 매매 중단.` |
| 일일 결산 | `[결산] 매매 5회 / 승 3 패 2 / 순손익 +1.2%` |
| 장애 | `[긴급] WebSocket 끊김. kill-switch 실행.` |
---
## 11. 백테스트 계획
### 데이터 준비
```
수집 대상: 코스피200 + 코스닥150 편입 종목
기간: 2021-01-01 ~ 2024-12-31 (4년치)
봉: 1분봉
도구: pykrx (무료, 과거 분봉 제공)
생존편향: 상장폐지 종목 별도 수집 포함
```
### 수수료 시뮬레이션
```
매수 수수료: 0.015%
매도 수수료: 0.015%
거래세: 0.18% (매도 시)
슬리피지: 시장가 0.10%, 지정가 0.03%
총 1회전 비용 추정: 약 0.21%
```
### 합격 기준 (out-of-sample 1년 기준)
| 지표 | 통과 기준 | 목표 |
|------|----------|------|
| 샤프지수 | > 1.0 | > 1.5 |
| MDD | < 15% | < 10% |
| 승률 | > 45% | > 55% |
| 손익비 | > 1.3 | > 1.8 |
| 일평균 매매 | 1~5회 | 2~3회 |
### K값 최적화 방법
```
1. K = 0.3 ~ 0.8 구간 0.05 단위 그리드 서치
2. 인샘플(2021~2023) 에서 상위 3개 K값 선별
3. 아웃샘플(2024) 에서 재검증
4. 피크 K값 배제 → 샤프지수 안정 구간 채택
5. 최종 채택: K = 0.5 (사전 기본값, 백테스트로 재확인)
```
---
## 12. 인프라 (Synology Docker)
### docker-compose.yml
```yaml
version: "3.9"
services:
redis:
image: redis:7-alpine
container_name: stockbot-redis
restart: unless-stopped
volumes:
- ./data/redis:/data
stockbot:
build: ./app
container_name: stockbot-main
restart: unless-stopped
depends_on:
- redis
env_file: .env
volumes:
- ./data:/app/data
- ./logs:/app/logs
environment:
- TZ=Asia/Seoul
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "5"
kill-switch:
build: ./kill_switch
container_name: stockbot-killswitch
restart: "no" # 수동 또는 자동 트리거 시에만 실행
env_file: .env
profiles: ["emergency"] # docker compose --profile emergency up
dashboard:
build: ./monitor
container_name: stockbot-dashboard
restart: unless-stopped
ports:
- "8501:8501"
volumes:
- ./data:/app/data
environment:
- TZ=Asia/Seoul
```
### .env 구조
```
# KIS API
KIS_APP_KEY=...
KIS_APP_SECRET=...
KIS_ACCOUNT_NO=...
KIS_MOCK=true # 모의투자: true / 실거래: false
# 텔레그램
TELEGRAM_TOKEN=...
TELEGRAM_CHAT_ID=...
# Redis
REDIS_HOST=stockbot-redis
REDIS_PORT=6379
# 운영 모드
DRY_RUN=true # 주문 실제 전송 여부
LOG_LEVEL=INFO
```
---
## 13. 개발 로드맵
### Phase 1 — 데이터 기반 구축 (2주)
- [ ] KIS Open API 신청 + 모의투자 계좌 개설
- [ ] pykrx로 2021~2024 분봉 데이터 백필
- [ ] SQLite 스키마 생성
- [ ] Universe 스캐너 구현 (08:30 갱신)
- [ ] Docker Compose 기동 확인 (NAS)
### Phase 2 — 백테스트 (3주)
- [ ] vectorbt 환경 구성
- [ ] 변동성 돌파 전략 백테스트 코드 작성
- [ ] 수수료/슬리피지 반영
- [ ] K값 그리드 서치
- [ ] out-of-sample 검증 → 합격 기준 통과 확인
### Phase 3 — KIS 연동 + dry-run (2주)
- [ ] KIS REST 클라이언트 구현 (인증/토큰 갱신)
- [ ] KIS WebSocket 클라이언트 구현 (시세 수신)
- [ ] OrderExecutor 구현 (시장가/지정가/IOC)
- [ ] DRY_RUN=true 상태에서 신호 발생 확인
### Phase 4 — 리스크 + 알림 + 대시보드 (2주)
- [ ] RiskManager 전 계층 구현 (L1~L5)
- [ ] kill-switch 컨테이너 구현
- [ ] 텔레그램 Notifier 구현
- [ ] Streamlit 대시보드 구현 (실시간 PnL)
### Phase 5 — 모의투자 실운영 (최소 3개월)
- [ ] KIS_MOCK=true, DRY_RUN=false
- [ ] 매일 결산 로그 검토
- [ ] 주간 샤프지수/MDD 추적
- [ ] 이상 거동 발생 시 전략 파라미터 재검토 (코드 수정, K값 조정)
- [ ] 3개월 연속 샤프 > 1.0, MDD < 15% 달성 시 Phase 6 진입
### Phase 6 — 소액 실거래 (무기한)
- [ ] KIS_MOCK=false
- [ ] 총자산의 5% 한도로 시작
- [ ] 1개월 단위 성과 검토, 한도 점진 확대
---
## 14. 보안 체크리스트
- [ ] .env → .gitignore 등록 필수
- [ ] KIS API 키 → GitHub 절대 커밋 금지
- [ ] Synology 방화벽: 8501 포트 내부망만 허용
- [ ] 텔레그램 봇: 특정 chat_id만 허용 (화이트리스트)
- [ ] 모든 주문 로그 SQLite + logs/ 이중 보관
- [ ] 월 1회 .env 파일 암호화 백업
---
## 15. 절대 금지 항목 (하드코딩)
```python
# 이 리스트는 코드에서 상수로 관리, 절대 런타임 수정 불가
BLACKLIST_REASONS = [
"신규상장 6개월 미만",
"관리종목",
"투자경고",
"거래정지",
"우선주",
"스팩",
"ETF/ETN",
]
TRADING_BLACKOUT = [
("11:30", "13:00"), # 점심 휴식
("14:50", "15:30"), # 장 마감 전
("08:00", "09:00"), # 동시호가
]
HARD_EXIT_TIME = "14:50" # 절대 변경 불가
```
---
## 16. 면책 조항
> 본 기획서는 시스템 설계 문서이며, 투자 수익을 보장하지 않는다.
> 단타는 통계적으로 개인투자자의 90% 이상이 손실을 보는 영역이다.
> 백테스트 결과는 미래 수익을 보장하지 않으며, 반드시 모의투자 3개월 이상 검증 후 실거래로 전환할 것.
> 시스템 장애, API 오류, 네트워크 단절로 인한 손실에 대해 어떠한 책임도 지지 않는다.