Files
turf_saas/EVOLUTION_PREDICTIF.md
2026-04-25 17:18:43 +02:00

695 lines
21 KiB
Markdown

# É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*