fix: fetch today's in-progress bar; name weekday crons

Two independent bugs left the near-close scan running on the previous
session's close, silently degrading live execution to the stale_close
floor (~1.57 Sharpe) instead of the intended ~1.77 close-fill case.

1. OHLCV window never covered the current day. Daily bars are stamped at
   session start (04:00Z under EDT), so an end of midnight-on-end_date
   landed before that day's bar and dropped it. Widening the window alone
   fails the whole request with 'subscription does not permit querying
   recent SIP data', so end is also clamped to now-20min. Today's bar is
   now returned, roughly 20 minutes behind live -- within the staleness
   the near-close design already assumed.

   Intraday runs therefore store a partial bar and ingestion progress
   reaches today, which made incremental resume skip the after-close
   refresh entirely. collect_ohlcv_final() re-pulls the last sessions so
   the consolidated bar overwrites the partial one before outcome eval.

2. APScheduler's from_crontab() passes day-of-week to its own field where
   0=Monday, so '1-5' meant Tue-Sat: every Monday was skipped and the
   scanner ran Saturdays on stale data. Weekday schedules now use names.
   Stored settings already corrected via Admin; this fixes the defaults.

Tests cover both: today's bar inside the window, the delayed-data clamp,
historical windows untruncated, and a week of fire times asserting Monday
is present and weekends are not.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 21:10:35 +02:00
co-authored by Claude Fable 5
parent bb8aa655a1
commit 1fa3d70dec
4 changed files with 213 additions and 14 deletions
+49
View File
@@ -32,6 +32,55 @@ class TestValidateCron:
validate_cron("0 7 * * *", "Mars/Phobos")
class TestTradingDayCrons:
"""APScheduler's from_crontab() uses 0=Monday, so numeric "1-5" means
TueSat: it skips every Monday and fires on Saturdays. Weekday schedules
must therefore be spelled with day *names*.
"""
_WEEKDAY_KEYS = (
"schedule_near_close_pipeline_cron",
"schedule_after_close_pipeline_cron",
"schedule_intraday_pipeline_cron",
)
@pytest.mark.parametrize("key", _WEEKDAY_KEYS)
def test_fires_monday_and_never_saturday(self, key: str):
from datetime import datetime, timedelta
from apscheduler.triggers.cron import CronTrigger
trigger = CronTrigger.from_crontab(
SCHEDULE_DEFAULTS[key], timezone=SCHEDULE_DEFAULTS["schedule_timezone"]
)
# Walk a full week of fire times from a known Sunday.
cursor = datetime(2026, 7, 19, tzinfo=trigger.timezone)
weekdays = set()
previous = None
for _ in range(12):
fire = trigger.get_next_fire_time(previous, cursor)
weekdays.add(fire.strftime("%a"))
previous = fire
cursor = fire + timedelta(seconds=1)
assert "Mon" in weekdays, f"{key} skips Mondays — numeric day-of-week?"
assert {"Sat", "Sun"}.isdisjoint(weekdays), f"{key} fires on a weekend"
def test_fundamentals_runs_on_monday(self):
from datetime import datetime
from apscheduler.triggers.cron import CronTrigger
trigger = CronTrigger.from_crontab(
SCHEDULE_DEFAULTS["schedule_fundamentals_cron"],
timezone=SCHEDULE_DEFAULTS["schedule_timezone"],
)
fire = trigger.get_next_fire_time(
None, datetime(2026, 7, 19, tzinfo=trigger.timezone)
)
assert fire.strftime("%a") == "Mon"
class TestScheduleConfig:
async def test_defaults_when_unset(self, session: AsyncSession):
config = await get_schedule_config(session)