← Retour aux articles
March 20, 2026
5 min de lecture

LLM Alpha Mining : comment extraire des signaux de trading des earnings calls et des documents financiers

LLM Alpha Mining : comment extraire des signaux de trading des earnings calls et des documents financiers
#llm
#alpha
#earnings
#nlp
#gpt
#financial-analysis
#algo-trading
🤖
Part 5 of 5 · Collection
AI Agents for Trading

Il y a une blague à Wall Street : « L'information la plus précieuse dans un earnings call n'est pas ce que le PDG a dit, mais comment il l'a dit. » Quand Tim Cook déclare « nous sommes prudemment optimistes » au lieu du « nous sommes très satisfaits » de l'année précédente — ce n'est pas un jeu de langage, c'est un signal qui vaut des centaines de millions de dollars.

Depuis des décennies, les fonds quantitatifs tentent de systématiser l'extraction de ces signaux. D'abord, ils comptaient la fréquence des mots « positifs » et « négatifs » à l'aide de dictionnaires. Puis ils ont déployé BERT. Et maintenant nous avons GPT-4o, Claude et des LLM open source capables d'analyser les subtilités de la langue de bois corporative avec une précision qui effraie même les chercheurs eux-mêmes.

Voyons comment construire un pipeline complet pour extraire des signaux de trading à partir des earnings calls — de l'obtention de la transcription jusqu'au backtesting des rendements anormaux cumulés.

Pourquoi les earnings calls sont une mine d'or pour l'alpha

Post-Earnings Announcement Drift : l'anomalie qui refuse de mourir

En 1968, Ball et Brown ont découvert quelque chose d'étrange : après la publication des résultats trimestriels, les actions continuent de dériver dans la direction de la « surprise » pendant encore 60 à 90 jours. Ils ont appelé cela le Post-Earnings Announcement Drift (PEAD). Plus d'un demi-siècle s'est écoulé depuis, des centaines d'articles ont été écrits, l'anomalie a été expliquée sous une dizaine d'angles différents — et elle fonctionne toujours.

Le PEAD est l'une des anomalies de marché les plus persistantes de l'histoire de la finance. Une stratégie de portefeuille « acheter la surprise positive, vendre la surprise négative » a historiquement généré un rendement excédentaire annuel de 10 à 25 %. Pourquoi le marché n'a-t-il pas arbitré cela ? Plusieurs raisons :

  • Attention limitée des investisseurs — quand 200 entreprises publient leurs résultats la même semaine, il est physiquement impossible de lire toutes les transcriptions
  • Complexité cognitive — un earnings call dure 45 à 60 minutes, et le signal clé peut être enfoui dans une seule phrase à la 38e minute de la session de questions-réponses
  • Ambiguïté du langage — le CFO dit « nous naviguons à travers des vents contraires », et sans contexte, on ne sait pas s'il s'agit d'un avertissement discret ou d'une couverture standard

C'est ici qu'entrent en scène les LLM. Pour la première fois, nous disposons d'un outil capable de traiter 500 transcriptions en une soirée tout en captant des nuances que même des analystes expérimentés manqueraient.

PEAD.txt : le texte compte plus que les chiffres

Des chercheurs de la Federal Reserve Bank of Philadelphia (Meursault, Liang, Routledge, Scanlon) ont publié l'article PEAD.txt, qui a bouleversé les hypothèses sur la valeur de l'information textuelle. Ils ont construit un analogue textuel de la surprise de résultats standard — SUE.txt — qui n'utilise pas du tout la valeur numérique des résultats.

Le résultat ? SUE.txt génère un drift deux fois plus important que le PEAD classique. De plus : ces dernières années, alors que le PEAD classique basé sur les surprises numériques a pratiquement disparu (le marché a appris), le drift textuel reste significatif. Le marché a appris à traiter les chiffres rapidement, mais peine encore avec l'interprétation du texte.

C'est l'argument fondamental en faveur d'une approche NLP pour les earnings calls.

Du sentiment à la sémantique : évolution des approches

From sentiment to semantics

Première génération : bag-of-words et dictionnaires (2000-2015)

Tout a commencé avec le dictionnaire Loughran-McDonald (2011) — une liste de mots étiquetés comme « positifs », « négatifs », « incertains » et « litigieux ». L'idée était élégante dans sa simplicité : compter le pourcentage de mots négatifs dans un dépôt 10-K et trader là-dessus.

Le problème ? Le mot « outstanding » dans un contexte financier signifie le plus souvent « dette impayée » plutôt que « résultat excellent ». Le mot « risque » dans Risk Management n'est pas un signal négatif — c'est une description de processus. Les dictionnaires de sentiment NLP standards ont eu des performances embarrassantes sur les textes financiers.

Loughran et McDonald ont créé un dictionnaire spécialisé, ce qui a amélioré la situation, mais le problème fondamental demeurait : le bag-of-words ne comprend pas le contexte. « Nous n'avons pas manqué de répondre aux attentes » — il y a ici deux mots « négatifs », mais le sens est positif.

Deuxième génération : FinBERT et les transformers (2019-2023)

