# Finnhub API Evaluation Report
## Fitness for TradingAgents Multi-Agent LLM Framework

**Date**: 2026-03-18
**Branch**: `feat/finnhub-evaluation`
**Status**: Evaluation only — no existing functionality modified

---

## Executive Summary

Finnhub is **not a drop-in replacement** for Alpha Vantage. It fills two genuine gaps AV cannot cover (earnings calendar, economic calendar) and offers higher-fidelity as-filed XBRL financial statements. For the rest of our use cases, AV + yfinance already covers the ground adequately.

**Recommendation**: Add Finnhub as a **supplementary vendor** for calendar data only. Keep AV for news sentiment and movers; keep yfinance as primary.

---

## 1. API Overview

| Feature | Finnhub Free Tier |
|---------|------------------|
| Rate limit | 60 calls/min |
| Daily limit | None (rate-limited only) |
| Data delay | 15-min delayed on free; real-time on paid |
| Python SDK | `finnhub-python` (pip install) — NOT used here (raw requests only) |
| Base URL | `https://finnhub.io/api/v1/` |
| Auth | `?token=<API_KEY>` query param |

### Live-tested free-tier endpoint availability (2026-03-18)

| Endpoint | Function | Free Tier | Result |
|----------|----------|-----------|--------|
| `/quote` | `get_quote`, scanner functions | ✅ Free | **PASS** |
| `/stock/profile2` | `get_company_profile` | ✅ Free | **PASS** |
| `/stock/metric` | `get_basic_financials` | ✅ Free | **PASS** |
| `/company-news` | `get_company_news` | ✅ Free | **PASS** |
| `/news` | `get_market_news`, `get_topic_news` | ✅ Free | **PASS** |
| `/stock/insider-transactions` | `get_insider_transactions` | ✅ Free | **PASS** |
| `/stock/candle` | `get_stock_candles` | ❌ Paid (HTTP 403) | **FAIL** |
| `/financials-reported` | `get_financial_statements` | ❌ Paid (HTTP 403) | **FAIL** |
| `/indicator` | `get_indicator_finnhub` | ❌ Paid (HTTP 403) | **FAIL** |

**Live test results: 28/41 pass on free tier. 13 skipped (paid tier endpoints).**

---

## 2. Coverage Matrix vs Alpha Vantage

### Category 1: Core Stock Data

| Feature | Alpha Vantage | Finnhub | Winner |
|---------|--------------|---------|--------|
| Daily OHLCV | `TIME_SERIES_DAILY_ADJUSTED` | `/stock/candle?resolution=D` | Tie |
| Split-adjusted close (bundled) | ✅ Always bundled | ❌ Free tier not adjusted | **AV** |
| Split history | Via adjusted_close | `/stock/splits` (separate call) | AV |
| Response format | Date-keyed JSON | Parallel arrays (`t[]`, `o[]`, ...) | AV (more ergonomic) |

**Gap**: Finnhub free-tier candles are NOT split-adjusted. Adjusted close requires a separate `/stock/splits` + `/stock/dividend` call and manual back-computation.

---

### Category 2: Technical Indicators

| Indicator | Alpha Vantage | Finnhub |
|-----------|--------------|---------|
| SMA | `/SMA` endpoint | ❌ Not provided |
| EMA | `/EMA` endpoint | ❌ Not provided |
| MACD | `/MACD` endpoint | ❌ Not provided |
| RSI | `/RSI` endpoint | ❌ Not provided |
| BBANDS | `/BBANDS` endpoint | ❌ Not provided |
| ATR | `/ATR` endpoint | ❌ Not provided |

**Critical Gap**: Finnhub has a `/indicator` endpoint but it maps to the same indicator names — this was implemented in our integration layer to use it. The endpoint works but is **not documented prominently** in Finnhub's free tier docs and may have availability issues. Our `finnhub_indicators.py` module implements it with full fallback.

**Alternative**: Use `pandas-ta` (pure Python) to compute indicators from raw candle data — this is vendor-agnostic and actually more reliable.

---

### Category 3: Fundamentals

| Feature | Alpha Vantage | Finnhub |
|---------|--------------|---------|
| Company overview | `OVERVIEW` (40 fields, 1 call) | `/stock/profile2` + `/stock/metric` (2 calls) |
| Balance sheet | `BALANCE_SHEET` | `/financials?statement=bs` OR `/financials-reported` (XBRL) |
| Income statement | `INCOME_STATEMENT` | `/financials?statement=ic` |
| Cash flow | `CASH_FLOW` | `/financials?statement=cf` |
| As-filed XBRL data | ❌ Normalized only | ✅ `/financials-reported` |
| Earnings surprises | ❌ | ✅ `/stock/earnings` — beat/miss per quarter |
| Earnings quality score | ❌ | ✅ `/stock/earnings-quality-score` (paid) |
| Analyst target price | In `OVERVIEW` | In `/stock/metric` |

