Add local backtest snapshot runner
This commit is contained in:
@@ -791,6 +791,23 @@ def _backtest_worker_count() -> int:
|
||||
return max(1, min(configured, cpu - 1))
|
||||
|
||||
|
||||
def _offline_snapshot_mode() -> bool:
|
||||
return os.getenv("BACKTEST_SNAPSHOT_OFFLINE", "").strip().lower() in {"1", "true", "yes", "on"}
|
||||
|
||||
|
||||
async def _load_benchmark_closes_for_backtest(
|
||||
db: AsyncSession, *, days: int | None = None, refresh: bool = True
|
||||
) -> dict[date, float]:
|
||||
from app.services.benchmark_service import load_benchmark_closes, refresh_benchmark_prices
|
||||
|
||||
if refresh and not _offline_snapshot_mode():
|
||||
if days is None:
|
||||
await refresh_benchmark_prices(db)
|
||||
else:
|
||||
await refresh_benchmark_prices(db, days=days)
|
||||
return await load_benchmark_closes(db)
|
||||
|
||||
|
||||
def _mp_context():
|
||||
"""A start method safe to use from the threaded asyncio server: ``forkserver``
|
||||
(workers forked from a clean, single-threaded server — avoids the
|
||||
@@ -800,6 +817,12 @@ def _mp_context():
|
||||
for method in ("forkserver", "fork"):
|
||||
if method in methods:
|
||||
return multiprocessing.get_context(method)
|
||||
if (
|
||||
_offline_snapshot_mode()
|
||||
and os.getenv("BACKTEST_ALLOW_SPAWN", "").strip().lower() in {"1", "true", "yes", "on"}
|
||||
and "spawn" in methods
|
||||
):
|
||||
return multiprocessing.get_context("spawn")
|
||||
return None
|
||||
|
||||
|
||||
@@ -1568,10 +1591,9 @@ async def run_backtest(
|
||||
# emitted and the rest of the report remains valid.
|
||||
benchmark_closes: dict[date, float] = {}
|
||||
try:
|
||||
from app.services.benchmark_service import load_benchmark_closes, refresh_benchmark_prices
|
||||
|
||||
await refresh_benchmark_prices(db, days=settings.ohlcv_history_days + 365)
|
||||
benchmark_closes = await load_benchmark_closes(db)
|
||||
benchmark_closes = await _load_benchmark_closes_for_backtest(
|
||||
db, days=settings.ohlcv_history_days + 365
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("Benchmark load for residual momentum failed")
|
||||
|
||||
@@ -1693,16 +1715,13 @@ async def run_backtest(
|
||||
|
||||
spy_closes: dict | None = None
|
||||
try:
|
||||
from app.services.benchmark_service import (
|
||||
load_benchmark_closes,
|
||||
refresh_benchmark_prices,
|
||||
)
|
||||
|
||||
oldest = min((cols[0][0] for cols in price_columns.values()), default=None)
|
||||
if oldest is not None:
|
||||
days_needed = None
|
||||
if oldest is not None and not _offline_snapshot_mode():
|
||||
days_needed = (date.today() - date.fromordinal(oldest)).days + 30
|
||||
await refresh_benchmark_prices(db, days=days_needed)
|
||||
spy_closes = await load_benchmark_closes(db)
|
||||
spy_closes = await _load_benchmark_closes_for_backtest(
|
||||
db, days=days_needed, refresh=oldest is not None
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("Benchmark load for the portfolio sim failed")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user