En 2019, Dogu Araci a publié FinBERT — un BERT affiné sur des textes financiers de Reuters TRC2. Les résultats étaient impressionnants : une amélioration de 14 points de pourcentage sur le jeu de données Financial PhraseBank par rapport à l'état de l'art. FinBERT comprenait le contexte : « outstanding » à côté de « debt » — négatif, à côté de « performance » — positif.

Mais FinBERT avait une limite : une fenêtre de contexte de 512 tokens. Un earnings call fait 8 000 à 12 000 mots. Découper en chunks et faire la moyenne du sentiment signifie perdre la sémantique entre les paragraphes. Le PDG pourrait commencer avec optimisme, puis mentionner négligemment des problèmes de chaîne d'approvisionnement pendant les questions-réponses. FinBERT analyse chaque chunk indépendamment et manque ce contraste.

Troisième génération : les LLM à long contexte (2023-aujourd'hui)

GPT-4, Claude, Gemini avec des fenêtres de contexte de 128K à 1M de tokens ont changé les règles du jeu. On peut désormais charger une transcription entière en une seule fois et poser des questions qui nécessitent la compréhension du document dans son ensemble.

L'étude clé — Lopez-Lira & Tang (2023) « Can ChatGPT Forecast Stock Price Movements? » Sur plus de 50 000 titres, GPT-4 a affiché un taux de réussite d'environ 90 % dans la prédiction de la direction de la réaction initiale du marché et a prédit de manière significative le drift ultérieur, en particulier pour les petites capitalisations et les actualités négatives. Les modèles antérieurs (GPT-1, GPT-2, BERT) n'ont pas montré cette capacité — le pouvoir prédictif émerge comme une propriété émergente des grands modèles.

BloombergGPT (2023) — un modèle de 50 milliards de paramètres entraîné sur le corpus financier de Bloomberg — a démontré des améliorations en NER financière, en classification d'actualités et en analyse de sentiment. FinGPT — son alternative open source — atteint 89 % de précision sur les tâches de sentiment financier grâce à une approche centrée sur les données et RAG.

MarketSenseAI, qui utilise GPT-4 avec Chain-of-Thought et apprentissage en contexte pour l'analyse du S&P 100, a montré un alpha excédentaire de 10 à 30 % et des rendements cumulés allant jusqu'à 72 % sur 15 mois de tests. Oui, ces chiffres doivent être pris avec précaution (backtest ≠ trading en direct), mais la tendance est claire.

Pipeline de données : où trouver les données

SEC EDGAR : la source officielle

Pour les actions américaines, la source principale est SEC EDGAR. Les earnings calls ne sont généralement pas déposés directement, mais des documents associés sont disponibles :

  • Dépôts 8-K (Item 2.02 — Résultats des opérations) — communiqués de presse avec les résultats, incluant souvent l'exhibit 99 avec la transcription
  • 10-Q / 10-K — rapports trimestriels et annuels avec Management Discussion & Analysis (MD&A) — également une source de texte précieuse
  • DEF 14A — déclarations de procuration avec les informations sur la rémunération de la direction
from edgar import Company

company = Company("AAPL")
filings = company.get_filings(form="8-K")

for filing in filings.latest(10):
    if "2.02" in str(filing.items):
        doc = filing.document()
        text = doc.text()  # Full text with exhibits
        print(f"{filing.filing_date}: {len(text)} chars")

Seeking Alpha et les API commerciales

Les transcriptions d'earnings calls sont un produit à part. Seeking Alpha était historiquement la principale source gratuite, mais restreint désormais l'accès. Options commerciales :

  • Seeking Alpha Premium API — transcriptions complètes avec étiquetage des intervenants
  • AlphaVantage Earnings API — niveau gratuit avec limitations
  • Financial Modeling Prep — transcriptions + données fondamentales
  • Earnings Call Edge / Motley Fool Transcripts — sources alternatives

Crypto : appels de gouvernance et propositions DAO

C'est ici que ça devient intéressant. Les grands protocoles DeFi organisent leur équivalent d'earnings calls :

  • Uniswap — appels de gouvernance, appels communautaires, enregistrements sur YouTube
  • Aave — appels communautaires mensuels + propositions sur le forum de gouvernance
  • MakerDAO — appels de gouvernance + discussions étendues sur le forum
  • Compound — propositions de gouvernance avec discussions détaillées

Les transcriptions d'appels crypto sont généralement non structurées. La solution — Whisper d'OpenAI pour transcrire les enregistrements YouTube :

import openai
from yt_dlp import YoutubeDL

def transcribe_governance_call(youtube_url: str) -> str:
    """Download audio from YouTube and transcribe via Whisper."""
    ydl_opts = {
        'format': 'bestaudio/best',
        'postprocessors': [{
            'key': 'FFmpegExtractAudio',
            'preferredcodec': 'mp3',
            'preferredquality': '64',  # Low bitrate is sufficient for speech
        }],
        'outtmpl': '/tmp/governance_call.%(ext)s',
    }

    with YoutubeDL(ydl_opts) as ydl:
        ydl.download([youtube_url])

    client = openai.OpenAI()

    with open("/tmp/governance_call.mp3", "rb") as audio_file:
        transcript = client.audio.transcriptions.create(
            model="whisper-1",
            file=audio_file,
            response_format="verbose_json",
            timestamp_granularities=["segment"]
        )

    return transcript.text

Le coût de la transcription via l'API Whisper : 0,006 /min.Unappeldegouvernanceduneheurecou^teenviron0,36/min. Un appel de gouvernance d'une heure coûte environ 0,36 . Pour une option auto-hébergée — Whisper Large-v3 Turbo transcrit un fichier de 60 minutes en environ 17 secondes (216x le temps réel) sur un GPU moderne.

Stratégies de prompting LLM : du naïf au prêt pour la production

Signal extraction pipeline

Stratégie 1 : sentiment direct (faible)

L'approche la plus naïve — demander directement au modèle :

« Cet earnings call est-il positif ou négatif pour le cours de l'action ? »

Est-ce que ça fonctionne ? Oui, étonnamment. Lopez-Lira & Tang ont montré que même un prompt aussi primitif produit des prédictions statistiquement significatives. Mais il y a des problèmes :

  • Sortie binaire — on perd les gradations. « Catastrophe » et « légère déception » reçoivent la même étiquette
  • Pas d'explication — on ne sait pas sur quoi le modèle a fondé sa décision
  • Instabilité — une exécution répétée peut donner une réponse différente

Stratégie 2 : extraction structurée avec Chain-of-Thought (forte)

L'idée : au lieu d'un nombre unique, extraire un ensemble structuré de signaux, en forçant le modèle à expliquer chaque étape.

from pydantic import BaseModel, Field
from openai import OpenAI
from enum import Enum
from typing import Optional


class SentimentLevel(str, Enum):
    VERY_BEARISH = "very_bearish"
    BEARISH = "bearish"
    NEUTRAL = "neutral"
    BULLISH = "bullish"
    VERY_BULLISH = "very_bullish"


class GuidanceSurprise(BaseModel):
    """Deviation of forward guidance from consensus expectations."""
    revenue_guidance_vs_consensus: Optional[float] = Field(
        None, description="% deviation of revenue guidance from consensus"
    )
    margin_guidance_direction: Optional[str] = Field(
        None, description="expanding / stable / contracting"
    )
    key_quote: str = Field(
        description="Verbatim quote with guidance"
    )
    reasoning: str = Field(
        description="CoT: why this guidance matters"
    )


class ConfidenceMetrics(BaseModel):
    """Management confidence metrics."""
    hedge_word_count: int = Field(
        description="Number of hedge words: 'approximately', 'potentially', 'subject to'"
    )
    forward_looking_ratio: float = Field(
        description="Ratio of forward-looking statements to total statements"
    )
    q_and_a_evasion_count: int = Field(
        description="Number of questions where CEO/CFO gave an evasive answer"
    )
    ceo_vs_cfo_sentiment_delta: float = Field(
        description="Sentiment difference between CEO and CFO (-1 to 1). Divergence is a red flag"
    )


class CompetitiveIntelligence(BaseModel):
    """Mentions of competitors and market position."""
    competitors_mentioned: list[str] = Field(
        description="List of mentioned competitors"
    )
    market_share_claims: list[str] = Field(
        description="Market share claims"
    )
    new_product_signals: list[str] = Field(
        description="Signals about new products/services"
    )


class ManagementSignals(BaseModel):
    """Management signals."""
    turnover_risk: SentimentLevel = Field(
        description="Risk of key management turnover"
    )
    tone_shift_from_previous: Optional[str] = Field(
        None, description="How tone changed compared to last quarter"
    )
    insider_language_flags: list[str] = Field(
        description="Marker phrases: 'exploring strategic alternatives', 'right-sizing', etc."
    )


class EarningsCallAnalysis(BaseModel):
    """Complete earnings call analysis."""
    ticker: str
    quarter: str
    overall_sentiment: SentimentLevel
    sentiment_score: float = Field(description="from -1.0 to 1.0")
    guidance_surprise: GuidanceSurprise
    confidence_metrics: ConfidenceMetrics
    competitive_intel: CompetitiveIntelligence
    management_signals: ManagementSignals
    key_risks: list[str]
    key_catalysts: list[str]
    one_line_summary: str


def analyze_earnings_call(transcript: str, ticker: str, quarter: str) -> EarningsCallAnalysis:
    """
    Extract structured signals from an earnings call.
    Cost: ~$0.15-0.30 per call (GPT-4o, ~10K tokens input).
    """
    client = OpenAI()

    system_prompt = """You are a senior equity research analyst with 20 years of experience.
Analyze the following earnings call transcript and extract structured trading signals.

IMPORTANT INSTRUCTIONS:
1. Use Chain-of-Thought reasoning for each field — explain WHY before giving the value
2. Focus on DEVIATIONS from expectations, not absolute statements
3. Pay special attention to Q&A section — management is less scripted there
4. Compare management's language to typical corporate hedging baseline
5. Flag any "strategic alternatives", "right-sizing", or other euphemisms
6. Score sentiment relative to market expectations, not in absolute terms

HEDGE WORDS TO COUNT: approximately, potentially, subject to, may, might,
could, uncertain, challenging, headwinds, navigate, prudent, cautious,
evolving, dynamic, unprecedented, transitional"""

    completion = client.beta.chat.completions.parse(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": f"Ticker: {ticker}\nQuarter: {quarter}\n\n{transcript}"}
        ],
        response_format=EarningsCallAnalysis,
        temperature=0.1,  # Low temperature for reproducibility
    )

    return completion.choices[0].message.parsed

