# 단타 자동매매 시스템 종합 기획서 > 버전: 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 오류, 네트워크 단절로 인한 손실에 대해 어떠한 책임도 지지 않는다.