거래 빠르게 안티에서 병신만든거 커서로

feat: Implement backtest source management and enhance candle data handling

Changes:
- Introduced a new function `_apply_backtest_source_env_from_request` to manage the environment variables for candle, tick, and order book sources based on incoming requests.
- Added a teardown function `_teardown_backtest_source_env` to ensure that environment variables do not persist between requests, enhancing the stability of the backtesting environment.
- Refactored existing code to utilize the new source management functions, improving code readability and maintainability.
- Added new utility functions in `bt_candle_source.py` for fetching and managing candle data, ensuring consistency with live trading data sources.

Impact:
- These changes improve the flexibility and reliability of the backtesting framework, allowing for better management of data sources and reducing the risk of cross-request contamination.
This commit is contained in:
Your Name
2026-08-13 16:03:40 +09:00
parent c6bd62a25f
commit 2c7ad867f4
53 changed files with 15251 additions and 637 deletions

View File

@@ -86,6 +86,7 @@ def prepend_momentum_candle_warmup(
ps = str(period_start_key)[:12]
ind_cols = ws_candles_select_indicator_cols(db)
total_prepended = 0
from kis_trader.backtest.bt_candle_source import fetch_ws_candles_warmup_before
for code, rows in list(candles_by_code.items()):
if not rows:
continue
@@ -102,15 +103,13 @@ def prepend_momentum_candle_warmup(
first_ct = str(rows[first_period_idx].get("candle_time") or "")
if not first_ct:
continue
warm_rows = db.conn.execute(
f"SELECT candle_time, open, high, low, close, volume, is_confirmed{ind_cols} "
"FROM ws_candles WHERE timeframe=1 AND code=%s "
"AND candle_time < %s ORDER BY candle_time DESC LIMIT %s",
[code, first_ct, wb],
).fetchall()
warm_rows = fetch_ws_candles_warmup_before(
db, code, 1, first_ct, wb,
extra_select=ind_cols,
)
if not warm_rows:
continue
prefix = [dict(r) for r in reversed(warm_rows)]
prefix = warm_rows
candles_by_code[code] = prefix + [dict(r) for r in rows]
total_prepended += len(prefix)
if total_prepended > 0:
@@ -403,44 +402,27 @@ def load_momentum_candles_by_code(
"""
market: None/빈값 = 전체(기존 동작), 'US'|'KR' = ws_candles.market 필터.
"""
from kis_trader.backtest.bt_candle_source import (
fetch_ws_candles_for_code,
list_ws_candle_codes,
)
period_start = str(start_key)[:12]
mk = (market or "").strip().upper()
if mk:
codes_raw = db.conn.execute(
"SELECT DISTINCT code FROM ws_candles WHERE timeframe=1 AND market=%s "
"AND candle_time >= %s AND candle_time <= %s ORDER BY code",
[mk, start_key, end_key],
).fetchall()
else:
codes_raw = db.conn.execute(
"SELECT DISTINCT code FROM ws_candles WHERE timeframe=1 "
"AND candle_time >= %s AND candle_time <= %s ORDER BY code",
[start_key, end_key],
).fetchall()
codes = [r["code"] for r in codes_raw]
codes = list_ws_candle_codes(db, 1, start_key, end_key, market=mk or None)
ind_cols = ws_candles_select_indicator_cols(db)
candles_by_code: Dict[str, List[Dict]] = {}
total = 0
for code in codes:
if mk:
rows = db.conn.execute(
f"SELECT candle_time, open, high, low, close, volume, is_confirmed{ind_cols} "
"FROM ws_candles WHERE timeframe=1 AND code=%s AND market=%s "
"AND candle_time >= %s AND candle_time <= %s "
"ORDER BY candle_time ASC",
[code, mk, start_key, end_key],
).fetchall()
else:
rows = db.conn.execute(
f"SELECT candle_time, open, high, low, close, volume, is_confirmed{ind_cols} "
"FROM ws_candles WHERE timeframe=1 AND code=%s "
"AND candle_time >= %s AND candle_time <= %s "
"ORDER BY candle_time ASC",
[code, start_key, end_key],
).fetchall()
rows = fetch_ws_candles_for_code(
db, code, 1, start_key, end_key,
extra_select=ind_cols,
market=mk or None,
confirmed_only=False,
)
if len(rows) < 6:
continue
candles_by_code[code] = [dict(r) for r in rows]
candles_by_code[code] = rows
total += len(rows)
prepend_momentum_candle_warmup(
db, candles_by_code, period_start, warmup_bars=warmup_bars,