Notez plusieurs points clés :

Schéma Pydantic — OpenAI Structured Outputs garantit une conformité à 100 % au schéma. Fini le « sorry, I cannot parse the JSON ». Chaque champ a une description qui agit comme un mini-prompt pour un aspect spécifique de l'analyse.

Chain-of-Thought au sein du schéma — les champs reasoning et key_quote forcent le modèle à « montrer son travail ». Cela améliore non seulement la qualité (le modèle est contraint de trouver une citation précise avant de porter un jugement) mais crée aussi une piste d'audit pour les régulateurs.

Température 0,1 — nous ne voulons pas de créativité. Nous avons besoin de reproductibilité. À la température 0, le modèle reste parfois « coincé » dans des motifs ; 0,1 est le compromis optimal.

Stratégie 3 : few-shot avec des exemples historiques

Encore plus puissant — donner au modèle des exemples d'earnings calls passés avec les réactions de marché réelles :

few_shot_examples = """
EXAMPLE 1:
Transcript excerpt: "We are cautiously optimistic about the second half...
While we continue to navigate macro headwinds, our pipeline remains robust."
Actual market reaction: -3.2% (next day)
Analysis: Despite surface-level positivity, "cautiously optimistic" is a
DOWNGRADE from previous quarter's "very confident". Five hedge words in
two sentences. Market read through the hedging.

EXAMPLE 2:
Transcript excerpt: "Frankly, demand has exceeded our ability to supply.
We're expediting CapEx to address this."
Actual market reaction: +7.8% (next day)
Analysis: "Frankly" signals genuine surprise even from management.
Accelerated CapEx on demand = strong confidence. No hedging language.
"""

