← Terug naar artikelen
March 20, 2026
5 min leestijd

LLM Alpha Mining: hoe haal je handelssignalen uit earnings calls en financiële documenten

LLM Alpha Mining: hoe haal je handelssignalen uit earnings calls en financiële documenten
#llm
#alpha
#earnings
#nlp
#gpt
#financial-analysis
#algo-trading
🤖
Part 5 of 5 · Collection
AI Agents for Trading

Er gaat een grap rond op Wall Street: "De meest waardevolle informatie in een earnings call is niet wat de CEO zei, maar hoe hij het zei." Wanneer Tim Cook zegt "we zijn voorzichtig optimistisch" in plaats van het "we zijn zeer tevreden" van vorig jaar — dat is geen taalspelletje, dat is een signaal dat honderden miljoenen dollars waard is.

Al decennialang proberen kwantitatieve fondsen het extraheren van deze signalen te systematiseren. Eerst telden ze de frequentie van "positieve" en "negatieve" woorden met behulp van woordenboeken. Toen zetten ze BERT in. En nu hebben we GPT-4o, Claude en open-source LLM's die de subtiliteiten van bedrijfsjargon kunnen ontleden met een nauwkeurigheid die zelfs de onderzoekers zelf schrik aanjaagt.

Laten we uiteenzetten hoe je een volwaardige pipeline bouwt om handelssignalen uit earnings calls te halen — van het verkrijgen van het transcript tot het backtesten van cumulatieve abnormale rendementen.

Waarom earnings calls een goudmijn zijn voor alpha

Post-Earnings Announcement Drift: de anomalie die niet wil sterven

In 1968 ontdekten Ball en Brown iets vreemds: nadat de kwartaalresultaten zijn gepubliceerd, blijven aandelen nog 60-90 dagen doordrijven in de richting van de "verrassing". Ze noemden het Post-Earnings Announcement Drift (PEAD). Sindsdien is er meer dan een halve eeuw verstreken, zijn er honderden papers geschreven, is de anomalie vanuit tientallen invalshoeken verklaard — en toch werkt het nog steeds.

PEAD is een van de meest hardnekkige marktanomalieën in de geschiedenis van de financiën. Een portfoliostrategie van "koop positieve verrassing, verkoop negatieve verrassing" heeft historisch gezien 10-25% jaarlijks overrendement opgeleverd. Waarom heeft de markt dit niet weggearbitreerd? Verschillende redenen:

  • Beperkte aandacht van beleggers — wanneer 200 bedrijven in dezelfde week rapporteren, is het fysiek onmogelijk om alle transcripten te lezen
  • Cognitieve complexiteit — een earnings call duurt 45-60 minuten, en het cruciale signaal kan verstopt zitten in één enkele zin in de 38e minuut van de Q&A-sessie
  • Taalambiguïteit — de CFO zegt "we navigeren door tegenwind", en zonder context is het onduidelijk of dit een zachte waarschuwing is of standaard hedging

Hier komen LLM's het toneel op. Voor het eerst hebben we een instrument dat 500 transcripten op een avond kan verwerken, terwijl het nuances opvangt die zelfs ervaren analisten zouden missen.

PEAD.txt: tekst is belangrijker dan cijfers

Onderzoekers van de Federal Reserve Bank of Philadelphia (Meursault, Liang, Routledge, Scanlon) publiceerden het PEAD.txt-paper, dat aannames over de waarde van tekstuele informatie omverwierp. Ze bouwden een tekstgebaseerde analoog van de standaard earnings surprise — SUE.txt — die de numerieke earnings-waarde helemaal niet gebruikt.

Het resultaat? SUE.txt genereert een drift die twee keer zo groot is als de klassieke PEAD. Bovendien: in de afgelopen jaren, terwijl de klassieke PEAD gebaseerd op numerieke verrassingen vrijwel is verdwenen (de markt heeft geleerd), blijft de tekstuele drift significant. De markt heeft geleerd cijfers snel te verwerken, maar worstelt nog steeds met tekstinterpretatie.

Dit is het fundamentele argument voor een op NLP gebaseerde benadering van earnings calls.

Van sentiment naar semantiek: evolutie van de aanpak

From sentiment to semantics

Eerste generatie: bag-of-words en woordenboeken (2000-2015)

