Files
kis_bot/kis_trader
Your Name 4dbb1387a1 fix: 백테스트 UI 렌더링(엔진/휩쏘) 오류 및 mode_refine 작업 라벨 수정
- optuna_web_jobs.py:
  - 과거 JSON 로그에 use_rust 필드가 없는 경우 꼬리잡기 외에는 Python 엔진으로 폴백 처리되도록 수정
  - mode_refine 작업 생성 시 특정 조건에서 label 포맷팅 에러(None)로 인해 UI에서 라벨이 소실되는 버그 수정
  - legacy JSON에 대비하여 whipsaw 관련 속성명(whipsaw_filter_enabled 등)의 호환성 확보
  - register_result_json_as_job 시 use_rust 필드 저장 보장
- backtest_web.py:
  - 완료된 작업의 경우에도 period_info 파싱/복구 로직을 추가하여 요약(summary)이 정상 렌더링 되도록 폴백 보완
- 참고: 일부 레거시 데이터와의 호환성 충돌 등 미처 파악하지 못한 엣지 케이스 오류가 아직 남아있을 수 있음
2026-09-06 16:59:14 +09:00
..
2026-05-05 21:04:17 +09:00
2026-08-19 22:11:31 +09:00

kis_trader — 통합 트레이딩 봇

스캘핑(SCALP) + 꼬리잡기(SHORT, Tail Catch) 두 전략을 단일 프로세스에서 각자 독립 쓰레드로 돌리는 통합 봇. KIS REST/WebSocket 호출을 단일 허브로 묶고, 주문은 단일 OrderManager 를 경유해 ODNO 기반으로 추적한다.

디렉터리

kis_trader/
├── main.py                  # 오케스트레이터 (각 전략을 쓰레드로 기동)
├── utils/
│   ├── env.py               # env_config (DB) + os.environ 통합 조회
│   ├── logger.py            # 공용 로거 / 안전 JSON 저장 / 알림(MM/TG)
│   └── request_handler.py   # SafeRequest: rate-limit + 재시도
├── network/
│   └── ws_manager.py        # 단일 WS 허브 (kis_ws 재사용, 구독 ref-counting)
├── strategies/
│   ├── base.py              # BaseStrategy (threading.Thread)
│   ├── scalping.py          # scalping_engine 래퍼
│   └── tail_catch.py        # tail_engine 래퍼
├── execution/
│   ├── kis_client.py        # 통합 KIS REST 클라이언트 (ODNO 반환)
│   └── order_manager.py     # Master Executor (종목 Lock + 실잔고검증)
├── database/
│   └── db_manager.py        # TradeDBExt: 기존 TradeDB + orders 테이블
└── backtest/
    └── backtest_web.py      # 기존 backtest_web.py 재호출 래퍼

아키텍처 한 눈에

[SCALP 쓰레드]  ──┐
                   │─▶ OrderRequest ─▶  OrderManager  ─▶  KISClient  ─▶  KIS API
[SHORT 쓰레드]  ──┘                       │  │  │
                                          │  │  └── DB(orders) ← ODNO PK
                                          │  └───── DB(active_trades, trade_history)
                                          └──────── 실잔고 검증 (get_broker_holdings)

공유 인프라 (1개 인스턴스)
  • KISClient      : 토큰/Throttle/재시도
  • WSManager      : 단일 WS 세션, 구독 ref counting
  • TradeDBExt     : orders 테이블 + 기존 TradeDB
  • OrderManager   : 종목 Lock, 동일 종목 다전략 정책, ODNO 저장

왜 이 구조인가

기존 문제 새 구조에서의 해결
봇이 잡고 있는 holdings 가 실제 계좌와 어긋남 매도/매수 직전 OrderManager.get_broker_holdings(force=True) 호출로 실잔고 검증
두 봇이 같은 종목에 동시 매수 → 이중 포지션 OrderManager._code_locks[code] 로 직렬화 + orders 테이블 UNIQUE(strategy,code,side,date)
주문번호(ODNO) 미저장 → 사후 추적 불가 kis_client._order() 가 ODNO 반환 → TradeDBExt.insert_order() 로 PK 저장
토큰 재발급 경합 / REST 호출 폭주 KISClient 하나 + kis_token_manager 공유 + SafeRequest 쿨다운
두 봇이 WS 각자 → 구독 수/approval_key 경합 WSManager 단일 세션 + 구독 레퍼런스 카운팅
설정 하드코딩 모든 값은 env_configos.environ → 기본값 순으로 조회

실행

cd ~/kis_bot

# 기본(두 전략 모두 ON)
python -m kis_trader.main

# 스캘핑만
STRATEGY_SCALP_ENABLED=true STRATEGY_SHORT_ENABLED=false python -m kis_trader.main

# 꼬리잡기만
STRATEGY_SCALP_ENABLED=false STRATEGY_SHORT_ENABLED=true python -m kis_trader.main

DB 설정 테이블 (2026-05 분리)