Les exemples few-shot aident le modèle à se calibrer : il apprend que « cautiously optimistic » dans le langage de Wall Street n'est pas positif — c'est un négatif discret. Sans exemples, le LLM pourrait interpréter les mots littéralement.

Quatre types de signaux

1. Surprise de guidance

Le signal le plus direct. Une entreprise fournit une prévision (guidance) pour le prochain trimestre/année, et le marché réagit à l'écart par rapport au consensus. Un LLM peut extraire le guidance même lorsque la direction le communique de manière vague :

  • « We expect revenues in the range of... » — guidance direct, facile à parser
  • « We feel comfortable with current Street estimates » — confirmation implicite du consensus
  • « There are puts and takes relative to consensus » — signal de risque implicite

Un LLM comprend les trois formulations ; regex ne comprend que la première.

2. Métriques de confiance : densité de mots de couverture

C'est mon signal préféré parce qu'il est contre-intuitif. L'essentiel : les dirigeants sont des personnes ayant une formation juridique et des services juridiques paranoïaques. Quand les choses vont bien, ils s'autorisent à être précis. Quand des problèmes se préparent — ils commencent à se couvrir.

Métriques à suivre :

Métrique Description Signal baissier
Densité de mots de couverture Part de mots de couverture pour 1 000 mots > 15 pour 1 000 mots
Ratio de certitude Ratio « will/expect » contre « may/could » < 1,5
Taux d'évasion en Q&A % de questions sans réponse directe > 30 %
Delta CEO/CFO Divergence de ton entre le CEO et le CFO > 0,3 sur l'échelle [-1, 1]

Le dernier point est particulièrement intéressant. Le CEO est un conteur d'histoires — son travail est de peindre un joli tableau. Le CFO est celui qui rend des comptes aux auditeurs. Quand le CEO dit « transformative growth ahead » et que le CFO intervient immédiatement avec « while maintaining disciplined cost management » — cette divergence signale des tensions internes.

3. Renseignement concurrentiel

Un LLM peut extraire les mentions de concurrents d'une transcription, même lorsque la direction évite les noms directs. « The largest player in the market » — ce n'est pas un mystère pour GPT-4 s'il connaît le secteur.

Signal de trading : si l'entreprise A mentionne le concurrent B dans un contexte négatif lors de son earnings call (« we're taking share from... »), c'est un signal non seulement pour A (long) mais aussi pour B (short). Un pairs trade.

4. Signaux de rotation de la direction

Phrases marqueurs de changements de direction ou de pivots stratégiques :

  • « Exploring strategic alternatives » — probable vente de l'entreprise
  • « Right-sizing our operations » — licenciements massifs
  • « The board has initiated a comprehensive review » — le CEO va bientôt partir
  • « We're bringing in fresh perspectives » — l'équipe actuelle a échoué

Chacune de ces phrases présente une corrélation statistiquement significative avec la dynamique de prix ultérieure. Un LLM peut les détecter sans faux positifs — car il comprend le contexte, contrairement à regex, qui pourrait capturer « strategic alternatives » dans une description de gamme de produits.

Backtesting : méthodologie d'étude d'événements