Alles begon met het Loughran-McDonald-woordenboek (2011) — een woordenlijst gelabeld als "positief," "negatief," "onzeker," en "geschilgevoelig." Het idee was elegant in zijn eenvoud: tel het percentage negatieve woorden in een 10-K-indiening en handel daarop.

Het probleem? Het woord "outstanding" betekent in een financiële context vaker "openstaande schuld" dan "uitstekend resultaat." Het woord "risico" in Risk Management is geen negatief signaal — het is een procesbeschrijving. Standaard NLP-sentimentwoordenboeken presteerden gênant slecht op financiële teksten.

Loughran en McDonald creëerden een gespecialiseerd woordenboek, wat de situatie verbeterde, maar het fundamentele probleem bleef: bag-of-words begrijpt geen context. "We zijn er niet in geslaagd de verwachtingen niet te halen" — er staan hier twee "negatieve" woorden, maar de betekenis is positief.

Tweede generatie: FinBERT en transformers (2019-2023)

In 2019 publiceerde Dogu Araci FinBERT — BERT fijn afgesteld op financiële teksten van Reuters TRC2. De resultaten waren indrukwekkend: een verbetering van 14 procentpunten op de Financial PhraseBank-dataset ten opzichte van de state-of-the-art. FinBERT begreep context: "outstanding" naast "debt" — negatief, naast "performance" — positief.

Maar FinBERT had een beperking: een contextvenster van 512 tokens. Een earnings call beslaat 8.000-12.000 woorden. Opsplitsen in chunks en het sentiment middelen betekent het verlies van de semantiek tussen paragrafen. De CEO zou kunnen beginnen met optimisme, om vervolgens terloops problemen in de toeleveringsketen te noemen tijdens de Q&A. FinBERT analyseert elke chunk onafhankelijk en mist dit contrast.

Derde generatie: LLM's met lange context (2023-heden)

GPT-4, Claude, Gemini met contextvensters van 128K-1M tokens veranderden de spelregels. Nu kun je een volledig transcript in één keer laden en vragen stellen die begrip van het hele document vereisen.

De sleutelstudie — Lopez-Lira & Tang (2023) "Can ChatGPT Forecast Stock Price Movements?" Op meer dan 50.000 krantenkoppen liet GPT-4 een trefzekerheid van ~90% zien bij het voorspellen van de richting van de eerste marktreactie en voorspelde het significant de daaropvolgende drift, vooral voor small-capbedrijven en negatief nieuws. Eerdere modellen (GPT-1, GPT-2, BERT) vertoonden deze vaardigheid niet — voorspellend vermogen ontstaat als een opkomende eigenschap van grote modellen.

BloombergGPT (2023) — een model met 50 miljard parameters getraind op Bloombergs financiële corpus — toonde verbeteringen in financiële NER, nieuwsclassificatie en sentimentanalyse. FinGPT — het open-source alternatief — behaalt 89% nauwkeurigheid op financiële sentimenttaken met behulp van een datagerichte aanpak en RAG.

MarketSenseAI, dat GPT-4 gebruikt met Chain-of-Thought en In-Context Learning voor S&P 100-analyse, liet een overrendement van 10-30% zien en cumulatieve rendementen tot 72% over 15 maanden testen. Ja, deze cijfers moeten met voorzichtigheid worden bekeken (backtest ≠ live trading), maar de trend is duidelijk.

Datapipeline: waar haal je de data vandaan

SEC EDGAR: de officiële bron

Voor Amerikaanse aandelen is de primaire bron SEC EDGAR. Earnings calls worden meestal niet rechtstreeks ingediend, maar gerelateerde documenten zijn beschikbaar:

  • 8-K-indieningen (Item 2.02 — Resultaten van Operaties) — persberichten met resultaten, vaak inclusief exhibit 99 met het transcript
  • 10-Q / 10-K — kwartaal- en jaarverslagen met Management Discussion & Analysis (MD&A) — ook een waardevolle tekstbron
  • DEF 14A — volmachtverklaringen met informatie over managementbeloningen
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 en commerciële API's

Earnings call-transcripten zijn een apart product. Seeking Alpha was historisch gezien de belangrijkste gratis bron, maar beperkt nu de toegang. Commerciële opties:

  • Seeking Alpha Premium API — volledige transcripten met sprekerlabels
  • AlphaVantage Earnings API — gratis tier met beperkingen
  • Financial Modeling Prep — transcripten + fundamentals
  • Earnings Call Edge / Motley Fool Transcripts — alternatieve bronnen

Crypto: governance calls en DAO-voorstellen

