Tests whether a PROSPECTIVE forecaster (owner or local LLM) carries signal the machine levers never found. Picks land premarket via dashboard panel or research/llm_picker.py (Ollama); research/pick_scoring.py judges them under a pre-registered bar (n>=40, >=30 sessions, mean >=+0.5%/pick net, median>0, both halves positive). Picks after 9:30 ET stored but flagged invalid. Shadow-only: human_picks is never read by the live loop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
56 lines
1.9 KiB
Python
56 lines
1.9 KiB
Python
"""Pick journal + scorer: the smallest checks that fail if the logic breaks."""
|
|
from datetime import datetime, timedelta
|
|
from zoneinfo import ZoneInfo
|
|
|
|
import pytest
|
|
|
|
from research.pick_journal import add_pick, ensure_schema, list_picks
|
|
from research.pick_scoring import score_pick
|
|
from storage.db_pg import get_connection
|
|
|
|
ET_ = ZoneInfo("America/New_York")
|
|
|
|
|
|
@pytest.fixture()
|
|
def con():
|
|
c = get_connection(":memory:")
|
|
yield c
|
|
c.close()
|
|
|
|
|
|
def test_pick_validity_locks_at_open(con):
|
|
early = datetime(2026, 8, 20, 9, 29, tzinfo=ET_)
|
|
late = datetime(2026, 8, 20, 9, 31, tzinfo=ET_)
|
|
assert add_pick(con, "aapl", now=early)["valid"] is True
|
|
assert add_pick(con, "TSLA", now=late)["valid"] is False
|
|
picks = list_picks(con, early.date())
|
|
assert [p["symbol"] for p in picks] == ["AAPL", "TSLA"]
|
|
assert [p["valid"] for p in picks] == [True, False]
|
|
|
|
|
|
def test_pick_rejects_garbage(con):
|
|
with pytest.raises(ValueError):
|
|
add_pick(con, "")
|
|
with pytest.raises(ValueError):
|
|
add_pick(con, "TOOLONGG")
|
|
with pytest.raises(ValueError):
|
|
add_pick(con, "AAPL", direction="sideways")
|
|
|
|
|
|
def test_score_pick_long_and_short(con):
|
|
ensure_schema(con)
|
|
d = datetime(2026, 8, 20).date()
|
|
base = datetime(2026, 8, 20, 9, 30)
|
|
for i, (o, c) in enumerate([(10.0, 10.2), (10.2, 10.5), (10.5, 11.0)]):
|
|
con.execute(
|
|
"INSERT INTO minute_bars (symbol, timestamp, session_date, is_premarket, "
|
|
"is_regular_hours, is_afterhours, open, high, low, close, volume) "
|
|
"VALUES (?, ?, ?, false, true, false, ?, ?, ?, ?, 1000)",
|
|
["TEST", base + timedelta(minutes=i), d, o, max(o, c), min(o, c), c])
|
|
s = score_pick(con, "TEST", d, "long")
|
|
# entry 10.0 open, exit 11.0 close: raw +10%, minus 2% cost (>=$3)
|
|
assert abs(s["net"] - 0.08) < 1e-9
|
|
s2 = score_pick(con, "TEST", d, "short")
|
|
assert abs(s2["net"] - (-0.12)) < 1e-9
|
|
assert score_pick(con, "NOPE", d, "long") is None
|