테이블 내용
env_config 공통 — KIS/키움 API, MM, WS, 전략 ON/OFF, 수수료, SLOT_MONEY_DEFAULT
config_scalp 스캘핑 SCALP_*
config_short 꼬리 SHORT_* / TAIL_* / SHOULDER_* / 익절 호가 SELL_ORDERBOOK_*
config_momentum 모멘텀 MOMENTUM_*
config_breakout 돌파 BREAKOUT_*
config_updow 하락매수 UPDOW_*
  • 코드는 get_latest_env() / get_env_from_db()병합 flat dict 를 그대로 씁니다 (하위 호환).
  • 최초 분리·재마이그레이션: python3 -m kis_trader.scripts.migrate_split_env_config
  • 키 분류 규칙: 프로젝트 루트 config_schema.py

주요 환경변수

이름 기본 설명
STRATEGY_SCALP_ENABLED true 스캘핑 전략 활성화
STRATEGY_SHORT_ENABLED true 꼬리잡기 전략 활성화
STRATEGY_SAME_CODE_POLICY allow 같은 종목을 다른 전략이 active_trades에 있어도 allow(허용) / block(차단)
REAL_BALANCE_VERIFY_BEFORE_BUY false false=타 전략·수동 보유 있어도 매수 가능 / true+MODE=strategy면 동일 전략 DB만 차단
REAL_BALANCE_VERIFY_BEFORE_BUY_MODE strategy strategy | global(실계좌 1주라도 있으면 매수 차단, 레거시)
REAL_BALANCE_VERIFY_BEFORE_SELL true 매도 전 실잔고. 보유(hldg_qty)와 매도가능(ord_psbl_qty) 분리. 매도가능 0만으로 유령정리 안 함
ORDER_CASH_PCT 0.95 예수금 부족 시에만 가용금×N%÷MAX_STOCKS 로 qty 축소 (기존 산식 우선)
ORDER_CASH_FEE_BUFFER 1.01 주문금액 대비 수수료 여유 (1.01=1%)
ORDER_CASH_DIVIDE_BY_MAX_STOCKS 1 1=종목당 예수금÷MAX_STOCKS, 0=나누지 않음
ACCOUNT_CASH_PERSIST_SEC 60 예수금 캐시 kv_store 저장 주기(체결 시 즉시 저장)
SCALP_LIVE_BACKTEST_ALIGN true 스캘핑: 신호봉(직전 확정) → 진입봉(현재 확정)=백테 다음봉 시가
SHORT_LIVE_BACKTEST_ALIGN true 꼬리(3분): 동일 패턴
MOMENTUM_LIVE_BACKTEST_ALIGN true 모멘텀(1분): 동일 패턴
BREAKOUT_LIVE_BACKTEST_ALIGN true 돌파(1분): 동일 + 진입가 진입봉 시가 우선
*_LIVE_SIGNAL_LOOKBACK_BARS 1 직전 N개 신호봉까지 소급 검사
MAX_STOCKS 3 전략당 동시 보유 최대 종목 수
REENTRY_COOLDOWN_SEC 300 매도 후 같은 종목 재진입 쿨다운(초)
WS_TIMEFRAMES 1,3,15,60 WS 봉 집계 타임프레임(분)
PERMANENT_WS_CODES 069500,229200 WS 영구 구독 코드(쉼표)
SCALP_STOP_LOSS_PCT / SCALP_TAKE_PROFIT_PCT -0.015 / 0.015 스캘핑 손절/익절 비율
STOP_LOSS_PCT / TAKE_PROFIT_PCT -0.04 / 0.05 꼬리잡기 손절/익절 비율
MAX_LOSS_PER_TRADE_KRW 200000 1회 거래 최대 손실 허용액(원)
SLOT_MONEY_DEFAULT 3000000 1슬롯 기본 투자 금액(원)

전략 ON/OFF 동작 방식

TradingOrchestrator 는 시작 시 STRATEGY_*_ENABLED 를 읽어서 해당 전략 클래스를 쓰레드로 등록한다. 따라서:

  1. 꼬리잡기만 끄고 싶을 때 → env_config 또는 OS env 에 STRATEGY_SHORT_ENABLED=false
  2. 재시작 필요 (동작 중 on/off 전환은 지원 안 함, 대신 공격적 재시작 스크립트 사용)

백테스트

python -m kis_trader.backtest.backtest_web

엔진별로 백테·실매가 동일 함수를 호출한다 (체결·유니버스는 별도).

전략 엔진 청산
SCALP reversal scalping_engine 어깨 → 익절 → 손절
MOMENTUM momentum_engine 어깨·트레일 → 손절 → tp_max 상한
SHORT(꼬리) tail_engine ATR·어깨·EOD
BREAKOUT breakout.py 익절 우선 (돌파 전용)

주의사항

  • 프로젝트 루트의 기존 파일 (scalping_engine.py, tail_engine.py, kis_ws.py, kis_token_manager.py, risk_manager.py, database.py 등) 을 그대로 사용한다. kis_trader/ 는 이들을 조립하는 얇은 래퍼 층이다.
  • DB 스키마에 orders 테이블이 자동 생성된다 (TradeDBExt._ensure_orders_table).
  • 기존 kis_scalping_ver2.py / kis_short_ver3.py 는 남겨두되, 중복 실행 금지 (계좌/토큰/WS 경합).