LLM Alpha Mining: Come Estrarre Segnali di Trading dalle Earnings Call e dai Documenti Finanziari
A Wall Street circola una battuta: "L'informazione più preziosa di una earnings call non è ciò che ha detto il CEO, ma come lo ha detto." Quando Tim Cook dice "siamo cautamente ottimisti" invece del "siamo molto soddisfatti" dell'anno scorso — non è un gioco linguistico, è un segnale che vale centinaia di milioni di dollari.
Per decenni, i fondi quant hanno cercato di sistematizzare l'estrazione di questi segnali. Prima contavano la frequenza delle parole "positive" e "negative" usando dizionari. Poi hanno scatenato BERT. E ora abbiamo GPT-4o, Claude e LLM open-source capaci di analizzare le sottigliezze del gergo corporativo con una precisione che spaventa persino i ricercatori stessi.
Vediamo come costruire una pipeline completa per l'estrazione di segnali di trading dalle earnings call — dall'ottenimento della trascrizione fino al backtesting dei rendimenti anomali cumulativi.
Perché le Earnings Call Sono una Miniera d'Oro per l'Alpha
Post-Earnings Announcement Drift: L'Anomalia che Non Muore
Nel 1968, Ball e Brown scoprirono qualcosa di strano: dopo la pubblicazione dei risultati trimestrali, le azioni continuano a muoversi nella direzione della "sorpresa" per altri 60-90 giorni. Lo chiamarono Post-Earnings Announcement Drift (PEAD). Da allora è passato più di mezzo secolo, sono stati scritti centinaia di articoli, l'anomalia è stata spiegata da una dozzina di angolazioni — e funziona ancora.
Il PEAD è una delle anomalie di mercato più persistenti nella storia della finanza. Una strategia di portafoglio "compra la sorpresa positiva, vendi la sorpresa negativa" ha storicamente generato un rendimento in eccesso del 10-25% annuo. Perché il mercato non ha arbitraggiato questa opportunità? Diverse ragioni:
- Attenzione limitata degli investitori — quando 200 aziende pubblicano i risultati nella stessa settimana, è fisicamente impossibile leggere tutte le trascrizioni
- Complessità cognitiva — una earnings call dura 45-60 minuti e il segnale chiave può essere sepolto in una singola frase al 38° minuto della sessione Q&A
- Ambiguità del linguaggio — il CFO dice "stiamo navigando controventi," e senza contesto non è chiaro se si tratta di un avvertimento soft o di una copertura standard
È qui che gli LLM entrano in scena. Per la prima volta disponiamo di uno strumento in grado di elaborare 500 trascrizioni in una serata cogliendo sfumature che anche analisti esperti mancherebbero.
PEAD.txt: Il Testo Conta Più dei Numeri
Ricercatori della Federal Reserve Bank of Philadelphia (Meursault, Liang, Routledge, Scanlon) hanno pubblicato il paper PEAD.txt, che ha ribaltato le assunzioni sul valore dell'informazione testuale. Hanno costruito un analogo testuale della sorpresa standard sugli utili — SUE.txt — che non utilizza affatto il valore numerico degli utili.
Il risultato? SUE.txt genera un drift due volte più grande del classico PEAD. Inoltre: negli ultimi anni, mentre il classico PEAD basato sulle sorprese numeriche è praticamente scomparso (il mercato ha imparato), il drift testuale rimane significativo. Il mercato ha imparato a elaborare velocemente i numeri, ma ancora fatica con l'interpretazione del testo.
Questo è l'argomento fondamentale a favore di un approccio NLP alle earnings call.
Dal Sentiment alla Semantica: Evoluzione degli Approcci

