Fix backtest benchmark read after optional table probe
This commit is contained in:
1 parent
9846977d00
commit
9c48eb20c5
2 files changed
+32
-3
No files matched your search
@@ -937,13 +937,16 @@ async def _load_research_rank_only_symbols(db: AsyncSession) -> set[str]:
|
|||||||
"""Symbols that feed signal IC only (no GTL/candidate replay).
|
"""Symbols that feed signal IC only (no GTL/candidate replay).
|
||||||
|
|
||||||
Optional side table ``research_rank_only`` on research snapshots. Missing
|
Optional side table ``research_rank_only`` on research snapshots. Missing
|
||||||
table → empty set (production path unchanged).
|
table → empty set (production path unchanged). Probe within a savepoint:
|
||||||
|
PostgreSQL aborts the current transaction after a missing-table error, so
|
||||||
|
catching that error alone would break the subsequent benchmark read.
|
||||||
"""
|
"""
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = await db.execute(text("SELECT symbol FROM research_rank_only"))
|
async with db.begin_nested():
|
||||||
return {str(row[0]).upper() for row in result.fetchall() if row[0]}
|
result = await db.execute(text("SELECT symbol FROM research_rank_only"))
|
||||||
|
return {str(row[0]).upper() for row in result.fetchall() if row[0]}
|
||||||
except Exception:
|
except Exception:
|
||||||
return set()
|
return set()
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ from types import SimpleNamespace
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from app.models.benchmark_price import BenchmarkPrice
|
||||||
from app.models.ohlcv import OHLCVRecord
|
from app.models.ohlcv import OHLCVRecord
|
||||||
from app.models.ticker import Ticker
|
from app.models.ticker import Ticker
|
||||||
from app.services import backtest_service as bt
|
from app.services import backtest_service as bt
|
||||||
|
from app.services.benchmark_service import load_benchmark_closes
|
||||||
from app.services.outcome_service import (
|
from app.services.outcome_service import (
|
||||||
OUTCOME_EXPIRED,
|
OUTCOME_EXPIRED,
|
||||||
OUTCOME_STOP_HIT,
|
OUTCOME_STOP_HIT,
|
||||||
@@ -1600,6 +1602,30 @@ def _pin_benchmark(monkeypatch, closes: dict | None = None) -> None:
|
|||||||
monkeypatch.setattr(bt, "_load_benchmark_closes_for_backtest", _stub)
|
monkeypatch.setattr(bt, "_load_benchmark_closes_for_backtest", _stub)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_missing_research_table_does_not_abort_benchmark_read(session, monkeypatch):
|
||||||
|
"""The optional research table is absent online; its failed probe must be
|
||||||
|
isolated so PostgreSQL can still read the SPY prices in the same session.
|
||||||
|
"""
|
||||||
|
close_date = date(2025, 1, 2)
|
||||||
|
session.add(BenchmarkPrice(symbol="SPY", date=close_date, close=470.0))
|
||||||
|
await session.commit()
|
||||||
|
|
||||||
|
real_execute = session.execute
|
||||||
|
probed_in_savepoint = False
|
||||||
|
|
||||||
|
async def track_probe(statement, *args, **kwargs):
|
||||||
|
nonlocal probed_in_savepoint
|
||||||
|
if str(statement) == "SELECT symbol FROM research_rank_only":
|
||||||
|
probed_in_savepoint = session.in_nested_transaction()
|
||||||
|
return await real_execute(statement, *args, **kwargs)
|
||||||
|
|
||||||
|
monkeypatch.setattr(session, "execute", track_probe)
|
||||||
|
|
||||||
|
assert await bt._load_research_rank_only_symbols(session) == set()
|
||||||
|
assert probed_in_savepoint
|
||||||
|
assert await load_benchmark_closes(session) == {close_date: 470.0}
|
||||||
|
|
||||||
|
|
||||||
async def _seed_oscillating_ticker(session, symbol: str, n: int = 160) -> None:
|
async def _seed_oscillating_ticker(session, symbol: str, n: int = 160) -> None:
|
||||||
t = Ticker(symbol=symbol)
|
t = Ticker(symbol=symbol)
|
||||||
session.add(t)
|
session.add(t)
|
||||||
|
|||||||
Reference in new issue
Block a user