# Note Intelligence — Système ML Prédictions dans turf_saas **Date de création** : 2026-04-30 **Auteur** : IngenieurDev (H3R7Tech) **Ticket de référence** : HRT-96 (sprint ML SaaS — HRT-90) **Scope** : `/home/h3r7/turf_saas/` — AUCUNE modification de `/home/h3r7/turf_scraper/` --- ## 1. Contexte & Décision architecturale ### 1.1 Deux systèmes, deux DB H3R7Tech exploite deux dépôts séparés : | Dépôt | Rôle | Base de données | |---|---|---| | `/home/h3r7/turf_scraper/` | Scraping PMU + entraînement XGBoost | `turf.db` | | `/home/h3r7/turf_saas/` | SaaS utilisateurs + API v1 + dashboard | `turf_saas.db` | ### 1.2 Décision de duplication (vs modification turf_scraper) **Choix : dupliquer les tables et scripts ML dans turf_saas.db, sans toucher à turf_scraper.** Justification : - `turf_scraper` est la source de vérité du scraping PMU et des modèles XGBoost — toute modification risque de casser la chaîne de collecte de données. - `turf_saas` doit fonctionner de manière autonome, avec ses propres utilisateurs, subscriptions et données. - La table `ml_predictions_cache` est *pré-peuplée* dans `turf_saas.db` par un processus de synchronisation (scheduler ou copie périodique depuis `turf.db`). - Le feedback loop (`ml_feedback_saas.py`) écrit dans `paris` de `turf_saas.db` uniquement. --- ## 2. Architecture du système ML dans turf_saas ### 2.1 Vue d'ensemble du flow ``` [turf_scraper/turf.db] └── ml_predictions_cache (XGBoost v1) │ │ [sync périodique / scheduler] ▼ [turf_saas/turf_saas.db] ├── ml_predictions_cache ← prédictions XGBoost importées ├── pmu_partants ← données courses PMU ├── pmu_rapports ← dividendes réels PMU ├── paris ← paris virtuels ML (ml_feedback_saas.py) │ └── API v1 ──┬── GET /api/v1/predictions/* (lecture ml_predictions_cache) ├── GET /api/v1/roi/by-model (jointure paris + rapports) ├── POST /api/v1/ml/feedback/run (déclenche ml_feedback_saas) └── GET /api/v1/ml/feedback/stats (stats par stratégie) │ ▼ [dashboard_saas.html] Section "Performance & ROI" Chart.js — ROI par modèle / évolution ``` ### 2.2 Table `ml_predictions_cache` (turf_saas.db) Table centrale du système ML. Contient les prédictions XGBoost pour chaque cheval/course. | Colonne | Type | Description | |---|---|---| | `date` | TEXT | Date de la course (YYYY-MM-DD) | | `num_reunion` | INTEGER | Numéro de réunion | | `num_course` | INTEGER | Numéro de course | | `horse_name` | TEXT | Nom du cheval | | `horse_number` | INTEGER | Numéro du cheval | | `odds` | REAL | Cote au moment de la prédiction | | `prob_top1` | REAL | Probabilité XGBoost de finir 1er | | `prob_top3` | REAL | Probabilité XGBoost de finir top 3 | | `ml_score` | REAL | Score ML composite (0–100) | | `recommendation` | TEXT | `top1` / `top3` / `value_bet` | | `is_value_bet` | INTEGER | 1 si value bet détecté | | `is_outlier` | INTEGER | 1 si outlier de cote | | `race_label` | TEXT | Ex: `R1C3` | | `model_version` | TEXT | Version du modèle (ex: `xgboost_v1`) | | `risque_label` | TEXT | Niveau de risque (`low`/`neutral`/`high`) | | `risque_score` | INTEGER | Score risque (0–100) | **Contrainte d'unicité** : `(date, num_reunion, num_course, horse_name)` — garantit l'idempotence des imports. **Volume actuel** : ~1 000 entrées (2 dates de courses). --- ## 3. Feedback Loop ML — `ml_feedback_saas.py` ### 3.1 Rôle Script Python autonome qui : 1. Lit les prédictions XGBoost dans `ml_predictions_cache` de `turf_saas.db` 2. Génère des paris virtuels selon 4 stratégies XGBoost 3. Insère les paris dans la table `paris` de `turf_saas.db` 4. Est **idempotent** : ne duplique pas les paris existants ### 3.2 Stratégies supportées | Stratégie | Type pari | Condition sélection | Mise | |---|---|---|---| | `xgboost_sg` | `simple_gagnant` | top 1 ML par course, `ml_score >= 70` | 1€ | | `xgboost_value` | `simple_gagnant` | `is_value_bet = 1` | 1€ | | `xgboost_sp` | `simple_place` | top 1 ML par course, `ml_score >= 50` | 1€ | | `xgboost_2sur4` | `deux_sur_quatre` | top 4 ML par course, 6 combos générés | 6€ (1€/combo) | ### 3.3 Schéma d'idempotence ```python # Vérifie avant insertion SELECT id FROM paris WHERE date_course = ? AND source_reco = ? # ex: 'xgboost_sg' AND type_pari = ? AND numero1 = ? AND race_label = ? ``` Si le pari existe déjà → skip (aucune duplication). ### 3.4 Table `paris` — colonnes clés pour le ML | Colonne | Valeur ML | |---|---| | `source_reco` | `xgboost_sg` / `xgboost_value` / `xgboost_sp` / `xgboost_2sur4` | | `model_source` | `xgboost_v1` (héritée de ml_predictions_cache) | | `type_pari` | `simple_gagnant` / `simple_place` / `deux_sur_quatre` | | `statut` | `EN_ATTENTE` → `GAGNE` / `PERDU` (mise à jour par update_paris_results.py) | | `gain` | Dividende réel × mise (depuis pmu_rapports) | ### 3.5 Usage CLI ```bash # Traitement du jour python3 ml_feedback_saas.py # Date spécifique python3 ml_feedback_saas.py --date 2026-04-29 # Backfill python3 ml_feedback_saas.py --backfill 2026-04-20 ``` **Différence avec `turf_scraper/ml_feedback.py`** : - `DB_PATH` = `/home/h3r7/turf_saas/turf_saas.db` (PAS `/home/h3r7/turf_scraper/turf.db`) - Logs dans `/home/h3r7/turf_saas/logs/` - AUCUNE référence à `turf_scraper` --- ## 4. API ROI — `/api/v1/roi/*` ### 4.1 Route principale **`GET /api/v1/roi/by-model`** — Calcul du ROI par modèle/stratégie Jointures SQL : ```sql -- paris ←→ pmu_partants (via race_label + date + numero) -- paris ←→ pmu_rapports (dividendes réels) SELECT p.source_reco AS model_source, COUNT(p.id) AS nb_paris, SUM(p.mise) AS mise_totale, SUM(p.gain) AS gain_total, (SUM(p.gain) - SUM(p.mise)) / SUM(p.mise) * 100 AS roi_pct, COUNT(CASE WHEN p.statut='GAGNE' THEN 1 END) * 100.0 / COUNT(p.id) AS win_rate FROM paris p WHERE p.date_course BETWEEN :start AND :end AND (:strategy IS NULL OR p.source_reco = :strategy) GROUP BY p.source_reco ``` **Paramètres query** : - `?strategy=xgboost_sg` — filtrer par stratégie (optionnel) - `?days=30` — fenêtre temporelle en jours (défaut : 30, max : 365) **Réponse JSON** : ```json { "period": {"start": "2026-04-01", "end": "2026-04-30", "days": 30}, "models": [ { "model_source": "xgboost_sg", "nb_paris": 42, "mise": 42.0, "gain": 51.3, "roi_pct": 22.1, "win_rate": 28.6 } ] } ``` **Accès plan** : - `free` : 1 stratégie max - `premium` : complet - `pro` : complet + historique illimité ### 4.2 Blueprint `api_v1/routes/roi.py` Enregistré dans `api_v1/__init__.py` avec : ```python from .routes.roi import roi_bp app.register_blueprint(roi_bp) ``` --- ## 5. API ML Feedback — `/api/v1/ml/feedback/*` ### 5.1 Routes | Méthode | Path | Auth | Description | |---|---|---|---| | `POST` | `/api/v1/ml/feedback/run` | Admin | Déclenche `ml_feedback_saas.py` manuellement | | `GET` | `/api/v1/ml/feedback/stats` | Premium+ | Stats paris par stratégie XGBoost | ### 5.2 `POST /api/v1/ml/feedback/run` - Réservé aux admins (token admin requis) - Déclenche le script `ml_feedback_saas.py` en subprocess - Corps optionnel : `{"date": "2026-04-29"}` ou `{"backfill": "2026-04-20"}` ### 5.3 `GET /api/v1/ml/feedback/stats` Retourne les statistiques agrégées par stratégie : ```json { "stats": [ { "source_reco": "xgboost_sg", "nb_paris": 42, "nb_gagnes": 12, "win_rate_pct": 28.6, "mise_totale": 42.0, "gain_total": 51.3, "roi_pct": 22.1 } ], "last_run": "2026-04-29T18:30:00" } ``` ### 5.4 Blueprint `api_v1/routes/ml_feedback.py` Enregistré dans `api_v1/__init__.py` avec : ```python from .routes.ml_feedback import ml_feedback_bp app.register_blueprint(ml_feedback_bp) ``` --- ## 6. Jointures de données — Schéma complet ``` ml_predictions_cache date, num_reunion, num_course, horse_name, horse_number ml_score, recommendation, is_value_bet race_label, model_version │ │ [ml_feedback_saas.py] ▼ paris date_course, race_label, numero1 source_reco (= stratégie XGBoost) model_source (= xgboost_v1) type_pari, mise, statut, gain │ ├──── JOIN pmu_partants ──── date_programme + num_reunion + num_course + num_pmu │ ordre_arrivee (résultat réel) │ └──── JOIN pmu_rapports ──── date_programme + num_reunion + num_course + type_pari dividende_euro (gain réel calculé) ``` --- ## 7. Dashboard SaaS — Section ROI Le dashboard `dashboard_saas.html` intègre une section **"Performance & ROI"** (implémentée dans HRT-94) : - Graphique ROI par `model_source` (histogramme Chart.js) - Évolution ROI dans le temps (line chart, 7j/30j/90j) - Tableau : `model_source | nb paris | mise | gain | ROI% | win_rate%` - Filtre dropdown par stratégie - Gating plan : Free = 1 stratégie, Premium/Pro = complet Appel API dashboard : ```javascript fetch('/api/v1/roi/by-model?days=30') ``` --- ## 8. Points d'attention & limites 1. **Données ML limitées** : actuellement 1 000 prédictions sur 2 dates (2026-04-24 et 2026-04-25). La pertinence du ROI augmentera avec le volume de données. 2. **Pas de paris XGBoost actifs** : la table `paris` contient des paris `manual`, `scoring_v2`, `canalturf` mais pas encore de paris `xgboost_*`. HRT-93 (ml_feedback_saas.py) doit être complété et exécuté. 3. **Modèle unique** : `model_version = 'xgboost_v1'`. L'évolution vers des versions de modèle multiples est prévue dans la roadmap. 4. **Sync turf_scraper → turf_saas** : le mécanisme de synchronisation de `ml_predictions_cache` n'est pas encore documenté formellement. À documenter dans une prochaine Note Intelligence. 5. **update_paris_results.py** : script de mise à jour des statuts paris (`EN_ATTENTE → GAGNE/PERDU`) à partir de `pmu_rapports` — dépendance critique pour le calcul du ROI réel. --- ## 9. Fichiers clés | Fichier | Rôle | |---|---| | `turf_saas.db` | Base de données principale SaaS | | `ml_feedback_saas.py` | Feedback loop ML (à créer — HRT-93) | | `api_v1/routes/roi.py` | Routes API ROI (à créer — HRT-92) | | `api_v1/routes/ml_feedback.py` | Routes API feedback (à créer — HRT-93) | | `api_v1/__init__.py` | Enregistrement des blueprints | | `dashboard_saas.html` | Dashboard SaaS avec section ROI | | `update_paris_results.py` | MAJ statuts paris depuis résultats PMU | | `scoring_v2.py` | Scoring engine (stratégie scoring_v2) | --- ## 10. Références tickets | Ticket | Description | Statut | |---|---|---| | HRT-90 | Orchestration ML SaaS (parent) | blocked | | HRT-92 | Backend: API ROI par modèle | in_progress | | HRT-93 | ML feedback loop ml_feedback_saas | in_progress | | HRT-94 | Frontend: Dashboard ROI | in_progress | | HRT-95 | QA: Tests end-to-end ML + ROI | in_progress | | HRT-96 | Note Intelligence ML + documentation (ce ticket) | in_progress |