Hier wordt het interessant. Grote DeFi-protocollen houden hun equivalent van earnings calls:

  • Uniswap — governance calls, community calls, opnames op YouTube
  • Aave — maandelijkse community calls + governance-forumvoorstellen
  • MakerDAO — governance calls + uitgebreide forumdiscussies
  • Compound — governance-voorstellen met gedetailleerde discussies

Crypto-call-transcripten zijn meestal ongestructureerd. De oplossing — OpenAI's Whisper voor het transcriberen van YouTube-opnames:

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

De kosten van transcriptie via de Whisper API: 0,006/min.Eenuurdurendegovernancecallkost 0,006/min. Een uur durende governance call kost ~0,36. Voor een self-hosted optie — Whisper Large-v3 Turbo transcribeert een bestand van 60 minuten in ~17 seconden (216x realtime) op een moderne GPU.

LLM-promptingstrategieën: van naïef tot productieklaar

Signal extraction pipeline

Strategie 1: direct sentiment (zwak)

De naïefste aanpak — het model rechtstreeks vragen:

"Is deze earnings call positief of negatief voor de aandelenkoers?"

Werkt dit? Ja, verrassend genoeg. Lopez-Lira & Tang toonden aan dat zelfs zo'n primitieve prompt statistisch significante voorspellingen oplevert. Maar er zijn problemen:

  • Binaire output — je verliest gradaties. "Catastrofe" en "milde teleurstelling" krijgen hetzelfde label
  • Geen uitleg — het is onduidelijk waarop het model zijn beslissing baseerde
  • Instabiliteit — een herhaalde run kan een ander antwoord geven

Strategie 2: gestructureerde extractie met Chain-of-Thought (sterk)

Het idee: in plaats van een enkel getal, een gestructureerde set signalen extraheren, waarbij het model wordt gedwongen elke stap te verklaren.

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

Let op een paar kernpunten:

Pydantic-schema — OpenAI Structured Outputs garandeert 100% schemanaleving. Geen "sorry, I cannot parse the JSON" meer. Elk veld heeft een beschrijving die dienstdoet als een mini-prompt voor een specifiek aspect van de analyse.

Chain-of-Thought binnen het schema — de velden reasoning en key_quote dwingen het model om "zijn werk te tonen." Dit verbetert niet alleen de kwaliteit (het model wordt gedwongen een specifiek citaat te vinden voordat het een oordeel velt), maar creëert ook een audit trail voor toezichthouders.

Temperatuur 0,1 — we willen geen creativiteit. We hebben reproduceerbaarheid nodig. Bij temperatuur 0 raakt het model soms "vast" in patronen; 0,1 is het optimale compromis.

Strategie 3: few-shot met historische voorbeelden

