Sentiment Analysis for Trading: News, Social Media and NLP
Sentiment analysis converts unstructured text — news, social posts, filings, earnings-call transcripts — into point-in-time numeric signals. The premise is narrow but real: prices move on information, much of it arrives first as text, and a desk that reads and quantifies that text faster or more accurately than the crowd owns a brief window before it is priced. The craft is far less about the scoring model than about timestamp integrity, entity resolution, and proving the signal survives crowding and costs. It is one branch of alternative data.
Sources, ranked by tradeability
| Source | Latency | Signal quality | Main hazard |
|---|---|---|---|
| News wires | Seconds-minutes | Clean, timely | Heavily crowded |
| Social (X, Reddit, Telegram) | Real-time | Noisy, leads retail names | Bots, manipulation |
| Filings / 10-K, 10-Q | Hours-days | Dense, durable | Slow; needs careful NLP |
| Earnings-call transcripts | Minutes-hours | High value | Parsing, speaker attribution |
| Analyst actions | Event-driven | Strong short-term | Crowded, embargoed |
News is timely but everyone reads it; social media is manipulable but can front-run news on retail-driven and crypto names; filings and transcripts are slower but reward NLP because subtle shifts in management tone (hedging language, withdrawn guidance) can precede fundamentals. A real program blends sources weighted by demonstrated reliability for the traded universe.
The pipeline, with the two underrated steps
- Collect with an honest availability timestamp (not publication time).
- Clean — dedupe, strip boilerplate, filter bots.
- Resolve entities — map "Apple", "AAPL", "$AAPL" to one security; reject the
fruit. This is where most signal is won or lost.
- Score — finance lexicon for breadth, transformer/LLM for nuance.
- Aggregate — per asset, per window, decayed and normalized.
The two steps practitioners underweight are collection (timestamps) and aggregation (entity resolution plus sensible windows). Both dominate the choice of scoring model.
import pandas as pd
def sentiment_features(df, decay="6h"):
"""df: columns [available_ts, asset, score in [-1,1]]. Strictly point-in-time."""
df = df.sort_values("available_ts")
out = {}
for asset, g in df.groupby("asset"):
s = g.set_index("available_ts")["score"]
tone = s.ewm(halflife=decay).mean().resample("1h").last() # decayed tone
mentions = s.resample("1h").count() # attention
att_z = (mentions - mentions.rolling(72).mean()) / mentions.rolling(72).std()
feat = pd.DataFrame({"tone": tone, "attention_z": att_z})
out[asset] = feat.shift(1) # lag one bar: decide at t using <= t-1
return out
Two disciplines are baked in: tone decays exponentially (an hour-old tweet outweighs a day-old one), and the final shift(1) prevents same-bar leakage.
Lexicons vs. transformers vs. LLMs
Generic sentiment tools fail in finance because they flag "liability", "tax", "cost", and "capital" as negative when they are neutral accounting terms. The Loughran-McDonald finance lexicon fixes the obvious cases cheaply and transparently — you can see exactly which words drove a score. Transformer models and LLMs grasp context ("not bad" is positive, "guidance was cut" is negative without a negative word), handle negation and sarcasm, and can extract structured events ("CEO resigned", "FDA approval") or classify stance toward a specific entity. The cost is compute, latency, and opacity.
| Loughran-McDonald lexicon | Transformer / LLM | |
|---|---|---|
| Context & negation | Poor | Strong |
| Speed / cost | Fast, cheap | Slow, costly |
| Transparency | High (word-level) | Low (black box) |
| Best for | Broad, low-latency coverage | High-value, nuanced text |
A common production pattern: cheap lexicons for broad real-time coverage, LLM passes reserved for high-value text like earnings calls and filings. Whatever the scorer, the output is just one weak feature among many.
Attention often beats polarity
A spike in mention volume is frequently more predictive than tone, because attention is what moves prices and is a cleaner measurement than contested polarity. When mentions of a ticker jump 10x in an hour, volatility and volume tend to follow regardless of whether the crowd has labeled the news good or bad. An attention z-score is also harder to manipulate at scale and easier to compute reliably. Many profitable text signals are, at their core, attention spikes used to anticipate volatility rather than direction — which makes them a natural input to a volatility-targeting overlay rather than a directional bet.
The pitfalls that actually lose money
- Timestamp / look-ahead error. The most dangerous and most invisible. Vendors
stamp publication time, but you only received the item after crawling. Backtesting on publication time pretends you reacted instantly, manufacturing a phantom edge. Worse, edited headlines and deleted posts mean your store may hold a revised version; trading that is trading the future. Store an availability timestamp per record and query strictly point-in-time; see backtesting biases.
- Manipulation. Social feeds are gamed by bot networks and paid promotion designed
to manufacture the very attention spike your signal keys on, especially in crypto. Without bot detection, source-reputation weighting, and de-duplication, your "signal" is someone else's pump script.
- Crowding and decay. Popular sentiment datasets are arbitraged fast; assume the
edge is temporary and monitor it.
- Survivorship in text. Deleted posts and pulled articles vanish from history.
Validating a text signal
Before any modeling, check whether the signal carries information at all with a stable information coefficient (rank correlation of signal to forward return), measured out-of-sample and by year:
import pandas as pd
def ic_by_year(signal: pd.Series, fwd_ret: pd.Series) -> pd.Series:
df = pd.concat([signal, fwd_ret], axis=1).dropna()
df.columns = ["sig", "ret"]
return df.groupby(df.index.year).apply(
lambda g: g["sig"].corr(g["ret"], method="spearman"))
# A stable IC of 0.02-0.05 across years is useful at scale.
# An IC of 0.20 on one year of data is a red flag for overfitting or leakage.
A signal whose IC was strong years ago and has flattened since is a crowded, dead edge, not a live one. Judge the final combination on net, after-cost Sharpe under walk-forward testing.
Event-study evaluation before any model
The cleanest first test of a text signal is an event study, not a backtest. Align every sentiment event to its availability timestamp and measure the average cumulative abnormal return in the minutes and hours after the event, bucketed by signal strength. If there is a real edge, you will see a monotonic, decaying drift that begins after the availability time; if the drift begins before, you have a timestamp leak. The event study also reveals the signal's natural horizon, which dictates holding period and cost budget.
import numpy as np, pandas as pd
def event_drift(events: pd.Series, prices: pd.Series, horizon=12):
"""Mean forward return after each event, by hour. events: availability_ts -> sign."""
logp = np.log(prices)
rows = []
for ts, side in events.items():
window = logp.loc[ts:].iloc[:horizon + 1]
if len(window) > 1:
rows.append(side * (window.values[1:] - window.values[0]))
arr = pd.DataFrame(rows)
return arr.mean() # cumulative abnormal return path; drift must start AFTER t
A drift that is statistically flat once you account for transaction costs means the signal is real but untradeable — a common and important negative result.
Aggregation depth: the part that actually scales
Entity resolution and aggregation windows quietly determine whether a sentiment program works at scale. Cashtag matching ("$AAPL") is high-precision but low-recall; named-entity recognition over article bodies catches far more but introduces false positives that must be filtered by context. Once resolved, you must collapse many noisy, bursty scores into a stable per-asset series — and the aggregation window is a real hyperparameter. Too short and the signal is pure noise; too long and it lags the event it is supposed to anticipate. Weight by source reputation, decay by recency, and normalize cross-sectionally so a mega-cap with constant coverage is comparable to a small-cap that is silent until it is not. None of this is glamorous, but it is where most of the realized edge is won.
Combining sentiment with price
Sentiment rarely stands alone — its edge is small, noisy, and decaying. It earns its keep as a conditioning input inside a machine-learning model: a momentum breakout backed by a genuine attention spike is more trustworthy than one in silence; a mean-reversion setup is more dangerous when sentiment is screaming with the move. Feed tone, tone change, and attention z-score into a tree model alongside price, volatility, and order-flow features and let the model learn the interactions rather than hand-coding them.
Cross-sectional vs. single-name use
As with most weak signals, sentiment is far more robust used cross-sectionally than as a single-name timer. Ranking a universe by attention-adjusted tone each day and trading the spread between the top and bottom buckets diversifies away the enormous idiosyncratic noise in any one ticker's text, and it neutralizes market-wide sentiment waves that would otherwise swamp the relative signal. A per-name tone score with an IC of 0.02 is nearly useless alone but can support a respectable information ratio across a few hundred names. Normalize tone cross-sectionally within each date so that a perpetually-covered mega-cap is comparable to a quiet small-cap, and be careful that coverage itself is not the signal — attention concentrates in volatile names, so an uncontrolled tone factor can secretly become a volatility bet.
Realistic expectations
Expect a low, decaying IC, a short half-life, and a hard dependence on execution speed and cost. Event-driven, attention-based use around earnings and in crypto is where text most reliably pays; broad directional alpha from polarity alone is largely arbitraged. The durable advantage is operational: honest timestamps, clean entity resolution, robust bot filtering, and disciplined point-in-time backtesting.
Conclusion
Sentiment analysis is a genuine but narrow form of alternative data, strongest around events and in attention-driven crypto markets. The edge lives in the unglamorous fundamentals — availability timestamps, entity resolution, bot filtering, and treating mention volume as seriously as tone — not in the choice of model. Mind timestamps, manipulation, and decay, treat sentiment as a complement to price-based signals, and combine it with volatility and order-flow features through disciplined feature engineering.