Event study results

Nous générons des signaux — très bien. Mais fonctionnent-ils ? La méthode de vérification standard est une Event Study avec le calcul des rendements anormaux cumulés (CAR).

Méthodologie

  1. Définir l'événement — la date de l'earnings call
  2. Fenêtre d'estimation — [-250, -30] jours de bourse avant l'événement pour estimer les rendements « normaux »
  3. Fenêtre d'événement — [-1, +60] jours autour de l'événement
  4. Calculer les rendements normaux via le modèle de marché : Rit=αi+βiRmt+ϵitR_{it} = \alpha_i + \beta_i R_{mt} + \epsilon_{it}
  5. Rendement anormal — la différence entre le rendement réel et le rendement « normal »
  6. CAR — somme cumulée des rendements anormaux sur la fenêtre d'événement
import numpy as np
import pandas as pd
from scipy import stats
from dataclasses import dataclass


@dataclass
class EventStudyResult:
    car: np.ndarray          # Cumulative abnormal returns by day
    t_stats: np.ndarray      # t-statistics for each day
    avg_car_3d: float        # CAR[-1, +1]
    avg_car_30d: float       # CAR[-1, +30]
    avg_car_60d: float       # CAR[-1, +60]
    p_value_3d: float
    p_value_30d: float
    n_events: int


def run_event_study(
    returns: pd.DataFrame,       # Daily stock returns (columns = tickers)
    market_returns: pd.Series,   # Daily market index returns
    events: pd.DataFrame,        # DataFrame with columns: [ticker, date, signal_score]
    estimation_window: int = 220,
    gap: int = 30,
    event_window: tuple = (-1, 60),
) -> EventStudyResult:
    """
    Event study to evaluate the predictive power of LLM signals.

    Sort events by signal_score, form long/short portfolios,
    calculate CAR and test statistical significance.
    """
    all_cars = []

    for _, event in events.iterrows():
        ticker = event['ticker']
        event_date = event['date']

        if ticker not in returns.columns:
            continue

        try:
            event_idx = returns.index.get_loc(event_date, method='ffill')
        except KeyError:
            continue

        est_start = event_idx - estimation_window - gap
        est_end = event_idx - gap

        if est_start < 0:
            continue

        y = returns.iloc[est_start:est_end][ticker].values
        x = market_returns.iloc[est_start:est_end].values

        mask = ~(np.isnan(y) | np.isnan(x))
        if mask.sum() < 60:  # Minimum 60 observations
            continue

        y_clean, x_clean = y[mask], x[mask]

        slope, intercept, _, _, _ = stats.linregress(x_clean, y_clean)
        residual_std = np.std(y_clean - (intercept + slope * x_clean))

        ev_start = event_idx + event_window[0]
        ev_end = event_idx + event_window[1] + 1

        if ev_end > len(returns):
            continue

        actual = returns.iloc[ev_start:ev_end][ticker].values
        market = market_returns.iloc[ev_start:ev_end].values

        expected = intercept + slope * market
        ar = actual - expected
        car = np.cumsum(ar)

        all_cars.append(car)

    if not all_cars:
        raise ValueError("No valid events found")

    min_len = min(len(c) for c in all_cars)
    all_cars = np.array([c[:min_len] for c in all_cars])

    mean_car = np.mean(all_cars, axis=0)
    std_car = np.std(all_cars, axis=0) / np.sqrt(len(all_cars))
    t_stats = mean_car / (std_car + 1e-10)

    offset = -event_window[0]  # Shift to event date

    car_3d = mean_car[min(offset + 1, min_len - 1)] if min_len > offset + 1 else mean_car[-1]
    car_30d = mean_car[min(offset + 30, min_len - 1)] if min_len > offset + 30 else mean_car[-1]
    car_60d = mean_car[min(offset + 60, min_len - 1)] if min_len > offset + 60 else mean_car[-1]

    n = len(all_cars)
    p_3d = 2 * (1 - stats.t.cdf(abs(car_3d / (np.std([c[min(offset+1, min_len-1)] for c in all_cars]) / np.sqrt(n) + 1e-10)), df=n-1))
    p_30d = 2 * (1 - stats.t.cdf(abs(car_30d / (np.std([c[min(offset+30, min_len-1)] for c in all_cars]) / np.sqrt(n) + 1e-10)), df=n-1))

    return EventStudyResult(
        car=mean_car,
        t_stats=t_stats,
        avg_car_3d=car_3d,
        avg_car_30d=car_30d,
        avg_car_60d=car_60d,
        p_value_3d=p_3d,
        p_value_30d=p_30d,
        n_events=n,
    )