Nog krachtiger — het model voorbeelden geven van eerdere earnings calls met daadwerkelijke marktreacties:

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.
"""

Few-shot-voorbeelden helpen het model te kalibreren: het leert dat "cautiously optimistic" in Wall Street-taal niet positief is — het is een zacht negatief. Zonder voorbeelden kan de LLM woorden letterlijk interpreteren.

Vier soorten signalen

1. Guidance Surprise

Het meest directe signaal. Een bedrijf geeft een prognose (guidance) voor het volgende kwartaal/jaar, en de markt reageert op de afwijking van de consensus. Een LLM kan guidance extraheren, zelfs wanneer het management deze vaag communiceert:

  • "We expect revenues in the range of..." — directe guidance, gemakkelijk te parsen
  • "We feel comfortable with current Street estimates" — impliciete bevestiging van consensus
  • "There are puts and takes relative to consensus" — impliciet risicosignaal

Een LLM begrijpt alle drie de formuleringen; regex begrijpt alleen de eerste.

2. Confidence Metrics: hedge-word-dichtheid

Dit is mijn favoriete signaal omdat het contra-intuïtief is. De essentie: managers zijn mensen met juridische scholing en paranoïde juridische afdelingen. Wanneer het goed gaat, staan ze zichzelf toe specifiek te zijn. Wanneer er problemen broeien — beginnen ze te hedgen.

Te volgen metrics:

Metric Beschrijving Bearish signaal
Hedge-word-dichtheid Aandeel hedge-woorden per 1.000 woorden > 15 per 1.000 woorden
Certainty ratio Verhouding "will/expect" versus "may/could" < 1,5
Q&A ontwijkingspercentage % vragen zonder direct antwoord > 30%
CEO/CFO-delta Toonverschil tussen CEO en CFO > 0,3 op schaal [-1, 1]

Het laatste punt is bijzonder interessant. De CEO is een verhalenverteller — zijn taak is een mooi plaatje te schetsen. De CFO is degene die verantwoording aflegt aan de accountants. Wanneer de CEO zegt "transformative growth ahead" en de CFO onmiddellijk aanvult met "while maintaining disciplined cost management" — signaleert deze divergentie interne spanningen.

3. Competitive Intelligence

Een LLM kan concurrentvermeldingen uit een transcript extraheren, zelfs wanneer het management directe namen vermijdt. "The largest player in the market" — dat is geen mysterie voor GPT-4 als het de sector kent.

Handelssignaal: als bedrijf A concurrent B in een negatieve context noemt tijdens zijn earnings call ("we're taking share from..."), is dat niet alleen een signaal voor A (long) maar ook voor B (short). Een pairs trade.

4. Management Turnover-signalen

Markerzinnen voor managementveranderingen of strategische koerswijzigingen:

  • "Exploring strategic alternatives" — waarschijnlijke verkoop van het bedrijf
  • "Right-sizing our operations" — massaontslagen
  • "The board has initiated a comprehensive review" — de CEO vertrekt binnenkort
  • "We're bringing in fresh perspectives" — het huidige team is gefaald

Elk van deze zinnen heeft een statistisch significante correlatie met de daaropvolgende koersdynamiek. Een LLM kan ze detecteren met nul valse positieven — omdat het context begrijpt, in tegenstelling tot regex, dat "strategic alternatives" zou kunnen oppikken in een productlijnbeschrijving.

Backtesting: Event Study-methodologie

Event study results

We genereren signalen — geweldig. Maar werken ze? De standaard verificatiemethode is een Event Study met de berekening van Cumulative Abnormal Returns (CAR).

Methodologie

  1. Het event definiëren — de datum van de earnings call
  2. Schattingsvenster — [-250, -30] handelsdagen vóór het event om "normale" rendementen te schatten
  3. Event-venster — [-1, +60] dagen rondom het event
  4. Normale rendementen berekenen via het marktmodel: Rit=αi+βiRmt+ϵitR_{it} = \alpha_i + \beta_i R_{mt} + \epsilon_{it}
  5. Abnormaal rendement — het verschil tussen het werkelijke en het "normale" rendement
  6. CAR — cumulatieve som van abnormale rendementen over het event-venster
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%}")

Wat we verwachten te zien

Op basis van bestaand onderzoek, realistische CAR's voor LLM-signalen:

Venster Long-portfolio Short-portfolio L/S-spread
[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%

De belangrijkste indicator is statistische significantie. Met p < 0,01 en N > 200 events kun je spreken van een robuust signaal. Met p > 0,05 — kan het ruis zijn.

Productie-implementatie: van Jupyter naar prod

Real-time pipeline-architectuur

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)│
            └──────────────────────────────┘

Kostenanalyse: hoeveel kost één earnings call

Laten we de economie van het verwerken van één earnings call in productie uiteenzetten:

Component Kosten Latentie
Whisper API-transcriptie (60 min) $0,36 ~17 sec (Turbo)
GPT-4o gestructureerde extractie $0,15-0,30 ~8-15 sec
GPT-4o real-time chunk-analyse (x12) $1,80-3,60 ~5 sec elk
Embedding voor RAG-opslag $0,01 <1 sec
Totaal (volledige pipeline) $2,30-4,30 ~30 sec totaal

Wacht, de schatting was $30-50 per call. Waar komen die cijfers vandaan? Het hangt af van het model en de aanpak:

  • Budgetoptie (GPT-4o-mini, enkele pass): $0,50-1,00
  • Standaardoptie (GPT-4o, gestructureerde extractie + chunk-analyse): $2-5
  • Premiumoptie (GPT-4o, meerdere passes, cross-validatie, historische vergelijking): $15-30
  • Hedgefonds-niveau (meerdere modellen + menselijke review + real-time streaming): $30-50+

Voor een kwantitatief fonds dat 500 tickers verhandelt, bedragen de kosten voor het verwerken van een earnings-seizoen (~2.000 calls over 6 weken) 4.0004.000-10.000 met de standaardoptie. Gezien een gemiddelde alpha per positie van 1-3% — is de ROI astronomisch.

Latentie: de race om milliseconden

In de HFT-wereld is latentie alles. Maar voor op earnings gebaseerde strategieën is de situatie anders:

  1. Een earnings call duurt 45-60 minuten — je hebt tijd
  2. PEAD strekt zich uit over 60 dagen — geen noodzaak om in de eerste seconde in te stappen
  3. De belangrijkste dislocatie vindt plaats in de eerste 30 minuten na afloop van de call

De optimale strategie is tweefasig:

  • Fase 1 (real-time): analyseer chunks van 5 minuten tijdens de call, waarbij een voorlopig signaal wordt gevormd
  • Fase 2 (post-call): volledige analyse van het hele transcript 2-5 minuten na afloop

Fase 1 biedt een voorsprong van 5-10 minuten op marktdeelnemers die wachten tot de call eindigt. Voor mid-capaandelen is dit genoeg.

Uitbreiding naar crypto: DeFi governance en DAO-voorstellen

De cryptomarkt is een ideaal testterrein voor LLM alpha mining. Hier is waarom:

  1. Minder institutionele spelers — wat meer inefficiëntie betekent om te benutten
  2. Governance = earnings call — DAO-beslissingen beïnvloeden de tokenomics rechtstreeks
  3. 24/7-markt — je kunt de reactie onmiddellijk verhandelen
  4. Publieke data — alle voorstellen en stemmingen zijn on-chain

Soorten crypto-events voor analyse

Governance Proposals (Aave, Compound, Uniswap)

Een voorstel wijzigt protocolparameters — rentetarieven, onderpandfactoren, fee switches. Een LLM kan de economische impact beoordelen:

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}
"""