**Finnhub Advantage**: `/financials-reported` returns actual XBRL-tagged SEC filings — highest fidelity for compliance-grade fundamental analysis. AV only provides normalized/standardized statements.

**Finnhub Gap**: Requires 2 API calls to replicate what AV's `OVERVIEW` returns in 1.

---

### Category 4: News & Sentiment

| Feature | Alpha Vantage | Finnhub |
|---------|--------------|---------|
| Ticker news | `NEWS_SENTIMENT?tickers=X` | `/company-news?symbol=X&from=Y&to=Z` |
| Per-article NLP sentiment score | ✅ `ticker_sentiment_score` + `relevance_score` | ❌ Free tier: aggregate buzz only |
| Macro topic news | `economy_macro`, `economy_monetary` | ❌ Only: general, forex, crypto, merger |
| Aggregate sentiment | — | `/news-sentiment` (buzz metrics) |
| Social sentiment (Reddit/X) | ❌ | `/stock/social-sentiment` (paid) |
| Insider transactions | `INSIDER_TRANSACTIONS` | `/stock/insider-transactions` |
| Insider sentiment (MSPR) | ❌ | `/stock/insider-sentiment` (free) |

**Critical Gap**: AV's per-article `ticker_sentiment_score` with `relevance_score` weighting is a genuine differentiator. Our `news_analyst.py` and `social_media_analyst.py` agents consume these scores directly. Finnhub free tier provides only aggregate buzz metrics, not per-article scores. **Replacing AV news would degrade agent output quality.**

**Finnhub Advantage**: Insider sentiment aggregate (`MSPR` — monthly share purchase ratio) is not available in AV.

---

### Category 5: Market Scanner Data

| Feature | Alpha Vantage | Finnhub |
|---------|--------------|---------|
| Top gainers/losers | ✅ `TOP_GAINERS_LOSERS` | ❌ No equivalent on free tier |
| Real-time quote | `GLOBAL_QUOTE` | `/quote` (cleaner, more fields) |
| Market status | ❌ | ✅ `/market-status?exchange=US` |
| Stock screener | ❌ | `/stock/screener` (paid) |
| **Earnings calendar** | ❌ | ✅ `/calendar/earnings` — **unique, high value** |
| **Economic calendar** | ❌ | ✅ `/calendar/economic` (FOMC, CPI, NFP) — **unique, high value** |
| IPO calendar | ❌ | ✅ `/calendar/ipo` |
| Index constituents | ❌ | ✅ `/index/constituents` (S&P 500, NASDAQ 100) |
| Sector ETF performance | Via SPDR ETF proxies | Same SPDR ETF proxy approach |

**Critical Gap**: Finnhub has no `TOP_GAINERS_LOSERS` equivalent on the free tier. Our `finnhub_scanner.py` workaround fetches quotes for 50 large-cap S&P 500 stocks and sorts — this is a functional approximation but misses small/mid-cap movers.

**Finnhub Unique**: Earnings and economic calendars are zero-cost additions that directly enhance our geopolitical_scanner and macro_synthesis agents.

---

## 3. Unique Finnhub Capabilities (Not in Alpha Vantage)

These are additive value — things AV cannot provide at any tier:

| Capability | Endpoint | Value for TradingAgents |
|-----------|----------|------------------------|
| **Earnings Calendar** | `/calendar/earnings` | Event-driven triggers; pre-position before earnings volatility |
| **Economic Calendar** | `/calendar/economic` | FOMC, CPI, NFP dates for macro scanner context |
| **As-Filed XBRL Financials** | `/financials-reported` | Highest fidelity fundamental data for deep-think agents |
| **Earnings Surprise History** | `/stock/earnings` | Beat/miss rate — strong predictor signal for LLM reasoning |
| **Insider Sentiment (MSPR)** | `/stock/insider-sentiment` | Aggregated monthly buying pressure score |
| **Index Constituents** | `/index/constituents` | Know S&P 500 / NASDAQ 100 members without hardcoding |
| **Market Status** | `/market-status` | Gate scanner runs to market hours |
| **Options Chain** | `/stock/option-chain` (paid) | Put/call ratios, implied vol — not in AV at any tier |
| **Social Sentiment** | `/stock/social-sentiment` (paid) | Reddit/X structured signal |
| **Supply Chain Graph** | `/stock/supply-chain` (paid) | Peer/supplier/customer relationships |
| **Congressional Trading** | `/stock/usa-spending` | Insider signal from public officials |

---

## 4. Data Quality Assessment

| Dimension | Alpha Vantage | Finnhub | Notes |
|-----------|--------------|---------|-------|
| Real-time quotes | Delayed, occasionally stale | Delayed free / real-time paid; cleaner | Finnhub slightly better |
| Adjusted historical data | Known issues with reverse splits | More accurate back-adjustment | Finnhub better |
| Fundamental accuracy | Normalized, some restated-data lag | As-filed XBRL option is gold standard | Finnhub better for high-fidelity |
| News sentiment quality | ✅ Per-article NLP scores (genuine differentiator) | Aggregate only (free tier) | **AV wins** |
| API reliability | Generally stable; rate limits documented | Generally stable; free tier mostly reliable | Tie |