Prima Generazione: Bag-of-Words e Dizionari (2000-2015)
Tutto è iniziato con il dizionario Loughran-McDonald (2011) — un elenco di parole etichettate come "positive," "negative," "incerte" e "litigiose." L'idea era elegante nella sua semplicità: contare la percentuale di parole negative in un deposito 10-K e fare trading su questo.
Il problema? La parola "outstanding" in un contesto finanziario significa più spesso "debito non pagato" che "ottimo risultato." La parola "risk" in Risk Management non è un segnale negativo — è la descrizione di un processo. I dizionari di sentiment NLP standard hanno ottenuto risultati imbarazzantemente scarsi sui testi finanziari.
Loughran e McDonald hanno creato un dizionario specializzato, che ha migliorato la situazione, ma il problema fondamentale è rimasto: il bag-of-words non capisce il contesto. "We did not fail to meet expectations" — ci sono due parole "negative" qui, ma il significato è positivo.
Seconda Generazione: FinBERT e Transformer (2019-2023)
Nel 2019, Dogu Araci ha pubblicato FinBERT — BERT messo a punto su testi finanziari da Reuters TRC2. I risultati erano impressionanti: un miglioramento di 14 punti percentuali sul dataset Financial PhraseBank rispetto allo stato dell'arte. FinBERT capiva il contesto: "outstanding" vicino a "debt" — negativo, vicino a "performance" — positivo.
Ma FinBERT aveva un limite: una finestra di contesto di 512 token. Una earnings call ha 8.000-12.000 parole. Dividere in frammenti e mediare il sentiment significa perdere la semantica inter-paragrafo. Il CEO potrebbe iniziare con ottimismo, poi menzionare casualmente problemi della supply chain durante il Q&A. FinBERT analizza ogni frammento indipendentemente e perde questo contrasto.
Terza Generazione: LLM con Contesto Lungo (2023-Presente)
GPT-4, Claude, Gemini con finestre di contesto da 128K-1M token hanno cambiato le regole del gioco. Ora è possibile caricare una trascrizione intera in una volta sola e porre domande che richiedono la comprensione dell'intero documento.
Lo studio chiave — Lopez-Lira & Tang (2023) "Can ChatGPT Forecast Stock Price Movements?" Su oltre 50.000 titoli, GPT-4 ha mostrato un hit rate del ~90% nel prevedere la direzione della reazione iniziale del mercato e ha previsto significativamente il drift successivo, specialmente per le small-cap e le notizie negative. I modelli precedenti (GPT-1, GPT-2, BERT) non hanno mostrato questa capacità — il potere predittivo emerge come proprietà emergente dei grandi modelli.
BloombergGPT (2023) — un modello da 50 miliardi di parametri addestrato sul corpus finanziario di Bloomberg — ha dimostrato miglioramenti nel NER finanziario, nella classificazione delle notizie e nell'analisi del sentiment. FinGPT — la sua alternativa open-source — raggiunge l'89% di accuratezza nei compiti di sentiment finanziario usando un approccio data-centric e RAG.
MarketSenseAI, che utilizza GPT-4 con Chain-of-Thought e In-Context Learning per l'analisi dell'S&P 100, ha mostrato un alpha in eccesso del 10-30% e rendimenti cumulativi fino al 72% in 15 mesi di test. Sì, questi numeri vanno presi con cautela (backtest ≠ trading live), ma la tendenza è chiara.
Pipeline dei Dati: Dove Trovare i Dati
SEC EDGAR: La Fonte Ufficiale
Per le azioni statunitensi, la fonte primaria è SEC EDGAR. Le earnings call non vengono tipicamente depositate direttamente, ma i documenti correlati sono disponibili:
- Depositi 8-K (Item 2.02 — Risultati Operativi) — comunicati stampa con i risultati, spesso incluso l'allegato 99 con la trascrizione
- 10-Q / 10-K — relazioni trimestrali e annuali con Management Discussion & Analysis (MD&A) — anche questa è una preziosa fonte testuale
- DEF 14A — proxy statement con informazioni sulla remunerazione del management
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() # Testo completo con allegati
print(f"{filing.filing_date}: {len(text)} chars")
Seeking Alpha e API Commerciali
Le trascrizioni delle earnings call sono un prodotto separato. Seeking Alpha era storicamente la principale fonte gratuita, ma ora limita l'accesso. Opzioni commerciali:
- Seeking Alpha Premium API — trascrizioni complete con etichette dei relatori
- AlphaVantage Earnings API — tier gratuito con limitazioni
- Financial Modeling Prep — trascrizioni + dati fondamentali
- Earnings Call Edge / Motley Fool Transcripts — fonti alternative
Crypto: Governance Call e Proposte DAO
Qui le cose si fanno interessanti. I principali protocolli DeFi tengono il loro equivalente delle earnings call:
- Uniswap — governance call, community call, registrazioni su YouTube
- Aave — community call mensili + proposte nel forum di governance
- MakerDAO — governance call + ampie discussioni nei forum
- Compound — proposte di governance con discussioni dettagliate
Le trascrizioni delle call crypto sono solitamente non strutturate. La soluzione — Whisper di OpenAI per trascrivere le registrazioni YouTube:
import openai
from yt_dlp import YoutubeDL
def transcribe_governance_call(youtube_url: str) -> str:
"""Scarica l'audio da YouTube e trascrive tramite Whisper."""
ydl_opts = {
'format': 'bestaudio/best',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '64', # Basso bitrate sufficiente per il parlato
}],
'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
Il costo della trascrizione tramite l'API Whisper: 0.36. Per un'opzione self-hosted — Whisper Large-v3 Turbo trascrive un file da 60 minuti in ~17 secondi (216x real-time) su una GPU moderna.
Strategie di Prompting per LLM: Dal Naive al Production-Grade

