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