def backtest_llm_signals(
    llm_signals: pd.DataFrame,  # [ticker, date, sentiment_score]
    returns: pd.DataFrame,
    market_returns: pd.Series,
):
    """Backtest: long top-quintile signals, short bottom-quintile."""

    llm_signals['quintile'] = pd.qcut(
        llm_signals['sentiment_score'], 5, labels=[1, 2, 3, 4, 5]
    )

    long_events = llm_signals[llm_signals['quintile'] == 5].copy()
    short_events = llm_signals[llm_signals['quintile'] == 1].copy()

    long_result = run_event_study(returns, market_returns, long_events)
    short_result = run_event_study(returns, market_returns, short_events)

    print(f"LONG portfolio (top quintile LLM sentiment):")
    print(f"  CAR[0,+3]:  {long_result.avg_car_3d:+.2%} (p={long_result.p_value_3d:.4f})")
    print(f"  CAR[0,+30]: {long_result.avg_car_30d:+.2%} (p={long_result.p_value_30d:.4f})")
    print(f"  N events:   {long_result.n_events}")

    print(f"\nSHORT portfolio (bottom quintile LLM sentiment):")
    print(f"  CAR[0,+3]:  {short_result.avg_car_3d:+.2%} (p={short_result.p_value_3d:.4f})")
    print(f"  CAR[0,+30]: {short_result.avg_car_30d:+.2%} (p={short_result.p_value_30d:.4f})")
    print(f"  N events:   {short_result.n_events}")

    ls_3d = long_result.avg_car_3d - short_result.avg_car_3d
    ls_30d = long_result.avg_car_30d - short_result.avg_car_30d
    print(f"\nLONG-SHORT spread:")
    print(f"  CAR[0,+3]:  {ls_3d:+.2%}")
    print(f"  CAR[0,+30]: {ls_30d:+.2%}")

Ce à quoi nous nous attendons

Sur la base des recherches existantes, les CAR réalistes pour les signaux LLM :

Fenêtre Portefeuille long Portefeuille short Spread L/S
[0, +1] +0,8 % — +1,5 % -0,5 % — -1,2 % 1,3 % — 2,7 %
[0, +30] +1,5 % — +3,0 % -1,0 % — -2,5 % 2,5 % — 5,5 %
[0, +60] +2,0 % — +4,0 % -1,5 % — -3,5 % 3,5 % — 7,5 %

L'indicateur clé est la significativité statistique. Avec p < 0,01 et N > 200 événements, on peut parler d'un signal robuste. Avec p > 0,05 — il pourrait s'agir de bruit.

Implémentation en production : de Jupyter à la prod

Architecture du pipeline en temps réel

YouTube/Audio Stream
       │
       ▼
┌─────────────────┐    ┌──────────────────┐
│  Whisper         │───▶│  Transcript       │
│  Transcription   │    │  Buffer           │
│  (streaming)     │    │  (Redis Stream)   │
└─────────────────┘    └──────────────────┘
                              │
                    ┌─────────┴─────────┐
                    ▼                   ▼
            ┌──────────────┐   ┌──────────────┐
            │ Real-time    │   │ Full-call    │
            │ Chunk Anal.  │   │ Analysis     │
            │ (every 5min) │   │ (after call  │
            │              │   │  ends)       │
            └──────────────┘   └──────────────┘
                    │                   │
                    ▼                   ▼
            ┌──────────────────────────────┐
            │     Signal Aggregator        │
            │  (confidence-weighted merge) │
            └──────────────────────────────┘
                         │
                         ▼
            ┌──────────────────────────────┐
            │     Trading Engine           │
            │  (position sizing, risk mgmt)│
            └──────────────────────────────┘

Analyse des coûts : combien coûte un earnings call

Décomposons l'économie du traitement d'un seul earnings call en production :

Composant Coût Latence
Transcription API Whisper (60 min) 0,36 $ ~17 sec (Turbo)
Extraction structurée GPT-4o 0,15-0,30 $ ~8-15 sec
Analyse de chunks en temps réel GPT-4o (x12) 1,80-3,60 $ ~5 sec chacun
Embedding pour le stockage RAG 0,01 $ <1 sec
Total (pipeline complet) 2,30-4,30 $ ~30 sec au total

Attendez, l'estimation était de 30-50 $ par appel. D'où viennent ces chiffres ? Cela dépend du modèle et de l'approche :

  • Option économique (GPT-4o-mini, une seule passe) : 0,50-1,00 $
  • Option standard (GPT-4o, extraction structurée + analyse de chunks) : 2-5 $
  • Option premium (GPT-4o, passes multiples, validation croisée, comparaison historique) : 15-30 $
  • Niveau hedge fund (modèles multiples + revue humaine + streaming temps réel) : 30-50 $+

Pour un fonds quantitatif tradant 500 tickers, le coût du traitement d'une saison de résultats (~2 000 appels sur 6 semaines) est de 4 000-10 000 $ avec l'option standard. Étant donné un alpha moyen par position de 1-3 % — le ROI est astronomique.

Latence : la course aux millisecondes

Dans le monde du HFT, la latence est primordiale. Mais pour les stratégies basées sur les résultats, la situation est différente :

  1. Un earnings call dure 45 à 60 minutes — on a le temps
  2. Le PEAD s'étend sur 60 jours — pas besoin d'entrer dès la première seconde
  3. La principale dislocation se produit dans les 30 premières minutes après la fin de l'appel

La stratégie optimale est en deux phases :

  • Phase 1 (temps réel) : analyser des chunks de 5 minutes pendant l'appel, formant un signal préliminaire
  • Phase 2 (post-appel) : analyse complète de toute la transcription 2 à 5 minutes après la fin

