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

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

@@ -1704,6 +1704,13 @@ class BreakoutStrategy(BaseStrategy):
return 0.0
def check_buy(self, code: str, name: str) -> Optional[Dict]:
_cb = self._cb_prof_start(code)
try:
return self._check_buy_impl(code, name, _cb)
finally:
self._cb_prof_finish(_cb)
def _check_buy_impl(self, code: str, name: str, _cb) -> Optional[Dict]:
# 골든타임 가드 (_candidate_filter 가 미리 거른 뒤에도 방어용 재검사)
if not self._is_golden_time():
return None
@@ -1712,6 +1719,7 @@ class BreakoutStrategy(BaseStrategy):
if self.use_ema_filter and not self.skip_hts_scan_dupes:
need_n = max(need_n, self.ema_slow_period + 5)
confirmed = self.ws.get_candles(code, self.candle_tf, n=need_n + 5)
self._cb_prof_mark(_cb, "candles")
if len(confirmed) < need_n - 1:
# force 연타 금지 — 시세불가·특수코드는 fail_max 후에도 REST 폭주
force_sec = max(30, get_env_int("BREAKOUT_CANDLE_GAP_FORCE_SEC", 120))
@@ -1726,6 +1734,7 @@ class BreakoutStrategy(BaseStrategy):
self.ws.fill_gap([code], force=do_force)
except Exception:
pass
self._cb_prof_mark(_cb, "fill_gap")
log_sec = max(15, get_env_int("BREAKOUT_CANDLE_SHORT_LOG_SEC", 60))
if not hasattr(self, "_candle_short_log_ts"):
self._candle_short_log_ts = {}
@@ -1820,6 +1829,7 @@ class BreakoutStrategy(BaseStrategy):
forming_close=curr_price,
),
)
self._cb_prof_mark(_cb, "engine")
if reason:
self.logger.info("🔍 [%s] %s(%s) %s", reason, name, code, msg or "")
return None
@@ -1830,6 +1840,7 @@ class BreakoutStrategy(BaseStrategy):
curr_price = float(signal.get("entry_price") or curr_price)
else:
reason, msg, signal = check_buy_signal_breakout_live(confirmed, params)
self._cb_prof_mark(_cb, "engine")
if reason:
self.logger.info("🔍 [%s] %s(%s) %s", reason, name, code, msg or "")
return None
@@ -1842,6 +1853,7 @@ class BreakoutStrategy(BaseStrategy):
_defer = self._defer_mid_enroll_entry(
code, _ebk, int(self.candle_tf or 1), params,
)
self._cb_prof_mark(_cb, "mid_enroll")
if _defer:
self.logger.info("🔍 [%s] %s(%s)", _defer, name, code)
return None
@@ -1859,6 +1871,7 @@ class BreakoutStrategy(BaseStrategy):
p = self._live_current_price(code)
if p > 0:
curr_price = p
self._cb_prof_mark(_cb, "align")
if curr_price <= 0:
if get_env_bool("SCAN_REJECT_LOG_VERBOSE", False):
if not hasattr(self, "_no_price_log"):
@@ -1888,6 +1901,7 @@ class BreakoutStrategy(BaseStrategy):
name, code, curr_price, invest_cap,
)
return None
self._cb_prof_mark(_cb, "qty")
stop_price = curr_price * (1 + self.stop_loss_pct)
target_price = curr_price * (1 + self.take_profit_pct)