---
name: market_sentiment_analysis
description: Turns news and social chatter into tradeable signals: builds a sentiment pipeline (collect, score, weight sources, aggregate), dodges the classic echo traps, and backtests whether the signal would have made money. Triggers when someone wants to trade on market sentiment, build a news-driven signal, or evaluate a sentiment data product.
---

# Market Sentiment Analysis

## Purpose

Convert raw text (news headlines, social posts, forum threads, earnings-call tone) into a measured signal an agent can trade on or report with confidence bounds. The skill covers the full workflow: what to collect, how to score it, how to weight sources against each other, how to keep volume from faking out polarity, and how to backtest the signal honestly so you know what it is worth before risking anything.

## Workflow

1. **Define the trade.** Pick the asset or basket, the holding horizon (intraday, daily, weekly), and the decision the signal must drive (long/short, size up/down, or just an alert). Sentiment decays fast: realistic half-lives run 6-12 months, and expected net alpha is small after costs, so the horizon dictates everything downstream.
2. **Collect with timestamps.** Pull headlines and posts with exact publication timestamps, source name, and author where available. Cutoffs matter: a headline timestamped after the market move it describes is noise, not signal. Headline vs. body sentiment can diverge, so record both when you have them.
3. **Score the text.** Pick one scoring method per text type and stick with it (see `references/models.md`). Financial headlines get FinBERT; short social posts get VADER; long nuanced text gets a prompted LLM with a frozen prompt. Score on a fixed scale (-1 to +1) so sources stay comparable.
4. **Weight sources, don't average them.** Every source has a known bias (see `references/source-weighting.md`). Start from evidence-based weights: regulatory filings and earnings announcements near the top, financial news in the middle, social chatter low, unverified rumors out entirely. Re-fit weights quarterly by regressing each source's signal against forward returns.
5. **Aggregate with volume.** Track two series per asset: polarity (weighted mean score) and volume (item count per window, vs. baseline). A small surge of intense negative posts often moves prices more than a steady drift in polarity. Flag coordinated spikes (bot-like timing, duplicate phrasing) and discount them.
6. **Build the signal.** Convert the daily score into a z-score against a rolling baseline (this product vs. its own history, this period vs. prior period). Trade the *change*, not the level: enter when the z-score crosses a threshold, exit when it reverts. Keep the parameter count small (threshold, window, hold time).
7. **Backtest honestly.** Rules are non-negotiable: decide on bar t, execute on bar t+1 open (no look-ahead); include delisted assets (no survivorship bias); model fees and slippage on every trade; walk-forward validate with a 70/30 in-sample/out-of-sample split and require OOS metrics to hold at 80%+ of in-sample; demand 100+ trades before trusting Sharpe. See `references/backtest-gates.md`.
8. **Run the reference implementation.** `scripts/sentiment_pipeline.py` is a working end-to-end pipeline (ingest CSV, lexicon score, source-weight, aggregate, backtest with no look-ahead, report metrics). Use it as the template for real integrations.

## Output Contract

A finished sentiment-signal package contains:
- **Signal spec:** asset, horizon, scoring method per source type, source weights with the evidence behind them, aggregation window, entry/exit thresholds.
- **Backtest report:** trades, win rate, profit factor, Sharpe, max drawdown, CAGR, in-sample vs. out-of-sample comparison, cost assumptions used.
- **Live-monitoring plan:** what decay looks like, re-fit cadence, kill thresholds (e.g. OOS Sharpe drops below half the backtest value, auto-halt).
- **Caveat sheet:** every claim framed with its confidence. Sentiment is a secondary signal, never standalone alpha. Unverified claims are cut, not shipped.

## Operating Rules

1. Every factual claim in a signal report must be verifiable: cite the data window, the source, and the backtest metrics behind it. Never invent numbers, quotes, or events.
2. Sentiment numbers without a baseline are meaningless. Always report "X vs. its own 30-day baseline", never bare scores.
3. Never average sources naively. An unweighted mean of news + tweets is a vibes metric, not a signal.
4. Never trade on sentiment alone. Pair it with price/market context (momentum, volatility regime); in high-volatility regimes, weight market data above sentiment.
5. No look-ahead, ever. If the backtest cannot be explained as "decided at t, executed at t+1 open", it is invalid.
6. Paper-trade before live. A good backtest that fails paper trading within 20% is a bad backtest.
7. Frame limits plainly. Say "the signal faded after 8 months in the OOS window" instead of hiding it.

## Quickstart (dry run)

```bash
cd ~/workspace/skills/market-sentiment-analysis
python3 scripts/sentiment_pipeline.py --demo
```

Runs the full pipeline on synthetic data: 90 days of headlines, lexicon scoring, source weighting, daily aggregation, and a no-look-ahead backtest with cost modeling. Expect a modest positive gross result that shrinks toward zero after costs, which is exactly the lesson: gross alpha is not net alpha.
