Aller au contenu

Correction du fallback CSV silencieux — Restauration de la fiabilité des données

Billet #139 : Repli CSV silencieux causant des prix portefeuille figés
Type : Débogage / Correction / Intégrité des données
Composants concernés : code_source_simule/pipeline.py, tests/test_pipeline.py, base de données (table historique)


1. Contexte et Symptômes

Les prix du portefeuille dans l'interface sont restés figés à leurs valeurs CSV initiales pendant plus de 5 jours consécutifs (23–27 mars 2026), malgré la disponibilité de données marché en direct. Par exemple, la cad_value de VWAGY est restée à 14.85 CAD sur toutes les dates observées.


2. Processus d'Investigation

Une requête de base de données a confirmé les valeurs figées :

SELECT ticker, date_releve, valeur, cad_value FROM historique 
  WHERE ticker_id = (SELECT id FROM titres WHERE ticker = 'VWAGY') 
  ORDER BY date_releve DESC LIMIT 5;
Résultat : valeur = 10.61 USD et cad_value = 14.85 CAD identiques du 23 au 27 mars.

Corrélation mathématique : Le CSV contient VWAGY Price = 10.61 USD. Avec usd_to_cad_rate = 1.40 dans config.ini, on obtient 10.61 × 1.40 = 14.854 CAD, exactement la valeur figée observée.

Disponibilité API : Un test manuel Marketstack sur la même période a confirmé que les données existaient (ex. close = 10.08 pour le 27 mars 2026). Le problème n'était donc pas l'absence de données API, mais leur non-acheminement en base.

Cause opérationnelle : Le cron tourne à 05:03 UTC (au lieu de 21:05 UTC). À cette heure, les données EOD du jour ne sont généralement pas encore publiées, donc l'API peut répondre {"data": []}. Le pipeline substituait alors silencieusement ces absences par les prix CSV.


3. Causes Racines Identifiées

# Cause Impact Statut
1 Cron décalé de 16 h (05:03 UTC vs 21:05 UTC) Données EOD indisponibles au moment du run Hors scope code — correction VPS requise
2 Repli CSV silencieux dans enrich_data_with_marketstack() Remplace des prix API manquants par CSV sans signalement Corrigé
3 Absence d'alerte opérateur Incident invisible côté exploitation Corrigé — alerte courriel ajoutée

4. Solutions Implantées

4.1 - Suppression du repli CSV

Retrait de la logique qui remplaçait silencieusement les prix API manquants par les prix CSV :

# AVANT (bug)
df['market_price'].fillna(df['price'], inplace=True)

# APRÈS (corrigé)
# Pas de repli — les absences API restent NaN

df['market_price'] = df['marketstack_ticker'].map(all_prices)
missing = df[df['market_price'].isna()]['marketstack_ticker'].dropna().tolist()
if missing:
    print(f"AVERTISSEMENT: {len(missing)} ticker(s) sans prix API...")

4.2 - Ajout d'une alerte courriel

Implémentation de send_alert_email() pour notifier l'opérateur quand des tickers n'ont pas de prix API. Configuration .env requise : - SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASSWORD - ALERT_EMAIL_TO

Si SMTP n'est pas configuré, un avertissement explicite est journalisé.

4.3 - Blocage d'insertion en cas de prix manquant

Mise à jour de insert_data() pour ignorer tout ticker sans prix API valide :

market_price = row.get('market_price')
if pd.isna(market_price):
    continue  # Pas d'insertion

4.4 - Verrouillage par test de non-régression

Ajout du test test_pipeline_does_not_fallback_to_csv_when_api_key_exists (tc-pipe-nocsv01) : - Given : CSV avec prix + clé API + API vide - Then : aucune insertion dans historique - Statut : test passant ✓


5. Nettoyage des Données

Purge de l'historique à partir du 20 janvier 2026 pour éliminer les enregistrements produits sous logique défectueuse :

DELETE FROM historique WHERE date_releve >= '2026-01-20';

Résultat : 11 977 lignes supprimées
Justification : ces lignes contiennent des prix CSV injectés à la place de prix marché.


6. Vérification et Résultat

  • Tests locaux : 11/11 passent (incluant tc-pipe-nocsv01).
  • Cohérence données : disponibilité API confirmée manuellement ; insertion corrigée validée.
  • Prévention du repli : comportement verrouillé par test automatique.

7. Synchronisation de la Documentation (EN/FR)

Dans la clôture de ce correctif, la documentation a été relue et synchronisée dans les deux langues : - Alignement de la logique temporelle avec le comportement réellement exécuté. - Mise à jour de la description pipeline (absence de repli CSV, contournement des prix API manquants, chemin d'alerte opérateur). - Mise à jour des recommandations cron (exécution post-clôture). - Mise à jour de la documentation tests (ajout tc-pipe-nocsv01 + liens vers le rapport d'activité).


8. Dépendances et Prochaines Étapes

Immédiat (action VPS manuelle) :

  • Corriger le cron : 03 05 * * 1-505 21 * * 1-5
  • Configurer les variables SMTP dans .env pour l'alerte courriel

Suite :

  • Revoir la logique d'import (date cible, fréquence) via Speckit
  • Définir un seuil de complétude (ex. alerte si <95% des tickers ont un prix API)