La Phase 1 offre une avance de 5 à 10 minutes sur les participants au marché qui attendent la fin de l'appel. Pour les actions de moyenne capitalisation, c'est suffisant.

Extension à la crypto : gouvernance DeFi et propositions DAO

Le marché crypto est un terrain d'essai idéal pour le LLM alpha mining. Voici pourquoi :

  1. Moins d'acteurs institutionnels — donc plus d'inefficacités à exploiter
  2. Gouvernance = earnings call — les décisions DAO affectent directement la tokenomics
  3. Marché 24/7 — on peut trader la réaction immédiatement
  4. Données publiques — toutes les propositions et votes sont on-chain

Types d'événements crypto à analyser

Propositions de gouvernance (Aave, Compound, Uniswap)

Une proposition modifie les paramètres du protocole — taux d'intérêt, facteurs de garantie, fee switches. Un LLM peut évaluer l'impact économique :

crypto_analysis_prompt = """Analyze this DeFi governance proposal.
Extract:
1. Economic impact on token holders (positive/negative/neutral)
2. TVL impact estimate (increase/decrease/stable + magnitude)
3. Competitive positioning vs other protocols
4. Risk factors introduced by the proposal
5. Historical precedent (similar proposals in other protocols)
6. Likely voting outcome based on forum discussion sentiment

Proposal: {proposal_text}
Forum discussion: {discussion_text}
"""

Annonces de mise à jour de protocole

Quand Uniswap annonce v4 avec des hooks, ou qu'Aave lance GHO — c'est l'équivalent d'un lancement de produit en TradFi. Un LLM peut évaluer l'élan narratif et la portée technique.

Rapports de trésorerie

Les grandes DAO disposent de trésoreries valant des centaines de millions. Les rapports de trésorerie trimestriels sont un analogue direct des résultats. Runway, taux de combustion, diversification — tout se prête à l'analyse par LLM.

Spécificités des signaux crypto

Contrairement à la TradFi, en crypto :

  • Les données on-chain confirment ou contredisent le narratif — on peut recouper ce qui est dit lors des appels de gouvernance avec les métriques réelles du protocole (TVL, volume, utilisateurs actifs)
  • Les wallets baleines comme délit d'initié — les mouvements de gros wallets après des discussions de gouvernance précèdent souvent le vote
  • Amplification du sentiment via CT (Crypto Twitter) — un signal issu d'un appel de gouvernance peut être amplifié ou étouffé par les narratifs de Twitter

Pièges et limites

Hallucinations : quand le modèle invente des chiffres

Un LLM peut « extraire » un guidance qui n'était pas dans la transcription. C'est particulièrement dangereux lors de l'analyse de la densité de mots de couverture : le modèle peut compter plus ou moins de mots qu'il n'en existe réellement.

Solution : vérification en deux phases. Le LLM extrait, du code déterministe vérifie. Pour les mots de couverture — comptage regex en parallèle de l'évaluation LLM. Écart > 20 % — signaler pour révision manuelle.

import re

HEDGE_WORDS = [
    r'\bapproximately\b', r'\bpotentially\b', r'\bsubject to\b',
    r'\bmay\b', r'\bmight\b', r'\bcould\b', r'\buncertain\b',
    r'\bchallenging\b', r'\bheadwinds\b', r'\bnavigate\b',
    r'\bprudent\b', r'\bcautious\b', r'\bevolving\b',
    r'\bdynamic\b', r'\bunprecedented\b', r'\btransitional\b',
]

def verify_hedge_count(text: str, llm_count: int) -> dict:
    """Deterministic verification of LLM hedge word count."""
    regex_count = sum(
        len(re.findall(pattern, text, re.IGNORECASE))
        for pattern in HEDGE_WORDS
    )

    deviation = abs(llm_count - regex_count) / (regex_count + 1)

    return {
        "llm_count": llm_count,
        "regex_count": regex_count,
        "deviation": deviation,
        "needs_review": deviation > 0.2,
    }

Limites de la fenêtre de contexte

Même 128K tokens peuvent ne pas suffire si l'on veut fournir :

  • La transcription actuelle (~10K tokens)
  • La transcription précédente pour comparaison (~10K)
  • Les prévisions de consensus des analystes (~2K)
  • Les exemples few-shot (~3K)
  • Le prompt système (~1K)

Total ~26K — ça passe tout juste. Mais si l'on ajoute un dépôt 10-K (~80-120K tokens) pour le contexte — on est déjà à la limite. Solution : RAG pour récupérer les chunks pertinents dans des documents longs.

Biais et erreurs systématiques

Les LLM sont entraînés sur des données historiques où certaines phrases étaient associées à certains résultats. Mais le marché s'adapte :

  • Si tout le monde commence à compter les mots de couverture avec GPT-4, les dirigeants changeront leur langage
  • Le modèle peut surpondérer l'importance des motifs issus des données d'entraînement (biais de survie)
  • Le langage corporatif évolue : « synergies » signifiait une chose en 2010, autre chose en 2026

Risque de trade surpeuplé

