Live PMU horse-racing odds (French tracks plus foreign tracks PMU takes bets on) for races still open to betting, with 19 source-side filters (country, racecourse, discipline, distance, going, odds...). Flags implied-probability steamers and drifters between runs.
0.3.0 — Full source filters + race context columns (23/09/2026)
Added
Filter at source — 19 optional filters, applied before max_races, so
excluded races are never fetched nor billed: countries, meetings
(partial, accent-insensitive — LONGCHAMP matches PARISLONGCHAMP),
disciplines, categories (HANDICAP matches every handicap variant),
surfaces, going, age_conditions, sex_conditions, track_directions,
min/max_distance_m, min/max_prize_eur, min/max_runners,
start_after/start_before (+ filter_timezone), and horse-level
min/max_odds. Measured live: French flat only = 171 rows instead of 398.
Race context on every row: discipline (already read from PMU but
dropped before output), category, distance_m, prize_eur, runners,
surface, going, age_condition, sex_condition, track_direction.
Same filter engine as World Turf Pulse — a filter set works in both.
Requested by a user in the Issues tab — thanks, Achirama.
0.2.8 — Relative movement rule (09/09/2026)
Added
Outsider steamers are now caught. The signal used to fire only on an
absolute move of movement_threshold_pct implied-probability points, which
is blind to the classic outsider steam: 50/1 → 20/1 is only +3 points but
+150 %. A second rule now fires when the implied probability moves by at
least movement_relative_pct (default 30 %) of its previous value; moves
on 200/1+ shots are ignored as noise. Signal rows carry trigger
(absolute | relative) and relative_change_pct. Set
movement_relative_pct: 0 to keep the old behaviour.
0.2.7 — Cold review (09/09/2026)
Fixed
A false steamer/drifter on the first run of every day. The run-over-run
history was keyed on hippodrome + race + horse number, which is the same
every day (Vincennes R1C1 #4 exists on every racing day) — so the first
morning run compared today's horse against last night's different horse
and fired a signal (measured: +45 pts). History is now dated on the PMU
calendar day and ignored across midnight.
The steamer was the row max_results cut. Rows were emitted snapshot
first, so with the default cap (15) a run with one genuine steamer
delivered 15 snapshots and no signal. Signals and form patterns now come
first, snapshots after.
A race whose PMU call failed lost its odds history for the next run —
exactly when it was about to start. Horses not seen this run are carried
forward within the day.
earnings_swing fired "-100 %" on every horse with no earnings yet this
year (most of them early in the season). Both years must now be non-zero.
PMU's programme date is the French calendar day, not the container's
UTC day (they differ between midnight and 2 am Paris time).
Changed
History storage format is versioned ({"schema": 2, "date": ..., "probs": {...}});
a pre-upgrade history is treated as stale for one run.
0.2.1 — 2026-08-28
Reliability hardening — every run now returns a result.
PMU has long dead windows (overnight, between meetings) with no races open
for betting, and on a quiet run nothing moves. Previously the Actor pushed
nothing in those cases, which made the run look like a failure. It now
returns a single status row with a clear message so every scheduled run
comes back clean.
Input parsing hardened (max_races, movement_threshold_pct): a bad or
null value now falls back to the default instead of crashing the run.
Reads and writes of the run-history key-value store, and signal
evaluation, are now each isolated — a storage hiccup can no longer fail a
run, especially the post-delivery history write.
0.1.x / 0.2.0 — 2026-07 → 2026-08
Live PMU (France) horse-racing odds movement: steamers & drifters between
runs, optional hidden form patterns (debutant, winless streak, jockey
change, earnings swing).