261 lines
13 KiB
Markdown
261 lines
13 KiB
Markdown
# 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
|
||
```
|