옵투나 오류수정정
This commit is contained in:
@@ -194,9 +194,9 @@ def inject_momentum_rest_warmup_memory(
|
||||
"""
|
||||
DB 전일봉이 없을 때 키움 ka10080 REST를 종목당 호출해 **메모리에만** prepend.
|
||||
|
||||
- 1차: MOMENTUM_BACKTEST_REST_WARMUP_BARS (기본 700)
|
||||
- 전일 종가 미확보 시에만 2차: MOMENTUM_BACKTEST_REST_WARMUP_BARS_RETRY (기본 1500)
|
||||
- DB INSERT 없음. 성공 prefix·영구실패는 프로세스 캐시 (Optuna trial 재조회·로그 스팸 방지).
|
||||
- 사다리 최대 4단(실패 종목만 다음 단): BARS → RETRY → BARS_3 → BARS_4
|
||||
- 성공 prefix: 프로세스 RAM + `bt_rest_warmup_cache` (다른 PC 공유)
|
||||
- 실패는 DB 미저장(재시도 가능). 프로세스 영구실패는 동일 런 내 재호출 방지.
|
||||
"""
|
||||
from kis_trader.utils.env import get_env_bool, get_env_float, get_env_int
|
||||
from kis_trader.utils.logger import get_logger
|
||||
@@ -213,6 +213,7 @@ def inject_momentum_rest_warmup_memory(
|
||||
if len(ps) < 8 or not candles_by_code:
|
||||
return stats
|
||||
period_day = ps[:8]
|
||||
use_db_cache = get_env_bool("MOMENTUM_BACKTEST_REST_WARMUP_DB_CACHE", True)
|
||||
|
||||
target: Set[str]
|
||||
if universe_by_slot:
|
||||
@@ -238,15 +239,17 @@ def inject_momentum_rest_warmup_memory(
|
||||
if max_codes > 0:
|
||||
need_codes = need_codes[:max_codes]
|
||||
|
||||
n_bars = max(
|
||||
50,
|
||||
int(get_env_int("MOMENTUM_BACKTEST_REST_WARMUP_BARS", 700)),
|
||||
)
|
||||
# 전일(직전 세션) 종가가 1차에 안 잡힐 때만 — 평소엔 700만
|
||||
n_retry = max(
|
||||
n_bars,
|
||||
int(get_env_int("MOMENTUM_BACKTEST_REST_WARMUP_BARS_RETRY", 1500)),
|
||||
)
|
||||
n1 = max(50, int(get_env_int("MOMENTUM_BACKTEST_REST_WARMUP_BARS", 700)))
|
||||
n2 = max(n1, int(get_env_int("MOMENTUM_BACKTEST_REST_WARMUP_BARS_RETRY", 1500)))
|
||||
n3 = max(n2, int(get_env_int("MOMENTUM_BACKTEST_REST_WARMUP_BARS_3", 2500)))
|
||||
n4 = max(n3, int(get_env_int("MOMENTUM_BACKTEST_REST_WARMUP_BARS_4", 4000)))
|
||||
ladder: List[int] = []
|
||||
seen_n: Set[int] = set()
|
||||
for n in (n1, n2, n3, n4):
|
||||
if n not in seen_n:
|
||||
seen_n.add(n)
|
||||
ladder.append(n)
|
||||
ladder = ladder[:4]
|
||||
sleep_sec = float(get_env_float("MOMENTUM_BACKTEST_REST_SLEEP_SEC", 0.25))
|
||||
kw_key, kw_secret, is_mock = _kiwoom_gap_credentials()
|
||||
if not kw_key or not kw_secret:
|
||||
@@ -256,15 +259,14 @@ def inject_momentum_rest_warmup_memory(
|
||||
|
||||
from kis_trader.ws.kis_ws import get_kiwoom_candles_df
|
||||
|
||||
# 전부 캐시 hit면 Optuna trial 경로에서 INFO 스팸 금지
|
||||
will_fetch = any(
|
||||
(c, period_day) not in _REST_WARMUP_PREFIX_CACHE for c in need_codes
|
||||
)
|
||||
if will_fetch:
|
||||
log.info(
|
||||
"📡 모멘텀 REST 웜업(메모리): 전일봉 부족 %d종목 · ka10080 n=%d"
|
||||
" (실패 시 n=%d 1회 재시도, DB 미기록)",
|
||||
len(need_codes), n_bars, n_retry,
|
||||
"📡 모멘텀 REST 웜업(메모리): 전일봉 부족 %d종목 · 사다리 n=%s"
|
||||
" (실패 시만 다음 단, DB캐시=%s)",
|
||||
len(need_codes), ladder, "ON" if use_db_cache else "OFF",
|
||||
)
|
||||
|
||||
for i, code in enumerate(need_codes):
|
||||
@@ -274,58 +276,70 @@ def inject_momentum_rest_warmup_memory(
|
||||
stats["fail"] += 1
|
||||
continue
|
||||
cache_key = (code, period_day)
|
||||
prefix: List[Dict[str, Any]] = []
|
||||
|
||||
cached = _REST_WARMUP_PREFIX_CACHE.get(cache_key)
|
||||
did_network = False
|
||||
if cached is not None:
|
||||
stats["cache_hit"] += 1
|
||||
prefix = [dict(r) for r in cached]
|
||||
else:
|
||||
did_network = True
|
||||
elif use_db_cache:
|
||||
try:
|
||||
df = get_kiwoom_candles_df(
|
||||
code, 1, kw_key, kw_secret, is_mock=is_mock, n=n_bars,
|
||||
)
|
||||
except Exception as e:
|
||||
log.warning("⚠️ REST 웜업 실패 %s: %s", code, e)
|
||||
_REST_WARMUP_PERM_FAIL.add(cache_key)
|
||||
stats["fail"] += 1
|
||||
continue
|
||||
if df is None or getattr(df, "empty", True):
|
||||
_REST_WARMUP_PERM_FAIL.add(cache_key)
|
||||
stats["fail"] += 1
|
||||
continue
|
||||
try:
|
||||
prefix = _rest_df_to_prefix(df, rows, ps)
|
||||
except Exception as e:
|
||||
log.warning("⚠️ REST 웜업 파싱 실패 %s: %s", code, e)
|
||||
_REST_WARMUP_PERM_FAIL.add(cache_key)
|
||||
stats["fail"] += 1
|
||||
continue
|
||||
from kis_trader.backtest.bt_rest_warmup_cache import load_rest_warmup_prefix
|
||||
hit = load_rest_warmup_prefix(code, period_day=period_day, market="KR")
|
||||
except Exception:
|
||||
hit = None
|
||||
if hit:
|
||||
db_rows, _n_used = hit
|
||||
prefix = [dict(r) for r in db_rows]
|
||||
_REST_WARMUP_PREFIX_CACHE[cache_key] = [dict(r) for r in prefix]
|
||||
stats["cache_hit"] += 1
|
||||
|
||||
# 1차로 전일 종가 미확보 → 봉 수 늘려 1회만 재시도 (중간 거래일 0봉 등)
|
||||
if (not prefix or not _momentum_rows_have_prev_day(prefix, period_day)) and n_retry > n_bars:
|
||||
stats["retry"] += 1
|
||||
log.info(
|
||||
"📡 REST 웜업 재시도 %s: n=%d → n=%d (전일 종가 미확보)",
|
||||
code, n_bars, n_retry,
|
||||
)
|
||||
if not prefix:
|
||||
for tier_i, n_try in enumerate(ladder):
|
||||
if tier_i > 0:
|
||||
stats["retry"] += 1
|
||||
log.info(
|
||||
"📡 REST 웜업 재시도 %s: n=%d → n=%d (전일 종가 미확보 · %d/%d단)",
|
||||
code, ladder[tier_i - 1], n_try, tier_i + 1, len(ladder),
|
||||
)
|
||||
try:
|
||||
df2 = get_kiwoom_candles_df(
|
||||
code, 1, kw_key, kw_secret, is_mock=is_mock, n=n_retry,
|
||||
df = get_kiwoom_candles_df(
|
||||
code, 1, kw_key, kw_secret, is_mock=is_mock, n=int(n_try),
|
||||
)
|
||||
except Exception as e:
|
||||
log.warning("⚠️ REST 웜업 재시도 실패 %s: %s", code, e)
|
||||
df2 = None
|
||||
if df2 is not None and not getattr(df2, "empty", True):
|
||||
try:
|
||||
prefix = _rest_df_to_prefix(df2, rows, ps)
|
||||
except Exception as e:
|
||||
log.warning("⚠️ REST 웜업 재시도 파싱 실패 %s: %s", code, e)
|
||||
prefix = []
|
||||
|
||||
_REST_WARMUP_PREFIX_CACHE[cache_key] = [dict(r) for r in prefix]
|
||||
if sleep_sec > 0 and did_network and i + 1 < len(need_codes):
|
||||
time.sleep(sleep_sec)
|
||||
log.warning("⚠️ REST 웜업 실패 %s n=%s: %s", code, n_try, e)
|
||||
df = None
|
||||
if sleep_sec > 0 and i + 1 < len(need_codes):
|
||||
time.sleep(sleep_sec)
|
||||
if df is None or getattr(df, "empty", True):
|
||||
continue
|
||||
try:
|
||||
prefix = _rest_df_to_prefix(df, rows, ps)
|
||||
except Exception as e:
|
||||
log.warning("⚠️ REST 웜업 파싱 실패 %s: %s", code, e)
|
||||
prefix = []
|
||||
if prefix and _momentum_rows_have_prev_day(prefix, period_day):
|
||||
_REST_WARMUP_PREFIX_CACHE[cache_key] = [dict(r) for r in prefix]
|
||||
if use_db_cache:
|
||||
try:
|
||||
from kis_trader.backtest.bt_rest_warmup_cache import (
|
||||
save_rest_warmup_prefix,
|
||||
)
|
||||
save_rest_warmup_prefix(
|
||||
code,
|
||||
period_day=period_day,
|
||||
market="KR",
|
||||
n_bars=int(n_try),
|
||||
prefix_rows=prefix,
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
break
|
||||
else:
|
||||
# 사다리 전부 실패
|
||||
_REST_WARMUP_PERM_FAIL.add(cache_key)
|
||||
stats["fail"] += 1
|
||||
continue
|
||||
|
||||
if not prefix or not _momentum_rows_have_prev_day(prefix, period_day):
|
||||
_REST_WARMUP_PERM_FAIL.add(cache_key)
|
||||
@@ -335,7 +349,7 @@ def inject_momentum_rest_warmup_memory(
|
||||
stats["ok"] += 1
|
||||
stats["bars"] += len(prefix)
|
||||
|
||||
if will_fetch:
|
||||
if will_fetch or stats["cache_hit"] > 0:
|
||||
log.info(
|
||||
"✅ 모멘텀 REST 웜업 완료: ok=%d fail=%d cache=%d retry=%d bars=%d",
|
||||
stats["ok"], stats["fail"], stats["cache_hit"], stats["retry"], stats["bars"],
|
||||
|
||||
Reference in New Issue
Block a user