# Évolution du Système Prédictif Turf ## Historique des modifications - 25 Mars 2026 (suite) ### 25 Mars 2026 - Correction du titre du banner ✅ **Problème**: Le banner de la course affichait uniquement "🏇 MARSEILLE Quinté+" au lieu du nom complet de la course. **Solution**: - Modification de `combined_api.py` pour utiliser `get_full_race_name()` qui retourne le format complet: "R1 BORELY - 13:55 GRAND NATIONAL DU TROT" - Mise à jour du dashboard pour afficher le nom complet dans le banner - Ajustement CSS pour permettre l'affichage du nom complet sans troncature - Ajout du favicon avec le logo H3R7Tech **Résultat**: Le banner affiche maintenant "R1 BORELY - 13:55 GRAND NATIONAL DU TROT" avec le type de course "🏇 Quinté+" **Fichiers modifiés**: - `combined_api.py` - Utilisation de `get_full_race_name()` dans l'API - `dashboard.html` - Affichage du nom complet dans le banner ### 25 Mars 2026 - Résultats groupés par course ✅ **Problème**: L'onglet Résultats affichait les positions 1-5 pour chaque course sans séparation, ce qui était incohérent. **Solution**: - Modification de l'API pour inclure `race_label` (ex: "R1 BORELY") et `race_type` (ex: "GRAND NATIONAL DU TROT") dans les résultats - Mise à jour du dashboard pour grouper les résultats par course et afficher un en-tête pour chaque course **Résultat**: Les résultats affichent maintenant chaque course séparément: - R1 BORELY - GRAND NATIONAL DU TROT - R2 CAEN - PRIX D'ACQUEVILLE **Fichiers modifiés**: - `combined_api.py` - Ajout des infos de course dans les résultats - `dashboard.html` - Groupement et affichage par course --- ## Historique des modifications - 25 Mars 2026 --- ## 1. Analyse de la Base de Données ### Tables principales et volumes | Table | Lignes | Description | |-------|--------|-------------| | `historical_data` | 5 536 | Données historiques des courses | | `pmu_courses` | 3 146 | Courses PMU | | `pmu_reunions` | 480 | Réunions hippiques | | `predictions` | 739 | Prédictions effectuées | | `scoring` | 123 | Scores calculés par cheval | | `results` | 68 | Résultats des courses | | `performance` | 96 | Performance prédictions vs réels | | `recommendations` | 32 | Recommandations de paris | | `weather` | 4 | Données météo | ### Métriques de performance (avant ML) | Métrique | Valeur | |----------|--------| | Taux de réussite global | 20.83% | | Précision favori (rang 1) | 42.86% | | Précision top 3 | 50% | | Résultats remplis (recos) | 0/32 | --- ## 2. Améliorations Effectuées ### 2.1 Court Terme ✅ #### ✅ Script de mise à jour des résultats - **Fichier**: `update_recommendation_results.py` - **Fonction**: Compare les recommandations avec les résultats réels - **Résultat**: 20 recommandations mises à jour (6 GAGNE, 14 PERDU) - **Taux de réussite**: 30% #### ✅ Analyse du rang 0 - **Cause**: `canalturf_partants` (356 prédictions) et `canalturf_selections` (165) ont rank 0 par défaut - **Solution**: Seuls les ranks 1/2/3 constituent les vraies prédictions ### 2.2 Moyen Terme ✅ #### ✅ Entraînement XGBoost - **Fichier**: `train_xgboost.py` - **Données**: 4 902 lignes de `historical_data` - **Features**: 35 features (cote, forme, performances, etc.) | Modèle | CV AUC | Amélioration vs random | |--------|--------|----------------------| | Top 1 (gagnant) | **0.697** | +19.7% | | Top 3 (placé) | **0.715** | +21.5% | **Top Features (par importance):** 1. `cote_directe` - La cote est le predictor le plus important 2. `rang_cote` - Classement par cote 3. `implied_prob` - Probabilité implicite (1/cote) 4. `ratio_cote_field` - Ratio cote vs moyenne du field 5. `tx_victoire` - Taux de victoire historique 6. `forme_recente` - Forme récente du cheval **Fichiers générés:** - `xgboost_models.pkl` - Modèles entraînés - `feature_importance_top1.csv` - `feature_importance_top3.csv` ### 2.3 Intégration Dashboard ✅ #### ✅ Nouvel onglet "Prédictions ML" - **Fichier**: `dashboard.html` - **Endpoint**: `/turf/api/ml_predictions` - **Données affichées**: - Probabilité Top 1 (%) - Probabilité Top 3 (%) - Score ML composite - Conseil (TOP1 / TOP3 / PASS) #### ✅ Intégration vitesse - **Fichier**: `combined_api.py` - **Endpoint**: `/turf/api/vitesse` - **Calcul**: Moyenne du `temps_obtenu` dans historical_data - **Affichage**: Format mm:ss avec nombre de courses --- ## 3. Architecture Actuelle ``` ┌─────────────────────────────────────────────────────────┐ │ PORTAL DUCKDNS │ │ https://portal-kolifee.duckdns.org │ │ (Auth: h3r7 / ****) │ └─────────────────────┬───────────────────────────────────┘ │ ┌─────────────┴─────────────┐ │ │ Port 8765 Port 9999 │ │ ┌───────▼────────┐ ┌───────▼────────┐ │ combined_api │ │ vitesse_api │ │ - /turf/api │ │ - /api/vitesse │ │ - ML预测 │ │ (obsolète) │ │ - Vitesse │ └──────────────────┘ │ - Scoring │ └───────────────┘ │ ▼ ┌───────────────────────────────────┐ │ turf.db │ │ - predictions │ │ - historical_data (4 902 lignes) │ │ - scoring │ │ - results │ │ - recommendations │ └───────────────────────────────────┘ ``` --- ## 4. Améliorations à Venir ### 4.1 Priorité Haute #### 🔴 Comparaison Prédictions vs Résultats Réels - **Problème**: Seulement 96 prédictions evaluées avec résultats - **Solution**: - Automatiser le remplissage des résultats dans `performance` table - Créer script `backtest.py` qui compare prédictions ML vs réels - Calculer ROI par type de pari (simple gagnant, place, couplé) - **Métriques à suivre**: - Précision par rang (base 1, chance 2, outsider 3) - ROI par type de pari - Evolution de la précision dans le temps #### 🔴 Ajouter plus de données historiques - **Problème**: 4 902 lignes, seulement 364 jours - **Solution**: Améliorer `improve_historical_data.py` pour charger plus de dates - **Objectif**: 20 000+ lignes pour meilleur entraînement - **API à utiliser**: PMU API (https://turfinfo.api.pmu.fr) #### 🔴 Intégration météo - **Problème**: Table `weather` n'a que 4 lignes - **Solution**: Scraping météo quotidien + impact sur prédictions - **Impact**: Ajustement selon conditions (pluie, vent, température) - **Sources**: weather.com, openweathermap.org #### 🔴 Système de "Value Bets" - **Problème**: Pas de comparaison cote PMU vs cote "juste" - **Solution**: Estimer cote juste avec le modèle ML, parier si valeur > seuil - **Formule**: `value = (cote_PMU - cote_juste) / cote_juste` - **Seuil**: Parier si value > 10% ### 4.2 Priorité Moyenne #### 🟡 Scraping de Sources Hippiques Externes - **Problèmes identifiés**: - Canalturf: prédictions basiques - Pas d'avis externes intégrés - **Sources à scraper**: - **Equidia**: Pronostics experts, commentaires - **Paris-Turf**: Analyses courses, tiércé - **Zeturf**: Pronostics communautaire - **LeTrot**: Spécifique trot attelé - **Données à récupérer**: - Avis des experts (auteur, confiance, commentaire) - Cotes de référence (moyenne de plusieurs sources) - Statistiques jockeys/entraineurs #### 🟡 Backtest complet - **Problème**: Seulement 96 prédictions evaluées - **Solution**: Automatiser le backtest sur toutes les recommandations - **Objectif**: ROI réel du modèle - **Métriques**: ``` - ROI = (gains - mises) / mises - Yield = gains_esperés / mises - Hit Rate = paris_gagnés / total_paris - CLV = Cote_Moyenne - Cote_Fermee ``` #### 🟡 Amélioration du scoring - **Problème**: Formule actuelle pondérée manuellement - **Solution**: Utiliser les weights XGBoost pour pondérer le scoring - **Impact**: Précisions bases: 42.86% → 50%+ #### 🟡 Modèles multi-cibles - **Solution**: Entraîner modèles séparés pour: - `model_quinte` - top5 (pour couplés, tiercé, quinté) - `model_turf` - Discipline spécifique (trot vs plat) - `model_distance` - Performance par catégorie de distance - `model_hippodrome` - Performance par hippodrome #### 🟡 Intégration des performances jockeys/entraineurs - **Données manquantes**: - Taux de victoire du jockey - Taux de réussite de l'entraineur - Combinaison cheval/jockey historique - **Solution**: Ajouter tables `jockeys` et `entraineurs` - **Impact**: +5-10% de précision ### 4.3 Priorité Basse #### 🟢 Interface admin - **Solution**: Page pour gérer les prédictions, voir stats - **Fonction**: - Activer/désactiver scrapers - Voir ROI en temps réel - Historique des prédictions - Configuration des seuils #### 🟢 Alertes Telegram/Discord - **Solution**: Notification quand prediction forte (prob > 50%) - **Impact**: Réactivité augmentée - **Format**: - Cheval recommandé - Cote actuelle - Probabilité ML - Mise suggérée #### 🟢 Dashboards analytiques - **Solution**: Graphiques d'évolution - **Métriques**: - Précision vs temps - ROI vs temps - Meilleurs/wpires chevaux - Meilleurs/wpires jockeys --- ## 5. Scraping de Sources Externes ### 5.1 Sites à Intégrer | Site | Données | Difficulté | Priorité | |------|---------|------------|----------| | Equidia | Pronostics experts | Moyenne | Haute | | Paris-Turf | Analyses courses | Moyenne | Haute | | LeTrot | Spécifique trot | Facile | Moyenne | | Zeturf | Pronostics communauté | Difficile | Basse | ### 5.2 Données à Récupérer ```python # Exemple de structure pour données externes external_data = { "source": "equidia", "horse_name": "...", "expert_name": "...", "expert_confidence": 0-100, "comment": "Texte de l'analyse", "cote_recommandee": 0.0, "date": "YYYY-MM-DD" } ``` ### 5.3 Intégration dans le modèle 1. **NLP sur les commentaires**: - Sentiment: POSITIF / NEUTRE / NEGATIF - Mots-clés: формы,腿部, qualité, etc. - Score basé sur le texte 2. **Fusion des sources**: ``` score_final = 0.4 * score_ML + 0.3 * score_Canalturf + 0.2 * score_Equidia + 0.1 * score_cote ``` --- ## 6. Métriques de Performance à Suivre ### 6.1 Métriques Quotidiennes | Métrique | Description | Cible | |----------|-------------|-------| | `precision_bases` | % bases correctes | > 45% | | `precision_chances` | % chances correctes | > 30% | | `precision_outsiders` | % outsiders corrects | > 15% | | `nb_predictions` | Nombre de prédictions | > 20 | ### 6.2 Métriques Hebdomadaires | Métrique | Description | Cible | |----------|-------------|-------| | `roi_simple_gagnant` | ROI paris gagnant | > 5% | | `roi_simple_place` | ROI paris placé | > 10% | | `avg_cote` | Cote moyenne recommandée | - | | `value_bets` | % de value bets trouvés | > 20% | ### 6.3 Métriques Mensuelles | Métrique | Description | Cible | |----------|-------------|-------| | `roi_global` | ROI global | > 10% | | `evolution` | Evolution vs mois précédent | positive | | `meilleur_cheval` | Cheval le plus profitable | - | | `pire_cheval` | Cheval le moins profitable | - | --- ## 7. Structure de Données Suggérée ### 7.1 Nouvelle Table: `expert_predictions` ```sql CREATE TABLE expert_predictions ( id INTEGER PRIMARY KEY, date TEXT NOT NULL, source TEXT NOT NULL, -- 'equidia', 'paris_turf', etc. expert_name TEXT, horse_name TEXT NOT NULL, horse_number INTEGER, race_name TEXT, confidence INTEGER, -- 0-100 sentiment TEXT, -- 'POSITIF', 'NEUTRE', 'NEGATIF' comment TEXT, recommended_odds REAL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` ### 7.2 Nouvelle Table: `backtest_results` ```sql CREATE TABLE backtest_results ( id INTEGER PRIMARY KEY, date TEXT NOT NULL, race_name TEXT, horse_name TEXT, type_pari TEXT, -- 'simple_gagnant', 'simple_place', 'couple' mise REAL, Cote REAL, Resultat TEXT, -- 'GAGNE', 'PERDU' Gain REAL, prob_predite REAL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` ### 7.3 Nouvelle Table: `jockeys` ```sql CREATE TABLE jockeys ( id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, total_races INTEGER, victories INTEGER, places INTEGER, taux_victoire REAL, taux_place REAL, last_updated TIMESTAMP ); ``` --- ## 8. Plan d'Action Détaillé ### Phase 1: Amélioration Données (Semaine 1-2) - [ ] Augmenter historical_data à 10 000+ lignes - [ ] Remplir quotidiennement les résultats - [ ] Créer script backtest automatique - [ ] Tableau de bord métriques ### Phase 2: Intégration Sources (Semaine 3-4) - [ ] Intégrer Equidia API/scraping - [ ] Ajouter analyse sentiment des commentaires - [ ] Fusionner scores multi-sources ### Phase 3: Optimisation ML (Semaine 5-6) - [ ] Réentraîner avec nouvelles features - [ ] Modèles par discipline - [ ] Système de value bets ### Phase 4: Production (Semaine 7-8) - [ ] Déploiement nouveau modèle - [ ] Alertes Telegram - [ ] Interface admin --- ## 4.4 Implémenté ✅ #### ✅ Tables de données analytiques (25 Mars 2026) **Tables créées dans `turf.db`:** | Table | Description | Colonnes clés | |-------|-------------|---------------| | `bet_results` | Historique des paris | date, race_name, type_pari, horse_name, cote, mise, resultat, gain | | `daily_stats` | Stats quotidiennes | date, total_bets, bets_gagne, mise_totale, gain_total, precision_pct, roi_pct | | `stats_by_type` | Stats par type de pari | date, type_pari, total_bets, gagne, mise, gain, roi | | `expert_predictions` | Prédictions externes | date, source, expert_name, horse_name, confidence, sentiment, comment | **Scripts:** - `populate_analytics.py` - Remplit les tables depuis recommendations - `update_recommendation_results.py` - Met à jour les résultats des paris **API endpoints:** - `/api/backtest` - Lit depuis `bet_results` et `stats_by_type` - `/api/stats` - Lit depuis `daily_stats` --- ## 5. Commandes Utiles ```bash cd /home/h3r7/turf_scraper # ===== DONNÉES & PRÉDICTIONS ===== # Mettre à jour les résultats des recommandations python3 update_recommendation_results.py # Réentraîner le modèle ML python3 train_xgboost.py # ===== ANALYTICS ===== # Remplir les tables analytiques (à exécuter après mise à jour résultats) python3 populate_analytics.py # ===== API ===== # Redémarrer l'API pkill -f combined_api python3 combined_api.py # Vérifier les logs tail -f /tmp/combined.log # ===== BASE DE DONNÉES ===== # Voir les tables analytiques sqlite3 turf.db "SELECT * FROM daily_stats LIMIT 5;" sqlite3 turf.db "SELECT * FROM bet_results LIMIT 5;" sqlite3 turf.db "SELECT * FROM stats_by_type;" # Statistiques globales sqlite3 turf.db "SELECT SUM(total_bets) as total, SUM(gain_total) as gains, SUM(mise_totale) as mises FROM daily_stats;" ``` --- ## 6. Fichiers Clés | Fichier | Description | |---------|-------------| | `combined_api.py` | API principale (port 8765) | | `dashboard.html` | Interface frontend avec onglets | | `train_xgboost.py` | Entraînement ML XGBoost | | `update_recommendation_results.py` | Mise à jour résultats paris | | `populate_analytics.py` | Remplit tables analytiques | | `backtest.py` | Script de calcul du backtest | | `fetch_results.py` | Récupération résultats 1h après course | | `xgboost_models.pkl` | Modèles ML entraînés | | `PREDICTION_MODEL_ANALYSIS.md` | Analyse détaillée du modèle | | `EVOLUTION_PREDICTIF.md` | Ce document | --- ## 9. Résultats Automatiques ### 9.1 Source des données Les résultats sont récupérés depuis l'API PMU (`pmu_results.py`) et stockés dans: - `pmu_partants` - données des partants avec ordre d'arrivée - `pmu_courses` - informations des courses ### 9.2 Récupération automatique Le script `fetch_results.py` récupère les résultats: - Via `pmu_results.py` qui interroge l'API PMU - 自动每小时 ou à 14h (après les courses) - Mode scheduler: `python fetch_results.py` - Mode unique: `python fetch_results.py --once` ### 9.3 Affichage dashboard L'API affiche automatiquement les résultats: ```python # Query: top 5 de chaque course française (course 1) SELECT pp.nom, pp.ordre_arrivee, pp.cote_direct FROM pmu_partants pp JOIN pmu_reunions pr ON ... WHERE pays_code='FRA' AND num_course=1 ``` --- ## 13. Stratégie de Paris ZE5 (Focus B4/B3) ### 13.1 Objectif Suite à l'analyse des rapports, le pari le plus rentable est le **ZE5 avec objectif B4/B3** (trouver 4 ou 5 premiers). ### 13.2 Stratégies recommandées | Stratégie | Description | Mise conseillée | Risque | |-----------|-------------|------------------|--------| | **ZE5 B4/B3** | Bases + Chances + 1 Outsider | 3€ | Moyen | | **ZE5 Conservateur** | Top Favori + 2 Chances | 3€ | Faible | | **ZE5 Audacieux** | Base + 2 Outsiders | 1€ | Élevé | ### 13.3 Logique - **B5** (5/5) : ZE5 Ordre/Désordre - Jackpot! - **B4** (4/5) : Rapport ~20-30€ pour 2€ (fréquent) - **B3** (3/5) : Rapport ~5-10€ pour 2€ (très fréquent) ### 13.4 Implémentation API ```python def generate_ze5_recommendations(conn, today): # Récupérer prédictions: Bases + Chances + Outsiders # Générer combos optimisés pour B4/B3 return { 'ze5_b4b3': {...}, 'ze5_conservateur': {...}, 'ze5_audacieux': {...} } ``` ### 13.5 Résultats du 25 Mars 2026 | Pari | Mise | Résultat | Gain | |------|------|----------|------| | ZE5 B4/B3 | 3€ | B3 (3/5) | 12€ | | ZE5 Conservateur | 3€ | B3 (3/5) | 12€ | | ZE5 Audacieux | 1€ | PERDU | 0€ | **ROI: +242.9%** 🎯 --- ## 14. Suivi des Performances ### 14.1 Données sauvegardées Les informations suivantes sont enregistrées dans la table `recommendations`: | Champ | Description | |--------|-------------| | `date` | Date de la course | | `race_name` | Nom de la course | | `type_pari` | Type de pari (simple_gagnant, ze5_b4b3, etc.) | | `cheval1` | Cheval(x) sélectionné(s) | | `numero1` | Numéro du cheval | | `cote` | Cote du pari | | `mise` | Mise en euros | | `gain_potentiel` | Gain potentiel estimé | | `confiance` | Niveau de confiance (FORTE, BONNE, etc.) | | `justification` | Explication du choix | | `resultat` | Résultat (GAGNE, PERDU, B3, B4, B5) | ### 14.2 Script de mise à jour Le script `update_recommendation_results.py`: - Récupère les résultats depuis `pmu_partants` - Évalue chaque pari (ZE5: compte les matches dans top 5) - Met à jour le champ `resultat` ### 14.3 Calcul du ROI ```sql SELECT SUM(mise) as total_mise, SUM(CASE WHEN resultat='GAGNE' THEN mise * Cote WHEN resultat='B3' THEN mise * 4 WHEN resultat='B4' THEN mise * 10 ELSE 0 END) as total_gain FROM recommendations WHERE date = '2026-03-25'; ``` --- ## 15. Règles de Sélection des Courses ### 15.1 Critères d'inclusion | Critère | Description | |---------|-------------| | **Pays** | France uniquement (FR) | | **Données suffisantes** | Minimum 10 partants | | **Type de course** | Quinté, Trot, Plat, Toutes | ### 15.2 Implémentation API ```python # Filtre France uniquement france_condition = """ EXISTS ( SELECT 1 FROM pmu_reunions r WHERE r.pays_code='FRA' AND r.date_programme=date AND (r.hippodrome_long LIKE '%' || race_hippodrome || '%' OR r.hippodrome_court LIKE '%' || race_hippodrome || '%' OR r.hippodrome_code LIKE '%' || race_hippodrome || '%') ) """ # Minimum 10 partants min_partants_condition = """ (SELECT COUNT(*) FROM predictions p2 WHERE p2.race_name=predictions.race_name AND p2.date=predictions.date AND p2.source='canalturf_partants') >= 10 """ ``` --- ## 12. Récupération des Résultats ### 12.1 Règle Les résultats sont récupérés **1 heure après l'heure de départ** de chaque course. ### 12.2 Données collectées | Donnée | Description | |--------|-------------| | Position | Rang du cheval à l'arrivée | | Cotes finales | Rapports PMU officiels | | Gains | Gains potentiels par type de pari | ### 12.3 Script fetch_results.py ```python import schedule import time from datetime import datetime, timedelta def fetch_daily_results(): """Récupère les résultats du jour à 14h (1h après dernière course)""" run_result_fetch() schedule.every().day.at("14:00").do(fetch_daily_results) while True: schedule.run_pending() time.sleep(60) ``` --- *Document généré le 25 Mars 2026*