File size: 2,163 Bytes
e23172f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
"""End-to-end demo using mock FormFav data (no API key required).

Drives the real pipeline: discover meetings -> fetch race forms -> normalise ->
analyse -> report -> backtest, all against local mock payloads. This proves the
full code path works without live network access.
"""
from __future__ import annotations

import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))

from trifecta_bro.data.normalizer import normalise_race  # noqa: E402
from trifecta_bro.model.analyse_race import analyse_race  # noqa: E402
from trifecta_bro.model.scoring import load_weights  # noqa: E402
from trifecta_bro.reporting.dashboard import write_outputs  # noqa: E402
from trifecta_bro.evaluation.backtester import Backtester  # noqa: E402
from tests.mock_formfav import (  # noqa: E402
    race_form_full, race_form_with_scratch_and_missing, race_form_abandoned, meetings_payload)

DATE = "2026-08-11"


def main() -> None:
    weights = load_weights()
    forms = [
        race_form_full(DATE, "dubbo", 1),
        race_form_abandoned(DATE, "dubbo", 2),  # abandoned -> skip
        race_form_with_scratch_and_missing(DATE, "randwick", 7),
    ]
    analyses = []
    for form in forms:
        race = normalise_race(form)
        if form.get("abandoned"):
            analyses.append({"track": race.track, "race_number": race.race_number,
                             "skippable": True, "reason": "race abandoned"})
            continue
        analyses.append(analyse_race(race, weights=weights))

    json_path, md_path = write_outputs(DATE, analyses, "1.0.0", "2026-08-10T16:00:00Z")
    print("WROTE:", json_path)
    print("WROTE:", md_path)

    # backtest against provided actuals (no leakage: model never sees these)
    races = [normalise_race(f) for f in forms if not f.get("abandoned")]
    bt = Backtester(weights=weights)
    metrics = bt.evaluate(races, {("dubbo", 1): [3, 1, 2], ("randwick", 7): [8, 2, 4]})
    print("\nBACKTEST METRICS:")
    for k, v in metrics.items():
        if k != "records":
            print(f"  {k}: {v}")
    return json_path, md_path


if __name__ == "__main__":
    main()