chore: 작업 중 발생한 부수적 변경 사항 및 누락된 파일 전체 커밋
- 프론트엔드 UI 업데이트 (backtest.html, backtest.js) 엔진 라디오 버튼 통합 관련 반영 - Rust 플러그인(kis_rust_core) 및 컴파일 소스코드 추가 - CLI 백테스트 스크립트 수정 및 최신화 - 기타 스크래치 테스트 스크립트, 로그 요약 마크다운(.md) 등 누락 파일 일괄 반영 - 추가적으로 아직 발견되지 않은 엣지 케이스나 렌더링 오류가 포함되어 있을 가능성이 있음
This commit is contained in:
@@ -202,7 +202,7 @@ def _ingest_tick_rows(
|
||||
return n
|
||||
|
||||
|
||||
def load_breakout_ticks_by_code(
|
||||
def load_common_ticks_by_code(
|
||||
db,
|
||||
start_key: str,
|
||||
end_key: str,
|
||||
@@ -250,21 +250,63 @@ def load_breakout_ticks_by_code(
|
||||
len(codes) if codes else "ALL",
|
||||
)
|
||||
|
||||
for chunk_s, chunk_e in chunks:
|
||||
max_w = min(10, len(chunks)) if chunks else 1
|
||||
max_w = get_env_int("WS_TICK_LOAD_MAX_WORKERS", max_w)
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
def process_chunk(chunk_s_val, chunk_e_val):
|
||||
day_str = chunk_s_val[:8]
|
||||
pq_path = f"/home/hoon/kis_bot/data/ticks/{mkt}/{day_str}.parquet"
|
||||
|
||||
_local_out = defaultdict(dict)
|
||||
_n = 0
|
||||
|
||||
try:
|
||||
rows = _fetch_ws_ticks_day_rows(table, mkt, chunk_s, chunk_e, codes)
|
||||
n = _ingest_tick_rows(rows, out)
|
||||
total += n
|
||||
logger.info(
|
||||
"✅ %s day=%s rows=%s (누적=%s)",
|
||||
table, chunk_s[:8], n, total,
|
||||
)
|
||||
import os
|
||||
import time
|
||||
if os.environ.get("BACKTEST_USE_RUST") == "1" and os.path.exists(pq_path):
|
||||
import kis_rust_core
|
||||
_st = time.time()
|
||||
|
||||
codes_list = list(codes) if codes else None
|
||||
tick_source = os.environ.get("TICK_SOURCE", "").strip() or None
|
||||
|
||||
res = kis_rust_core.load_parquet_ticks_fast(
|
||||
pq_path, chunk_s_val, chunk_e_val, codes_list, tick_source
|
||||
)
|
||||
|
||||
_local_out.update(res["data"])
|
||||
_n = res["count"]
|
||||
|
||||
_et = time.time()
|
||||
logger.info(f"⚡ [Rust Parquet 초고속 로드] day={day_str} rows={_n} (Rust I/O + PyDict: {_et - _st:.3f}s)")
|
||||
return chunk_s_val, chunk_e_val, _local_out, _n
|
||||
except Exception as e:
|
||||
failed_days += 1
|
||||
logger.warning(
|
||||
"%s day=%s 조회 실패 — 해당일 스킵: %s",
|
||||
table, chunk_s[:8], e,
|
||||
)
|
||||
logger.warning(f"Parquet Rust 로드 실패, DB로 폴백 (day={day_str}): {e}")
|
||||
|
||||
try:
|
||||
_rows = _fetch_ws_ticks_day_rows(table, mkt, chunk_s_val, chunk_e_val, codes)
|
||||
_n = _ingest_tick_rows(_rows, _local_out)
|
||||
except Exception as e:
|
||||
logger.warning(f"DB 로드 폴백 실패 (day={day_str}): {e}")
|
||||
|
||||
return chunk_s_val, chunk_e_val, _local_out, _n
|
||||
|
||||
with ThreadPoolExecutor(max_workers=max_w) as executor:
|
||||
futures = {executor.submit(process_chunk, c[0], c[1]): c for c in chunks}
|
||||
for future in as_completed(futures):
|
||||
c_s, c_e = futures[future]
|
||||
try:
|
||||
chunk_s, chunk_e, local_out, n = future.result()
|
||||
for _code, mins_dict in local_out.items():
|
||||
code_bucket = out[_code]
|
||||
for min_k, ticks in mins_dict.items():
|
||||
code_bucket.setdefault(min_k, []).extend(ticks)
|
||||
total += n
|
||||
logger.info("✅ %s day=%s rows=%s (누적=%s)", table, chunk_s[:8], n, total)
|
||||
except Exception as e:
|
||||
failed_days += 1
|
||||
logger.warning("%s day=%s 조회 실패 — 해당일 스킵: %s", table, c_s[:8], e)
|
||||
|
||||
if total <= 0:
|
||||
# ws_ticks 비어도 LS 3차만으로 재생 가능 (1·2차 공백일)
|
||||
@@ -592,7 +634,7 @@ def build_tick_coverage_meta_for_day(
|
||||
})
|
||||
if not candles_by_code:
|
||||
return {"tick_codes_traded": len(codes_clean), "tick_bars_total": 0}
|
||||
ticks_by_code, tick_rows = load_breakout_ticks_by_code(
|
||||
ticks_by_code, tick_rows = load_common_ticks_by_code(
|
||||
db, start_key, end_key, set(candles_by_code.keys()),
|
||||
)
|
||||
meta = tick_coverage_stats(dict(candles_by_code), ticks_by_code, bar_tf_min=tf)
|
||||
|
||||
Reference in New Issue
Block a user