Si 50 fonds quantitatifs utilisent le même GPT-4 pour analyser les mêmes transcriptions — le signal se dégrade. Une analogie : quand tout le monde a commencé à trader le PEAD sur les surprises numériques, l'anomalie s'est réduite. La même chose se produira avec les signaux textuels, mais avec un délai :

  1. Maintenant (2026) — peu de fonds utilisent systématiquement les LLM pour les earnings calls. L'alpha est significatif
  2. Dans 2-3 ans — adoption généralisée, l'alpha diminue
  3. Dans 5 ans — les signaux LLM basiques deviennent une commodité, l'edge ne persiste que dans les modèles personnalisés et les données uniques

C'est le cycle de vie standard d'un signal alpha. Profitez-en tant que ça dure.

En guise de conclusion : un plan d'action

Si vous voulez commencer à utiliser les LLM pour l'analyse d'earnings calls, voici un plan minimum viable :

  1. Commencez avec des données gratuites — SEC EDGAR + EdgarTools pour les dépôts 8-K/10-Q
  2. Utilisez l'extraction structurée — schémas Pydantic via OpenAI Structured Outputs
  3. Faites du backtesting via event study — CAR sur données historiques, minimum 200 événements
  4. Ajoutez des exemples few-shot — 5 à 10 exemples étiquetés améliorent radicalement la qualité
  5. Vérifiez de manière déterministe — le LLM extrait, regex vérifie, l'humain audite
  6. Commencez par les moyennes capitalisations — plus d'alpha, moins de concurrence avec les grands fonds
  7. Étendez à la crypto — appels de gouvernance et propositions DAO comme territoire inexploré

Souvenez-vous de la règle cardinale de l'analyse quantitative : si un signal semble trop beau pour être vrai — vérifiez-le à nouveau. Les LLM créent une illusion de compréhension, mais derrière se cache un appariement statistique de motifs. Un outil puissant — mais un outil, pas un oracle.


Bibliographie

  1. Ball, R., Brown, P. (1968). An Empirical Evaluation of Accounting Income Numbers. Journal of Accounting Research, 6(2), 159-178. — Première découverte du PEAD.

  2. Bernard, V.L., Thomas, J.K. (1989). Post-Earnings-Announcement Drift: Delayed Price Response or Risk Premium? Journal of Accounting Research, 27, 1-36. — Article canonique sur le PEAD.

  3. Loughran, T., McDonald, B. (2011). When Is a Liability Not a Liability? Textual Analysis, Dictionaries, and 10-Ks. Journal of Finance, 66(1), 35-65. — Dictionnaire de sentiment financier.

  4. Araci, D. (2019). FinBERT: Financial Sentiment Analysis with Pre-trained Language Models. arXiv:1908.10063. — BERT pour le NLP financier, +14pp par rapport au SOTA.

  5. Wu, S. et al. (2023). BloombergGPT: A Large Language Model for Finance. arXiv:2303.17564. — Modèle de 50 milliards de paramètres de Bloomberg.

  6. Yang, H. et al. (2023). FinGPT: Open-Source Financial Large Language Models. arXiv:2306.06031. — Alternative open source à BloombergGPT, 89 % de précision.

  7. Lopez-Lira, A., Tang, Y. (2023). Can ChatGPT Forecast Stock Price Movements? Return Predictability and Large Language Models. arXiv:2304.07619. — GPT-4 prédit les rendements avec ~90 % de taux de réussite.

  8. Meursault, V., Liang, P.J., Routledge, B., Scanlon, M.M. (2023). PEAD.txt: Post-Earnings-Announcement Drift Using Text. Journal of Financial and Quantitative Analysis. — Le PEAD basé sur le texte est deux fois plus important que le PEAD numérique.

  9. Fatouros, G. et al. (2024). Can Large Language Models Beat Wall Street? Evaluating GPT-4's Impact on Financial Decision-Making with MarketSenseAI. Neural Computing and Applications. — Framework GPT-4 avec 10-30 % d'alpha excédentaire sur le S&P 100.

  10. Chen, Y. et al. (2025). GPT-Signal: Generative AI for Semi-automated Feature Engineering in the Alpha Research Process. arXiv:2410.18448. — Génération automatique de signaux de trading via LLM.

  11. Zhang, X. et al. (2025). Can LLMs Hit Moving Targets? Tracking Evolving Signals in Corporate Disclosures. arXiv:2510.03195. — Détection de « cibles mouvantes » dans les publications d'entreprise.

  12. Chen, Z. et al. (2025). Large Language Models in Equity Markets: Applications, Techniques, and Insights. Frontiers in Artificial Intelligence. — Étude de 84 recherches sur les LLM en finance.


Cet article a un caractère éducatif et ne constitue pas un conseil en investissement. Toute stratégie de trading décrite ici nécessite un backtesting approfondi et une gestion des risques avant tout déploiement avec du capital réel.

blog.disclaimer

Authors

Eugen Soloviov
Eugen Soloviov

Trading-systems engineer

Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.

Newsletter

Gardez une longueur d'avance sur le marché

Abonnez-vous à notre newsletter pour des insights exclusifs sur le trading IA, des analyses de marché et des mises à jour de la plateforme.

Nous respectons votre vie privée. Désabonnement possible à tout moment.