3.5 KiB
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 (매매 두뇌)
WebSocket 틱 →on_tick()→ RAM에서만 OHLCV 갱신 →
매수/매도 판단은get_candles()/get_latest_confirmed()등 메모리만 사용 (DB 대기 없음). - 트랙 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는 비동기로 쌓인다.