Strategia 1: Sentiment Diretto (Debole)
L'approccio più ingenuo — chiedere direttamente al modello:
"Questa earnings call è positiva o negativa per il prezzo dell'azione?"
Funziona? Sì, sorprendentemente. Lopez-Lira & Tang hanno dimostrato che anche un prompt così primitivo produce previsioni statisticamente significative. Ma ci sono dei problemi:
- Output binario — si perdono le gradazioni. "Catastrofe" e "lieve delusione" ricevono la stessa etichetta
- Nessuna spiegazione — non è chiaro su cosa il modello abbia basato la sua decisione
- Instabilità — un'esecuzione ripetuta può dare una risposta diversa
Strategia 2: Estrazione Strutturata con Chain-of-Thought (Forte)
L'idea: invece di un singolo numero, estrarre un insieme strutturato di segnali, costringendo il modello a spiegare ogni passaggio.
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):
"""Deviazione della guidance prospettica dalle aspettative di consenso."""
revenue_guidance_vs_consensus: Optional[float] = Field(
None, description="% deviazione della guidance sui ricavi dal consenso"
)
margin_guidance_direction: Optional[str] = Field(
None, description="expanding / stable / contracting"
)
key_quote: str = Field(
description="Citazione testuale con la guidance"
)
reasoning: str = Field(
description="CoT: perché questa guidance è importante"
)
class ConfidenceMetrics(BaseModel):
"""Metriche di fiducia del management."""
hedge_word_count: int = Field(
description="Numero di parole di copertura: 'approximately', 'potentially', 'subject to'"
)
forward_looking_ratio: float = Field(
description="Rapporto tra dichiarazioni prospettiche e dichiarazioni totali"
)
q_and_a_evasion_count: int = Field(
description="Numero di domande a cui CEO/CFO ha dato una risposta evasiva"
)
ceo_vs_cfo_sentiment_delta: float = Field(
description="Differenza di sentiment tra CEO e CFO (da -1 a 1). La divergenza è un segnale d'allerta"
)
class CompetitiveIntelligence(BaseModel):
"""Menzioni di concorrenti e posizionamento di mercato."""
competitors_mentioned: list[str] = Field(
description="Elenco dei concorrenti menzionati"
)
market_share_claims: list[str] = Field(
description="Affermazioni sulla quota di mercato"
)
new_product_signals: list[str] = Field(
description="Segnali su nuovi prodotti/servizi"
)
class ManagementSignals(BaseModel):
"""Segnali del management."""
turnover_risk: SentimentLevel = Field(
description="Rischio di turnover del management chiave"
)
tone_shift_from_previous: Optional[str] = Field(
None, description="Come è cambiato il tono rispetto al trimestre precedente"
)
insider_language_flags: list[str] = Field(
description="Frasi marcatore: 'exploring strategic alternatives', 'right-sizing', ecc."
)
class EarningsCallAnalysis(BaseModel):
"""Analisi completa della earnings call."""
ticker: str
quarter: str
overall_sentiment: SentimentLevel
sentiment_score: float = Field(description="da -1.0 a 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:
"""
Estrae segnali strutturati da una earnings call.
Costo: ~$0.15-0.30 per call (GPT-4o, ~10K token in input).
"""
client = OpenAI()
system_prompt = """Sei un senior equity research analyst con 20 anni di esperienza.
Analizza la seguente trascrizione di earnings call ed estrai segnali di trading strutturati.
ISTRUZIONI IMPORTANTI:
1. Usa il ragionamento Chain-of-Thought per ogni campo — spiega il PERCHÉ prima di dare il valore
2. Concentrati sulle DEVIAZIONI dalle aspettative, non sulle dichiarazioni assolute
3. Presta particolare attenzione alla sezione Q&A — il management è meno preparato lì
4. Confronta il linguaggio del management con il baseline tipico della copertura aziendale
5. Segnala qualsiasi "strategic alternatives", "right-sizing" o altri eufemismi
6. Valuta il sentiment in relazione alle aspettative di mercato, non in termini assoluti
PAROLE DI COPERTURA DA CONTARE: 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, # Bassa temperatura per la riproducibilità
)
return completion.choices[0].message.parsed
Notiamo alcuni punti chiave:
Schema Pydantic — OpenAI Structured Outputs garantisce il 100% di conformità allo schema. Niente più "sorry, I cannot parse the JSON." Ogni campo ha una descrizione che funge da mini-prompt per un aspetto specifico dell'analisi.
Chain-of-Thought nello schema — i campi reasoning e key_quote costringono il modello a "mostrare il lavoro." Questo non solo migliora la qualità (il modello è costretto a trovare una citazione specifica prima di esprimere un giudizio), ma crea anche un audit trail per i regolatori.
Temperatura 0.1 — non vogliamo creatività. Vogliamo riproducibilità. A temperatura 0, il modello a volte si "blocca" in pattern; 0.1 è il compromesso ottimale.
Strategia 3: Few-Shot con Esempi Storici
Ancora più potente — fornire al modello esempi di earnings call passate con le reazioni di mercato effettive:
few_shot_examples = """
ESEMPIO 1:
Estratto della trascrizione: "Siamo cautamente ottimisti sulla seconda metà...
Mentre continuiamo a navigare i venti contrari macro, la nostra pipeline rimane robusta."
Reazione di mercato effettiva: -3.2% (giorno successivo)
Analisi: Nonostante la positività superficiale, "cautamente ottimisti" è un
DOWNGRADE rispetto al "molto fiduciosi" del trimestre precedente. Cinque parole di
copertura in due frasi. Il mercato ha letto attraverso le coperture.
ESEMPIO 2:
Estratto della trascrizione: "Francamente, la domanda ha superato la nostra capacità di offerta.
Stiamo accelerando il CapEx per affrontarlo."
Reazione di mercato effettiva: +7.8% (giorno successivo)
Analisi: "Francamente" segnala una vera sorpresa anche da parte del management.
CapEx accelerato sulla domanda = forte fiducia. Nessun linguaggio di copertura.
"""
Gli esempi few-shot aiutano il modello a calibrarsi: impara che "cautamente ottimisti" nel linguaggio di Wall Street non è positivo — è un negativo soft. Senza esempi, l'LLM potrebbe interpretare le parole letteralmente.
Quattro Tipi di Segnali
1. Guidance Surprise
Il segnale più diretto. Un'azienda fornisce una previsione (guidance) per il prossimo trimestre/anno e il mercato reagisce alla deviazione dal consenso. Un LLM può estrarre la guidance anche quando il management la comunica in modo vago:
- "Ci aspettiamo ricavi nell'intervallo di..." — guidance diretta, facile da analizzare
- "Siamo a nostro agio con le stime attuali di Street" — conferma implicita del consenso
- "Ci sono put e take rispetto al consenso" — segnale di rischio implicito
Un LLM capisce tutte e tre le formulazioni; regex capisce solo la prima.
2. Metriche di Fiducia: Densità delle Parole di Copertura
Questo è il mio segnale preferito perché è controintuitivo. L'essenza: i manager sono persone con una formazione legale e dipartimenti legali paranoici. Quando le cose vanno bene, si permettono di essere specifici. Quando si profilano problemi — iniziano a coprirsi.
Metriche da monitorare:
| Metrica | Descrizione | Segnale Ribassista |
|---|---|---|
| Densità parole di copertura | Quota di parole di copertura per 1.000 parole | > 15 per 1.000 parole |
| Rapporto di certezza | Rapporto tra "will/expect" e "may/could" | < 1.5 |
| Tasso di evasione Q&A | % di domande senza risposta diretta | > 30% |
| Delta CEO/CFO | Divergenza di tono tra CEO e CFO | > 0.3 su scala [-1, 1] |
L'ultimo punto è particolarmente interessante. Il CEO è uno storyteller — il suo lavoro è dipingere un bel quadro. Il CFO è quello responsabile verso i revisori. Quando il CEO dice "crescita trasformativa in arrivo" e il CFO interviene immediatamente con "mantenendo una gestione disciplinata dei costi" — questa divergenza segnala tensioni interne.
3. Competitive Intelligence
Un LLM può estrarre le menzioni dei concorrenti da una trascrizione, anche quando il management evita i nomi diretti. "Il player più grande del mercato" — non è un mistero per GPT-4 se conosce il settore.
Segnale di trading: se l'azienda A menziona il concorrente B in un contesto negativo durante la sua earnings call ("stiamo prendendo quota da..."), questo è un segnale non solo per A (long) ma anche per B (short). Un pairs trade.
4. Segnali di Turnover del Management
Frasi marcatore per cambiamenti del management o pivot strategici:
- "Exploring strategic alternatives" — probabile vendita dell'azienda
- "Right-sizing our operations" — licenziamenti di massa
- "The board has initiated a comprehensive review" — il CEO se ne andrà presto
- "We're bringing in fresh perspectives" — il team attuale ha fallito
Ciascuna di queste frasi ha una correlazione statisticamente significativa con le dinamiche di prezzo successive. Un LLM può rilevarle con zero falsi positivi — perché capisce il contesto, a differenza di regex che potrebbe catturare "strategic alternatives" nella descrizione di una linea di prodotti.
Backtesting: Metodologia dell'Event Study

Stiamo generando segnali — ottimo. Ma funzionano? Il metodo di verifica standard è un Event Study con il calcolo dei Cumulative Abnormal Returns (CAR).
Metodologia
- Definire l'evento — la data della earnings call
- Finestra di stima — [-250, -30] giorni di trading prima dell'evento per stimare i rendimenti "normali"
- Finestra dell'evento — [-1, +60] giorni intorno all'evento
- Calcolare i rendimenti normali tramite il modello di mercato:
- Rendimento anomalo — la differenza tra i rendimenti effettivi e quelli "normali"
- CAR — somma cumulativa dei rendimenti anomali nella finestra dell'evento
import numpy as np
import pandas as pd
from scipy import stats
from dataclasses import dataclass
@dataclass
class EventStudyResult:
car: np.ndarray # Rendimenti anomali cumulativi per giorno
t_stats: np.ndarray # t-statistiche per ogni giorno
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, # Rendimenti giornalieri delle azioni (colonne = ticker)
market_returns: pd.Series, # Rendimenti giornalieri dell'indice di mercato
events: pd.DataFrame, # DataFrame con colonne: [ticker, date, signal_score]
estimation_window: int = 220,
gap: int = 30,
event_window: tuple = (-1, 60),
) -> EventStudyResult:
"""
Event study per valutare il potere predittivo dei segnali LLM.
Ordina gli eventi per signal_score, forma portafogli long/short,
calcola il CAR e testa la significatività statistica.
"""
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: # Minimo 60 osservazioni
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("Nessun evento valido trovato")
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 alla data dell'evento
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 quintile superiore dei segnali, short quintile inferiore."""
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"Portafoglio LONG (quintile superiore sentiment LLM):")
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 eventi: {long_result.n_events}")
print(f"\nPortafoglio SHORT (quintile inferiore sentiment LLM):")
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 eventi: {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"\nSpread LONG-SHORT:")
print(f" CAR[0,+3]: {ls_3d:+.2%}")
print(f" CAR[0,+30]: {ls_30d:+.2%}")
Cosa Ci Aspettiamo di Vedere
Basandosi sulla ricerca esistente, CAR realistici per i segnali LLM:
| Finestra | Portafoglio long | Portafoglio 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'indicatore chiave è la significatività statistica. Con p < 0.01 e N > 200 eventi, si può parlare di un segnale robusto. Con p > 0.05 — potrebbe essere rumore.
Implementazione in Produzione: Da Jupyter a Prod
Architettura della Pipeline Real-time
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)│
└──────────────────────────────┘
Analisi dei Costi: Quanto Costa una Earnings Call
Analizziamo l'economia dell'elaborazione di una singola earnings call in produzione:
| Componente | Costo | Latenza |
|---|---|---|
| Trascrizione Whisper API (60 min) | $0.36 | ~17 sec (Turbo) |
| Estrazione strutturata GPT-4o | $0.15-0.30 | ~8-15 sec |
| Analisi chunk real-time GPT-4o (x12) | $1.80-3.60 | ~5 sec ciascuno |
| Embedding per storage RAG | $0.01 | <1 sec |
| Totale (pipeline completa) | $2.30-4.30 | ~30 sec completo |
Aspetta, la stima era $30-50 per call. Da dove vengono quei numeri? Dipende dal modello e dall'approccio:
- Opzione budget (GPT-4o-mini, singolo passaggio): $0.50-1.00
- Opzione standard (GPT-4o, estrazione strutturata + analisi chunk): $2-5
- Opzione premium (GPT-4o, passaggi multipli, cross-validazione, confronto storico): $15-30
- Qualità hedge-fund (modelli multipli + revisione umana + streaming real-time): $30-50+
Per un fondo quant che fa trading su 500 ticker, il costo di elaborazione di una stagione di earnings (~2.000 call in 6 settimane) è 10.000 con l'opzione standard. Considerando un alpha medio per posizione dell'1-3% — il ROI è astronomico.
Latenza: La Corsa ai Millisecondi
Nel mondo dell'HFT, la latenza è tutto. Ma per le strategie basate sugli earnings, la situazione è diversa:
- Una earnings call dura 45-60 minuti — hai tempo
- Il PEAD si estende su 60 giorni — non è necessario entrare nel primo secondo
- La principale dislocazione avviene nei primi 30 minuti dopo la fine della call
La strategia ottimale è a due fasi:
- Fase 1 (real-time): analizzare frammenti da 5 minuti durante la call, formando un segnale preliminare
- Fase 2 (post-call): analisi completa dell'intera trascrizione 2-5 minuti dopo la fine
La Fase 1 fornisce un vantaggio di 5-10 minuti rispetto ai partecipanti al mercato che aspettano la fine della call. Per le mid-cap, questo è sufficiente.
Espansione al Crypto: Governance DeFi e Proposte DAO
Il mercato crypto è un terreno di test ideale per il LLM alpha mining. Ecco perché:
- Meno player istituzionali — il che significa più inefficienza da sfruttare
- Governance = earnings call — le decisioni DAO influenzano direttamente la tokenomics
- Mercato 24/7 — è possibile fare trading sulla reazione immediatamente
- Dati pubblici — tutte le proposte e i voti sono on-chain
Tipi di Eventi Crypto per l'Analisi
Proposte di Governance (Aave, Compound, Uniswap)
Una proposta cambia i parametri del protocollo — tassi di interesse, fattori di collaterale, fee switch. Un LLM può valutare l'impatto economico:
crypto_analysis_prompt = """Analizza questa proposta di governance DeFi.
Estrai:
1. Impatto economico sui detentori di token (positivo/negativo/neutro)
2. Stima dell'impatto sul TVL (aumento/diminuzione/stabile + entità)
3. Posizionamento competitivo rispetto ad altri protocolli
4. Fattori di rischio introdotti dalla proposta
5. Precedente storico (proposte simili in altri protocolli)
6. Probabile esito della votazione basato sul sentiment della discussione nel forum
Proposta: {proposal_text}
Discussione nel forum: {discussion_text}
"""
Annunci di Aggiornamento del Protocollo
Quando Uniswap annuncia la v4 con gli hook, o Aave lancia GHO — è l'equivalente di un lancio di prodotto nel TradFi. Un LLM può valutare il momentum narrativo e la rilevanza tecnica.
Report del Tesoro
Le grandi DAO hanno tesorerie che valgono centinaia di milioni. I report trimestrali del tesoro sono un diretto analogo degli earnings. Runway, burn rate, diversificazione — tutto si presta all'analisi LLM.
Specificità dei Segnali Crypto
A differenza del TradFi, nel crypto:
- I dati on-chain confermano o contraddicono la narrativa — è possibile incrociare ciò che viene detto nelle governance call con le metriche effettive del protocollo (TVL, volume, utenti attivi)
- I wallet whale come insider trading — i movimenti di grandi wallet dopo le discussioni di governance spesso precedono le votazioni
- Amplificazione del sentiment tramite CT (Crypto Twitter) — un segnale da una governance call può essere amplificato o soppresso dalle narrative di Twitter
Insidie e Limitazioni
Allucinazioni: Quando il Modello Inventa Numeri
Un LLM può "estrarre" guidance che non era nella trascrizione. Questo è particolarmente pericoloso quando si analizza la densità delle parole di copertura: il modello potrebbe contare più o meno parole di quante ne esistano realmente.
Soluzione: verifica in due fasi. L'LLM estrae, il codice deterministico verifica. Per le parole di copertura — conteggio regex in parallelo con la valutazione LLM. Deviazione > 20% — flag per revisione manuale.
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:
"""Verifica deterministica del conteggio delle parole di copertura dell'LLM."""
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,
}
Limitazioni della Finestra di Contesto
Anche 128K token potrebbero non essere sufficienti se si vuole inserire:
- Trascrizione corrente (~10K token)
- Trascrizione precedente per il confronto (~10K)
- Previsioni di consenso degli analisti (~2K)
- Esempi few-shot (~3K)
- System prompt (~1K)
Totale ~26K — ci stiamo. Ma se aggiungi un deposito 10-K (~80-120K token) per il contesto — sei già al limite. Soluzione: RAG per recuperare i frammenti rilevanti da documenti lunghi.
Bias ed Errori Sistematici
Gli LLM sono addestrati su dati storici in cui certe frasi erano associate a certi esiti. Ma il mercato si adatta:
- Se tutti iniziano a contare le parole di copertura con GPT-4, i manager cambieranno il loro linguaggio
- Il modello potrebbe sovrastimare la rilevanza dei pattern dai dati di addestramento (survivorship bias)
- Il linguaggio aziendale evolve: "synergies" nel 2010 significava una cosa, nel 2026 — un'altra
Rischio di Crowded Trade
Se 50 fondi quant usano lo stesso GPT-4 per analizzare le stesse trascrizioni — il segnale si deteriora. Un'analogia: quando tutti hanno iniziato a fare trading sul PEAD sulle sorprese numeriche, l'anomalia si è ridotta. Lo stesso accadrà con i segnali testuali, ma con un ritardo:
- Ora (2026) — pochi usano sistematicamente gli LLM per le earnings call. L'alpha è significativo
- Tra 2-3 anni — adozione diffusa, l'alpha diminuisce
- Tra 5 anni — i segnali LLM di base diventano una commodity, il vantaggio persiste solo nei modelli personalizzati e nei dati unici
Questo è il ciclo di vita standard del segnale alpha. Goditelo finché dura.
Al Posto di una Conclusione: Un Piano d'Azione
Se vuoi iniziare a usare gli LLM per l'analisi delle earnings call, ecco un piano minimo praticabile:
- Inizia con dati gratuiti — SEC EDGAR + EdgarTools per i depositi 8-K/10-Q
- Usa l'estrazione strutturata — schemi Pydantic tramite OpenAI Structured Outputs
- Backtesta tramite event study — CAR su dati storici, minimo 200 eventi
- Aggiungi esempi few-shot — 5-10 esempi etichettati migliorano radicalmente la qualità
- Verifica deterministicamente — LLM estrae, regex verifica, umano controlla
- Inizia con le mid-cap — più alpha, meno concorrenza con i fondi principali
- Espandi al crypto — governance call e proposte DAO come territorio inesplorato
Ricorda la regola cardinale dell'analisi quantitativa: se un segnale sembra troppo bello per essere vero — controlla di nuovo. Gli LLM creano un'illusione di comprensione, ma dietro si nasconde il pattern matching statistico. Uno strumento potente — ma uno strumento, non un oracolo.
Bibliografia
-
Ball, R., Brown, P. (1968). An Empirical Evaluation of Accounting Income Numbers. Journal of Accounting Research, 6(2), 159-178. — Prima scoperta del PEAD.
-
Bernard, V.L., Thomas, J.K. (1989). Post-Earnings-Announcement Drift: Delayed Price Response or Risk Premium? Journal of Accounting Research, 27, 1-36. — Paper canonico sul PEAD.
-
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. — Dizionario di sentiment finanziario.
-
Araci, D. (2019). FinBERT: Financial Sentiment Analysis with Pre-trained Language Models. arXiv:1908.10063. — BERT per il NLP finanziario, +14pp rispetto allo SOTA.
-
Wu, S. et al. (2023). BloombergGPT: A Large Language Model for Finance. arXiv:2303.17564. — Modello da 50 miliardi di parametri di Bloomberg.
-
Yang, H. et al. (2023). FinGPT: Open-Source Financial Large Language Models. arXiv:2306.06031. — Alternativa open-source a BloombergGPT, 89% di accuratezza.
-
Lopez-Lira, A., Tang, Y. (2023). Can ChatGPT Forecast Stock Price Movements? Return Predictability and Large Language Models. arXiv:2304.07619. — GPT-4 prevede i rendimenti con ~90% di hit rate.
-
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. — Il PEAD testuale è due volte più grande del PEAD numerico.
-
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 con 10-30% di alpha in eccesso sull'S&P 100.
-
Chen, Y. et al. (2025). GPT-Signal: Generative AI for Semi-automated Feature Engineering in the Alpha Research Process. arXiv:2410.18448. — Generazione automatica di segnali di trading tramite LLM.
-
Zhang, X. et al. (2025). Can LLMs Hit Moving Targets? Tracking Evolving Signals in Corporate Disclosures. arXiv:2510.03195. — Rilevamento di "moving target" nelle comunicazioni aziendali.
-
Chen, Z. et al. (2025). Large Language Models in Equity Markets: Applications, Techniques, and Insights. Frontiers in Artificial Intelligence. — Rassegna di 84 studi LLM in finanza.
Questo articolo ha natura educativa e non costituisce consulenza sugli investimenti. Qualsiasi strategia di trading descritta qui richiede un approfondito backtesting e una gestione del rischio prima dell'utilizzo con capitale reale.
Autori
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.