Files
kis_bot/docs/CANDLE_FLOW.md
2026-03-17 12:33:30 +09:00

3.5 KiB

캔들 수집·저장·매매 흐름 (스캘핑 vs 꼬리잡기)

1. 어떤 봉이 쌓이나? (전략별)

전략 CandleAggregator timeframes 주전략 봉 비고
스캘핑 (kis_scalping_ver1/ver2) [1, 3, 15, 60] 1분봉 (SCALP_CANDLE_TIMEFRAME=1) 4분봉 없음
꼬리잡기 (kis_short_ver2/ver3) [3, 15, 60] 3분봉 1분봉·4분봉 없음
  • 4분봉은 어디에도 사용하지 않음. 1분 / 3분 / 15분 / 60분만 집계·저장.
  • 스캘핑은 1분봉 중심, 꼬리잡기는 3분봉만 매수 신호에 사용.

2. 메모리 vs DB — 전략별 PK 여부

  • ws_candles 테이블은 전략별 PK가 없음.
    UNIQUE KEY (code, timeframe, candle_time) 하나로
    스캘핑이 넣은 1·3·15·60분봉과 꼬리잡기가 넣은 3·15·60분봉이 같은 테이블에 쌓임.
  • 꼬리잡기도 3분봉을 메모리(CandleAggregator) 에 먼저 쌓고,
    봉이 확정될 때마다 Queue → 백그라운드 스레드가 ws_candles에 배치 INSERT.

흐름 요약:

  1. 트랙 1 (매매 두뇌)
    WebSocket 틱 → on_tick()RAM에서만 OHLCV 갱신 →
    매수/매도 판단은 get_candles() / get_latest_confirmed()메모리만 사용 (DB 대기 없음).
  2. 트랙 2 (기록)
    확정 시점에만 dict를 Queue에 put_nowait()
    _db_writer 스레드가 BATCH_SIZE(50)개 또는 FLUSH_INTERVAL(2초)마다 ws_candles에 배치 INSERT.
    봉 모을 때까지 기다리지 않고, 확정되는 대로 메모리에 반영되고, DB는 그 뒤에 비동기로 저장.

3. 매수 시 캔들 조회 — 세 가지 분기 (DB / 메모리 / 키움·KIS REST)

꼬리잡기 매수 신호(check_buy_signal_tail_catch)에서 3분봉을 가져오는 순서:

순서 경로 설명
1 메모리 candle_agg.get_candles(code, 3, 50) — 확정봉만, DB/네트워크 없음
2 DB 메모리에 부족하면 db.get_ws_candles(code, 3, limit=50, confirmed_only=True)
3 REST 그래도 없으면 _get_candles_df() → 실패 시 client.get_minute_chart(code, period="3", limit=20) (KIS). 갭보정은 키움 우선, 없으면 KIS.
  • 매수가 확정봉일 때만 가능하도록 되어 있음:
    • 1·2번은 애초에 확정봉만 반환.
    • 3번(REST)에서 가져온 DataFrame은 마지막 행(진행봉) 제거 df.iloc[:-1] 후 신호 판단에 사용.

위 분기는 kis_short_ver3.py check_buy_signal_tail_catch() 안에 그대로 구현되어 있음 (메모리 → DB → REST 순).


4. “캔들 넣고 바로 매매” — 현재 동작

  • 봉이 확정되는 순간 이미 RAM(_confirmed) 에 들어가므로,
    매수 루프는 DB 쓰기 완료를 기다리지 않고 바로 그 데이터로 신호 판단.
  • DB는 그 뒤에 배치로 저장되므로, “캔들 DB에 넣고 나서 매매”를 기다릴 필요 없음.
    다만 봇 기동 직후에는 메모리에 봉이 없을 수 있음 →
    _fill_all_gaps()에서 키움(우선) 또는 KIS REST로 과거 봉을 가져와 fill_gap_from_rest()
    RAM + Queue(→ DB) 에 채움. 이 갭보정이 끝나면 해당 종목은 바로 매수 체크 가능.

정리: 봉 모을 때까지 기다리지 않고, 확정봉이 메모리에 들어오는 즉시 매매 로직에 쓰이고, DB는 비동기로 쌓인다.