---

## 5. Free Tier Viability

### Scanner call budget analysis

| Scanner Stage | AV Calls | Finnhub Equivalent | Notes |
|--------------|----------|-------------------|-------|
| Market movers (1 endpoint) | 1 | 50 `/quote` calls | Workaround — massively more expensive |
| Per-mover fundamentals (5 tickers) | 5 `OVERVIEW` | 10 (profile2 + metric × 5) | 2× call count |
| News (3 topics) | 3 | 2 `/news` categories | Reduced topic coverage |
| Sector ETFs (11) | 11 | 11 `/quote` | 1:1 |
| **Total per scan** | ~30 | ~73 | Over free tier per-minute budget |

**Verdict**: Finnhub as a **full replacement** exceeds the 60 calls/min free tier budget for a complete scan. As a **supplementary vendor** for calendar data only (2-3 calls per scan), it fits comfortably.

---

## 6. What We Built

### New files (all in `tradingagents/dataflows/`)

| File | Purpose |
|------|---------|
| `finnhub_common.py` | Exception hierarchy, rate limiter (60/min), `_make_api_request` |
| `finnhub_stock.py` | `get_stock_candles`, `get_quote` |
| `finnhub_fundamentals.py` | `get_company_profile`, `get_financial_statements`, `get_basic_financials` |
| `finnhub_news.py` | `get_company_news`, `get_market_news`, `get_insider_transactions` |
| `finnhub_scanner.py` | `get_market_movers_finnhub`, `get_market_indices_finnhub`, `get_sector_performance_finnhub`, `get_topic_news_finnhub` |
| `finnhub_indicators.py` | `get_indicator_finnhub` (SMA, EMA, MACD, RSI, BBANDS, ATR) |
| `finnhub.py` | Facade re-exporting all public functions |

### Test files (in `tests/`)

| File | Tests | Type |
|------|-------|------|
| `test_finnhub_integration.py` | 100 | Offline (mocked HTTP) — always runs |
| `test_finnhub_live_integration.py` | 41 | Live API — skips if `FINNHUB_API_KEY` unset |

---

## 7. Integration Architecture (Proposed for Future PR)

If we proceed with adding Finnhub as a supplementary vendor, the changes to existing code would be minimal:

```python
# default_config.py — add Finnhub to calendar-specific routes
"vendor_calendar_data": "finnhub",   # earnings + economic calendars (new category)
"vendor_filings_data": "finnhub",    # as-filed XBRL (optional deep mode)
```

```python
# interface.py — extend fallback error types
except (AlphaVantageError, FinnhubError, ConnectionError, TimeoutError):
```

```python
# .env.example — add new key
FINNHUB_API_KEY=your_finnhub_api_key_here
```

New tools to add in a follow-up PR:
- `get_upcoming_earnings(from_date, to_date)` → `/calendar/earnings`
- `get_economic_calendar(from_date, to_date)` → `/calendar/economic`

---

## 8. Recommendation Summary

| Category | Decision | Rationale |
|----------|----------|-----------|
| Daily OHLCV | Keep yfinance primary | Free, no split-adjust issue, already working |
| Technical Indicators | Compute locally (`pandas-ta`) | Neither AV nor Finnhub is reliable; local is better |
| Fundamentals (quick) | Keep AV `OVERVIEW` | 1 call vs 2; sufficient for screening |
| Fundamentals (deep) | Add Finnhub `/financials-reported` | XBRL as-filed for debate rounds / deep-think agents |
| News sentiment | Keep AV | Per-article NLP scores are irreplaceable for agents |
| Market movers | Keep AV `TOP_GAINERS_LOSERS` | No viable Finnhub free alternative |
| **Earnings calendar** | **Add Finnhub** | Not available in AV — high signal, low cost (1 call) |
| **Economic calendar** | **Add Finnhub** | Not available in AV — critical macro context |
| Insider transactions | Either AV or Finnhub | Finnhub has additional `insider-sentiment` MSPR |

**Bottom line**: Add Finnhub's free calendar endpoints as a zero-cost enhancement to the macro scanner. Everything else stays as-is. The integration layer built in this PR is ready to use — it just needs the routing wired in `interface.py` and the calendar tool functions added to `scanner_tools.py`.

---

## 9. Running the Tests

```bash
# Offline tests (no API key needed)
conda activate tradingagents
pytest tests/test_finnhub_integration.py -v

# Live integration tests (requires FINNHUB_API_KEY)
FINNHUB_API_KEY=your_key pytest tests/test_finnhub_live_integration.py -v -m integration
```
