21 KiB
É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.pypour utiliserget_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 deget_full_race_name()dans l'APIdashboard.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") etrace_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ésultatsdashboard.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) etcanalturf_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):
cote_directe- La cote est le predictor le plus importantrang_cote- Classement par coteimplied_prob- Probabilité implicite (1/cote)ratio_cote_field- Ratio cote vs moyenne du fieldtx_victoire- Taux de victoire historiqueforme_recente- Forme récente du cheval
Fichiers générés:
xgboost_models.pkl- Modèles entraînésfeature_importance_top1.csvfeature_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_obtenudans 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
performancetable - Créer script
backtest.pyqui compare prédictions ML vs réels - Calculer ROI par type de pari (simple gagnant, place, couplé)
- Automatiser le remplissage des résultats dans
- 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.pypour 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
weathern'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 distancemodel_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
jockeysetentraineurs - 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
# 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
-
NLP sur les commentaires:
- Sentiment: POSITIF / NEUTRE / NEGATIF
- Mots-clés: формы,腿部, qualité, etc.
- Score basé sur le texte
-
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
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
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
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 recommendationsupdate_recommendation_results.py- Met à jour les résultats des paris
API endpoints:
/api/backtest- Lit depuisbet_resultsetstats_by_type/api/stats- Lit depuisdaily_stats
5. Commandes Utiles
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éepmu_courses- informations des courses
9.2 Récupération automatique
Le script fetch_results.py récupère les résultats:
- Via
pmu_results.pyqui 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:
# 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
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
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
# 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
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