The Audit
Marking the homework, nightly, in a fixed order
Four jobs run in the first half hour after every restart, and the order they run in is the architecture. Reconciliation must precede the tournament; the tournament must precede calibration; calibration must precede the weight update. Each depends on what the one before it wrote.
reconciliation_service · strategy_tournament
calibration_tracker · backtest_engine
Nightly, then weekly
A prediction is a claim until something checks it. The reconciliation job is what converts claims into evidence, and everything else in this section is downstream of that conversion. It selects prediction-log rows that are approximately one, five, or twenty days old — with a twelve-hour tolerance either side — that carry an entry price and do not yet have a return recorded for that horizon. The null check on the return column is the idempotency guard: a row already filled is never selected again.
The return is the simplest possible expression: current price minus entry price, over entry price. Direction correctness is scored only for the one-day horizon, by comparing the predicted direction against the sign of the realised return.
Two mechanical caveats follow from the implementation and should be stated. All three horizons read the same live quote rather than a historical close at the correct as-of date; the five- and twenty-day figures are “return from entry to today” for a row that happens to be that old, which is correct only because the row was selected by age and only if the job actually ran that day. And if the job misses a day, that horizon's twelve-hour window never matches again, so the column stays null permanently.
The job also computes rolling hit rates over seven, thirty and ninety days. These are pooled across all strategies and written only to the log. Nothing persists them, and nothing reads them.
What happens next is the interesting part. Fifteen minutes later, the tournament pairs every two predictions made about the same symbol on the same day by different strategies, decides which was better, and updates both Elo ratings. Five minutes after that, the calibration tracker rebuilds each strategy's reliability curve. Five minutes after that, the compositor recomputes its source weights.
None of these three write anything the next boot will read. The tournament writes ratings to a table, which survives; the calibration tracker writes nothing at all and recomputes from scratch on every call; and the weight update writes a history row that is never loaded, so the weights themselves reset to their defaults on restart.
A prediction is a claim until something checks it. One nightly job does the converting, and everything else here is downstream of it.
On reconciliation as the root of the feedback loop