Protocol Update Announcements

Wanneer Uniswap v4 met hooks aankondigt, of Aave GHO lanceert — dat is het equivalent van een productlancering in TradFi. Een LLM kan narratief momentum en technische relevantie beoordelen.

Treasury Reports

Grote DAO's hebben treasuries ter waarde van honderden miljoenen. Kwartaal-treasuryrapporten zijn een directe analoog van earnings. Runway, burn rate, diversificatie — allemaal vatbaar voor LLM-analyse.

Specifieke kenmerken van crypto-signalen

In tegenstelling tot TradFi geldt in crypto:

  • On-chain data bevestigt of weerspreekt het narratief — je kunt kruisverwijzen wat er op governance calls wordt gezegd met werkelijke protocolmetrics (TVL, volume, actieve gebruikers)
  • Whale wallets als insider trading — grote wallet-bewegingen na governance-discussies gaan vaak vooraf aan stemmingen
  • Sentiment-amplificatie via CT (Crypto Twitter) — een signaal van een governance call kan worden versterkt of onderdrukt door Twitter-narratieven

Valkuilen en beperkingen

Hallucinaties: wanneer het model cijfers verzint

Een LLM kan guidance "extraheren" die niet in het transcript stond. Dit is vooral gevaarlijk bij het analyseren van hedge-word-dichtheid: het model kan meer of minder woorden tellen dan er daadwerkelijk bestaan.

Oplossing: tweefasige verificatie. De LLM extraheert, deterministische code verifieert. Voor hedge-woorden — regex-telling parallel aan LLM-beoordeling. Afwijking > 20% — markeren voor handmatige review.

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,
    }

Beperkingen van het contextvenster

Zelfs 128K tokens zijn misschien niet genoeg als je het volgende wilt aanleveren:

  • Huidig transcript (~10K tokens)
  • Vorig transcript ter vergelijking (~10K)
  • Analisten-consensusprognoses (~2K)
  • Few-shot-voorbeelden (~3K)
  • Systeemprompt (~1K)

Totaal ~26K — we passen er nog net in. Maar als je een 10-K-indiening (~80-120K tokens) toevoegt voor context — zit je al aan de grens. Oplossing: RAG om relevante chunks uit lange documenten op te halen.

Bias en systematische fouten

LLM's worden getraind op historische data waarin bepaalde zinsdelen geassocieerd werden met bepaalde uitkomsten. Maar de markt past zich aan:

  • Als iedereen hedge-woorden begint te tellen met GPT-4, zullen managers hun taalgebruik veranderen
  • Het model kan de betekenis van patronen uit trainingsdata overschatten (survivorship bias)
  • Bedrijfstaal evolueert: "synergieën" betekende in 2010 iets anders dan in 2026

Crowded-trade-risico

