왜: 체결이 없어도 마지막가는 유지인데, TTL로 None 만들고 매도/EOD를 건너뛰어 8/5 돌파·금요일 leftover가 남음. 호가필터 TTL 구멍과 같은 병. 넣을 파일 신규: kis_trader/engine/live_sell_price.py kis_trader/strategies/base.py (_ws_last_quote, _resolve_sell_price) 전략: momentum.py scalping.py tail_catch.py breakout.py range_break.py dart_strategy.py updow_strategy.py updown_feed.py us_momentum.py WS: ws_manager.py kis_ws.py kiwoom_ws.py ls_ws.py kis_ws_overseas.py kis_trader/web/live_config_schema.py (WS_PRICE_MAX_AGE_SEC 기본 0) database.py (키 주석 + legacy/ sys.path) kis_trader/execution/order_manager.py (잔고 있는데 40240000 ghost_purge 금지 — 같은 EOD 사고) EOD가 min_hold에 안 막히게 손본 momentum_hts_logic.py / scalping_engine.py / tail_engine.py (이 대화에서 손본 부분만 확인 후) 문서: docs/like_mcp.md/db_erd.md code_architecture.md (가격 TTL 문구) 메시지 초안 fix: 매수·매도 현재가를 TTL로 버리지 않음 (마지막 RAM) 횡보·체결 공백을 죽은 캐시로 오인해 None 처리하면 손절·EOD가 스킵된다. 호가필터와 같이 나이는 무시하고 마지막 체결가를 유지한다. EOD는 매수가 폴백. 영향: 실매 O / 백테·옵투나 봉 경로 거의 무관 (엔진 식 변경 아님) 커밋 2 — 루트 정리 (remove/ vs legacy/) 왜: 루트 단독봇·테스트는 지울 보관함으로. 웹·알람이 아직 쓰는 모듈은 remove에 두면 나중에 폴더째 삭제 때 깨짐. 넣을 파일 이동: 미사용 → remove/legacy_root/ (래퍼, ETF/키움 옛봇, 테스트, kiwoom_rest_api 등) 이동: 사용 중 → legacy/ (holding_bot kis_holding_ver1 news_analyzer kis_long_ver1/2) 신규: kis_trader/utils/legacy_root.py legacy/README.md remove/README.md import 경로: backtest_web.py mm_butler.py mm_remote.py updow_holding_cfg.py dbband_stock_cfg.py param_search_updow*.py dbband_param_search.py param_search_apply_snapshot.py verify_three_paths.py docs/like_mcp.md/code_architecture.md 수동 노트 메시지 초안 chore: 미사용 루트는 remove/, 웹·알람 구모듈은 legacy/ remove는 나중에 통째 삭제 예정. holding_bot·news_analyzer·kis_long은 ensure_legacy_root로 legacy/만 본다. 빼기: scratch/set_ws_price_max_age_zero.py (일회성)
5.6 KiB
5.6 KiB
ETF 액티브 매매 봇 (RSI 기반 분할 매수 & 슈팅 익절)
📊 전략 개요
테마성 ETF (원자력, 전력망, 이차전지 등) 의 눌림목 분할 매수와 슈팅 익절 전략
매매 로직
| 구분 | 조건 | 실행 |
|---|---|---|
| 1 차 매수 | RSI < 35 | 자본금의 30% 매수 |
| 2 차 매수 | RSI < 30 | 자본금의 30% 추가 매수 (물타기) |
| 3 차 매수 | RSI < 25 | 자본금의 40% 풀매수 |
| 익절 | 수익률 ≥ +4% 또는 RSI ≥ 70 | 전량 매도 |
| 손절 | 수익률 ≤ -10% | 전량 매도 (리스크 관리) |
왜 이 전략이 효과적인가?
- 눌림목 매수: 테마 ETF 가 며칠간 -2~-3% 눌릴 때 RSI 가 하락 → 3 분할로 평단가 낮춤
- 슈팅 익절: 호재로 +3~5% 슈팅 시 RSI 과열 (70 이상) → 전량 익절
- 리스크 관리: -10% 손절로 테마 소멸 시 즉시 손절
🚀 빠른 시작
1. 환경 변수 설정
# DB 에 ETF 유니버스 등록
python update_env_etf.py
설정 예시:
069500: KODEX 200114800: KODEX 은행280670: KODEX 원자력395030: KODEX 이차전지산업405840: KODEX AI 반도체
2. 백테스트 (선택)
# 과거 데이터로 전략 검증
python etf_backtest.py
결과 확인:
URA_etf_trade_history.json: 매매 내역- 최종 수익률, 매매 횟수 등 통계
3. 실전 매매
# 한투 API 연동 실전 매매
python etf_ver1.py
📁 파일 구성
| 파일 | 역할 |
|---|---|
etf_backtest.py |
백테스트 프로그램 (야후 파이낸스 데이터) |
etf_ver1.py |
실전 매매 봇 (한투 API 연동) |
update_env_etf.py |
ETF 유니버스 설정 스크립트 |
kis_ws.py |
WebSocket 실시간 가격 수신 (기존) |
database.py |
DB 관리 (기존) |
🔧 설정 (DB/env)
ETF 유니버스 변경
update_env_etf.py 파일의 ETF_UNIVERSE 값 수정:
"ETF_UNIVERSE": "069500,114800,280670,395030,405840",
매매 비율 조정
etf_ver1.py 내부 상수 수정:
# 3 분할 비율 (현재: 30% / 30% / 40%)
target_amount = cash * 0.3 # 1 차
# 익절/손절 기준
if profit_rate >= 0.04: # +4% 익절
if profit_rate <= -0.10: # -10% 손절
📊 백테스트 결과 분석
결과 파일
{TICKER}_etf_trade_history.json: 전체 매매 내역- 예:
URA_etf_trade_history.json
주요 지표
{
"ticker": "URA",
"date": "2024-03-15",
"type": "SELL (슈팅 익절)",
"price": 25.43,
"qty": 1000,
"profit_loss": 125000,
"rsi": 72.5
}
🏦 한투 API 설정
모의투자 vs 실전투자
database.py 의 env_config 테이블에서 설정:
| 키 | 모의투자 | 실전투자 |
|---|---|---|
KIS_APP_KEY |
KIS_APP_KEY_MOCK |
KIS_APP_KEY_REAL |
KIS_SECRET |
KIS_APP_SECRET_MOCK |
KIS_APP_SECRET_REAL |
KIS_ACCOUNT |
KIS_ACCOUNT_NO_MOCK |
KIS_ACCOUNT_NO_REAL |
KIS_MOCK |
true |
false |
WebSocket 설정
KIS_WS_URL_REAL:ws://ops.koreainvestment.com:21000KIS_WS_URL_MOCK:ws://ops.koreainvestment.com:31000KIS_WS_MOCK_ENABLED:true(모의투자 WebSocket 활성화)
📱 메신저 알림
텔레그램
# env 설정
MM_BOT_TOKEN_ = "YOUR_BOT_TOKEN"
KIS_SHORT_MM_CHANNEL = "YOUR_CHAT_ID"
매터모스트
# env 설정
MM_SERVER_URL = "https://mattermost.hoonfam.org"
MATTERMOST_CHANNEL = "stock"
⚠️ 주의사항
1. API 호출 제한
- 한투 API 는 초당 호출 제한이 있습니다
etf_ver1.py는random.sleep(60~180)으로 부하 방지- 백테스트도
random.sleep(0.5~1.5)적용
2. 슬리피지 & 수수료
- 수수료: 0.015% (ETF 우대)
- 슬리피지: 0.05% (호가 차이)
- 백테스트와 실전의 차이는 슬리피지에서 발생
3. RSI 계산
- 일봉 14 일 기준
- 장중 RSI 가 아닌 전일 종가 기준 RSI
- 실시간 RSI 는 WebSocket 체결가로 계산 가능 (확장 필요)
💡 전략 개선 아이디어
1. 분봉 RSI 활용
# 5 분봉 RSI 추가
prices_5m = get_5min_prices(code, days=5)
rsi_5m = calculate_rsi(prices_5m, period=14)
2. 거래량 필터
# 평균 거래량 대비 200% 이상 시 매수
if volume > volume_ma20 * 2.0:
# 수급 유입으로 판단
3. 테마 분석
# 원자력 관련 뉴스 발생 시
if "원자력" in news and "SMR" in news:
# 해당 ETF 우선 매수
📚 참고 문서
- [한투 API 문서](./한투 GIT)
- [한투 WebSocket 문서](./한투 API)
- 기존 단타 봇
- WebSocket 실시간 가격
❓ FAQ
Q1. ETF 가 아닌 종목에도 사용 가능한가요?
A: 네, RSI 전략은 개별 종목에도 적용 가능합니다. 다만 레버리지/인버스 ETF 는 변동성이 너무 커서 손절 라인을 넓혀야 합니다.
Q2. 3 분할이 아니라 5 분할로 하고 싶어요.
A: etf_ver1.py 의 buy_step 변수를 0~4 로 확장하고 비율을 20% 씩으로 조정하세요.
Q3. 백테스트 결과가 실전과 달라요.
A: 슬리피지와 호가 공백을 고려하지 않았을 수 있습니다. slippage_rate 를 0.1% 로 높여서 테스트해보세요.
🎯 다음 단계
- 백테스트 돌리기:
python etf_backtest.py - 모의투자 테스트:
KIS_MOCK=true로 설정 후python etf_ver1.py - 실전 투자:
KIS_MOCK=false로 설정 후 소액으로 시작
📈 행복한 ETF 투자 되세요!