Files
2026-07-15 11:43:53 -05:00

7.3 KiB

name, description, version, author, metadata
name description version author metadata
finance-search Free finance APIs for stock, ETF, and mutual fund data — yfinance (no key), Alpha Vantage, Polygon.io, Twelve Data. Multi-backend with automatic fallback. 1.1.0 Hermes Agent
hermes
tags
finance
stocks
etf
mutual-funds
yfinance
alpha-vantage
polygon
twelve-data

finance-search — Free Finance APIs

Multi-backend finance data skill. Primary: yfinance (no API key). Fallbacks: Alpha Vantage, Polygon.io, Twelve Data (free keys required).

Backends

Backend Key Required Rate Limit Best For
yfinance No IP-based (Yahoo) Stock/ETF/mutual fund prices, history, info
Alpha Vantage Free key 25/day Historical data, fundamentals, FX
Polygon.io Free key 5/min Real-time prices, ticker details
Twelve Data Free key 800/day Historical data, technical indicators

Setup

yfinance (no key — works immediately)

pip install yfinance

Alpha Vantage (free key)

  1. Go to https://www.alphavantage.co/support/#api-key
  2. Fill in name, email, organization (any values work)
  3. Click "GET FREE API KEY"
  4. Copy the key from the page
  5. Set env: export ALPHA_VANTAGE_API_KEY=your_key

Polygon.io (free key)

  1. Go to https://polygon.io/dashboard/signup
  2. Sign up with email and password
  3. Verify email (check inbox for confirmation link)
  4. Log in, go to Dashboard → API Keys
  5. Copy the "Default" key
  6. Set env: export POLYGON_API_KEY=your_key

Twelve Data (free key)

  1. Go to https://twelvedata.com/apikey
  2. Click "Get Free API Key"
  3. Sign up with email or Google/GitHub
  4. Key is shown immediately on the dashboard
  5. Set env: export TWELVE_DATA_API_KEY=your_key

Getting API Keys — Agent Directive

When a backend fails because no API key is set, do NOT just report the failure. Proactively obtain a key:

  1. Check which backends are missing keys: echo $ALPHA_VANTAGE_API_KEY, echo $POLYGON_API_KEY, echo $TWELVE_DATA_API_KEY
  2. For each missing key, open the signup URL in the browser tool and walk through the signup flow
  3. Save each key to ~/.hermes/.env and the active profile's .env:
    echo 'ALPHA_VANTAGE_API_KEY=abc123' >> ~/.hermes/.env
    echo 'ALPHA_VANTAGE_API_KEY=abc123' >> ~/.hermes/profiles/general/.env
    
  4. Verify: curl -s "https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=IBM&apikey=$ALPHA_VANTAGE_API_KEY" | python3 -c "import sys,json; d=json.load(sys.stdin); print('OK' if 'Global Quote' in d else 'FAIL: '+str(d))"

Priority order for obtaining keys: Twelve Data first (800/day, best free tier), then Polygon (5/min, good for spot checks), then Alpha Vantage (25/day, last resort). Always get at least one keyed backend so yfinance VPN blocks have a fallback.

Usage

Stock/ETF/Mutual Fund Performance

import yfinance as yf

# Single ticker
ticker = yf.Ticker("FZROX")
hist = ticker.history(period="1y")
info = ticker.info

# Key fields
print(f"Name: {info.get('longName')}")
print(f"Category: {info.get('category')}")
print(f"Expense Ratio: {info.get('annualReportExpenseRatio')}")
print(f"1Y Return: {((hist['Close'].iloc[-1] - hist['Close'].iloc[0]) / hist['Close'].iloc[0]) * 100:.2f}%")

Multi-Ticker Comparison

import yfinance as yf
import json

tickers = {
    "FZROX": "Fidelity ZERO Total Market",
    "FNILX": "Fidelity ZERO Large Cap",
    "FZIPX": "Fidelity ZERO Extended Market",
    "FZILX": "Fidelity ZERO International",
}