Als 50 kwantitatieve fondsen dezelfde GPT-4 gebruiken om dezelfde transcripten te analyseren — degradeert het signaal. Een analogie: toen iedereen PEAD begon te verhandelen op numerieke verrassingen, kromp de anomalie. Hetzelfde zal gebeuren met tekstuele signalen, maar met vertraging:

  1. Nu (2026) — weinigen gebruiken LLM's systematisch voor earnings calls. Alpha is significant
  2. Over 2-3 jaar — brede adoptie, alpha neemt af
  3. Over 5 jaar — basale LLM-signalen worden een commodity, edge blijft alleen bestaan in aangepaste modellen en unieke data

Dit is de standaard levenscyclus van een alpha-signaal. Geniet ervan zolang het duurt.

In plaats van een conclusie: een actieplan

Als je wilt beginnen met het gebruik van LLM's voor earnings call-analyse, hier een minimaal haalbaar plan:

  1. Begin met gratis data — SEC EDGAR + EdgarTools voor 8-K/10-Q-indieningen
  2. Gebruik gestructureerde extractie — Pydantic-schema's via OpenAI Structured Outputs
  3. Backtest via event study — CAR op historische data, minimaal 200 events
  4. Voeg few-shot-voorbeelden toe — 5-10 gelabelde voorbeelden verbeteren de kwaliteit radicaal
  5. Verifieer deterministisch — LLM extraheert, regex verifieert, mens auditeert
  6. Begin met mid-cap — meer alpha, minder concurrentie met grote fondsen
  7. Breid uit naar crypto — governance calls en DAO-voorstellen als onontgonnen terrein

Onthoud de kardinale regel van kwantitatieve analyse: als een signaal te mooi klinkt om waar te zijn — controleer het opnieuw. LLM's creëren een illusie van begrip, maar daarachter schuilt statistische patroonherkenning. Een krachtig instrument — maar een instrument, geen orakel.


Bibliografie

  1. Ball, R., Brown, P. (1968). An Empirical Evaluation of Accounting Income Numbers. Journal of Accounting Research, 6(2), 159-178. — Eerste ontdekking van 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. — Canonieke PEAD-paper.

  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. — Financieel sentimentwoordenboek.

  4. Araci, D. (2019). FinBERT: Financial Sentiment Analysis with Pre-trained Language Models. arXiv:1908.10063. — BERT voor financiële NLP, +14pp t.o.v. SOTA.

  5. Wu, S. et al. (2023). BloombergGPT: A Large Language Model for Finance. arXiv:2303.17564. — Bloombergs 50B-parametermodel.

  6. Yang, H. et al. (2023). FinGPT: Open-Source Financial Large Language Models. arXiv:2306.06031. — Open-source alternatief voor BloombergGPT, 89% nauwkeurigheid.

  7. Lopez-Lira, A., Tang, Y. (2023). Can ChatGPT Forecast Stock Price Movements? Return Predictability and Large Language Models. arXiv:2304.07619. — GPT-4 voorspelt rendementen met ~90% trefzekerheid.

  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. — Tekstgebaseerde PEAD is twee keer zo groot als numerieke PEAD.

  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. — GPT-4-framework met 10-30% overrendement op 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. — Automatische generatie van handelssignalen via LLM.

  11. Zhang, X. et al. (2025). Can LLMs Hit Moving Targets? Tracking Evolving Signals in Corporate Disclosures. arXiv:2510.03195. — Detectie van "bewegende doelen" in bedrijfspublicaties.

  12. Chen, Z. et al. (2025). Large Language Models in Equity Markets: Applications, Techniques, and Insights. Frontiers in Artificial Intelligence. — Overzicht van 84 LLM-onderzoeken in finance.


Dit artikel is educatief van aard en vormt geen beleggingsadvies. Elke hier beschreven handelsstrategie vereist grondige backtesting en risicobeheer voordat deze wordt ingezet met echt kapitaal.

Disclaimer: De informatie in dit artikel is uitsluitend bedoeld voor educatieve en informatieve doeleinden en vormt geen financieel, beleggings- of handelsadvies. Het handelen in cryptovaluta brengt een aanzienlijk risico op verlies met zich mee.

Auteurs

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

Blijf de markt voor

Abonneer je op onze nieuwsbrief voor exclusieve AI-handelsinzichten, marktanalyses en platformupdates.

We respecteren je privacy. Je kunt je op elk moment afmelden.