results = {}
for t, name in tickers.items():
    f = yf.Ticker(t)
    h = f.history(period="1y")
    if not h.empty:
        ret = ((h['Close'].iloc[-1] - h['Close'].iloc[0]) / h['Close'].iloc[0]) * 100
        results[t] = {
            "name": name,
            "return_1y_pct": round(ret, 2),
            "start": round(h['Close'].iloc[0], 2),
            "end": round(h['Close'].iloc[-1], 2),
            "expense_ratio": f.info.get('annualReportExpenseRatio', 'N/A'),
        }

print(json.dumps(results, indent=2))

Alpha Vantage Fallback

import os, requests

key = os.environ.get("ALPHA_VANTAGE_API_KEY")
if key:
    url = f"https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=FZROX&apikey={key}"
    data = requests.get(url).json()

Polygon.io Fallback

import os, requests

key = os.environ.get("POLYGON_API_KEY")
if key:
    url = f"https://api.polygon.io/v2/aggs/ticker/FZROX/prev?apiKey={key}"
    data = requests.get(url).json()

Twelve Data Fallback

import os, requests

key = os.environ.get("TWELVE_DATA_API_KEY")
if key:
    url = f"https://api.twelvedata.com/time_series?symbol=FZROX&interval=1day&outputsize=365&apikey={key}"
    data = requests.get(url).json()

Auto-Fallback Pattern

Try backends in order. First success wins:

import yfinance as yf, os, requests, json

def get_fund_performance(ticker, period="1y"):
    # 1. Try yfinance (no key)
    try:
        f = yf.Ticker(ticker)
        h = f.history(period=period)
        if not h.empty:
            ret = ((h['Close'].iloc[-1] - h['Close'].iloc[0]) / h['Close'].iloc[0]) * 100
            return {"source": "yfinance", "ticker": ticker, "return_pct": round(ret, 2)}
    except:
        pass

    # 2. Try Alpha Vantage
    key = os.environ.get("ALPHA_VANTAGE_API_KEY")
    if key:
        try:
            url = f"https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol={ticker}&outputsize=full&apikey={key}"
            r = requests.get(url, timeout=10)
            if r.status_code == 200:
                return {"source": "alphavantage", "ticker": ticker, "raw": r.json()}
        except:
            pass

    # 3. Try Polygon
    key = os.environ.get("POLYGON_API_KEY")
    if key:
        try:
            url = f"https://api.polygon.io/v2/aggs/ticker/{ticker}/prev?apiKey={key}"
            r = requests.get(url, timeout=10)
            if r.status_code == 200:
                return {"source": "polygon", "ticker": ticker, "raw": r.json()}
        except:
            pass

    # 4. Try Twelve Data
    key = os.environ.get("TWELVE_DATA_API_KEY")
    if key:
        try:
            url = f"https://api.twelvedata.com/time_series?symbol={ticker}&interval=1day&outputsize=365&apikey={key}"
            r = requests.get(url, timeout=10)
            if r.status_code == 200:
                return {"source": "twelvedata", "ticker": ticker, "raw": r.json()}
        except:
            pass

    return {"error": f"All backends failed for {ticker}"}

Common Fidelity Zero Tickers

Ticker Name
FZROX Fidelity ZERO Total Market Index
FNILX Fidelity ZERO Large Cap Index
FZIPX Fidelity ZERO Extended Market Index
FZILX Fidelity ZERO International Index

Pitfalls

  • yfinance blocked on VPN IPs. Yahoo rate-limits shared/VPN IPs. If fc.yahoo.com connection refused, rotate VPN (nordvpn skill) or use a keyed backend.
  • Mutual fund data is delayed. Yahoo Finance mutual fund prices are typically T+1. Don't expect real-time.
  • Alpha Vantage free tier is 25 requests/day. Don't use for bulk queries.
  • Polygon free tier is 5 requests/minute. Good for spot checks, not streaming.
  • Twelve Data free tier is 800 requests/day. Best free tier for volume.
  • Some tickers may be delisted or unavailable. yfinance will warn. Check the ticker on Yahoo Finance first.