196 lines
5.9 KiB
Markdown
196 lines
5.9 KiB
Markdown
---
|
|
name: finance-data
|
|
description: "Free finance APIs for stock, ETF, and mutual fund data — yfinance (no key), Alpha Vantage, Polygon.io, Twelve Data. Multi-backend with automatic fallback."
|
|
version: 1.0.0
|
|
author: Hermes Agent
|
|
metadata:
|
|
hermes:
|
|
tags: [finance, stocks, etf, mutual-funds, yfinance, alpha-vantage, polygon, twelve-data]
|
|
---
|
|
|
|
# finance-data — 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)
|
|
```bash
|
|
pip install yfinance
|
|
```
|
|
|
|
### Alpha Vantage (free key)
|
|
1. Sign up at https://www.alphavantage.co/support/#api-key
|
|
2. Set env: `export ALPHA_VANTAGE_API_KEY=your_key`
|
|
|
|
### Polygon.io (free key)
|
|
1. Sign up at https://polygon.io/dashboard/signup
|
|
2. Set env: `export POLYGON_API_KEY=your_key`
|
|
|
|
### Twelve Data (free key)
|
|
1. Sign up at https://twelvedata.com/apikey
|
|
2. Set env: `export TWELVE_DATA_API_KEY=your_key`
|
|
|
|
## Usage
|
|
|
|
### Stock/ETF/Mutual Fund Performance
|
|
|
|
```python
|
|
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
|
|
|
|
```python
|
|
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
|
|
|
|
```python
|
|
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
|
|
|
|
```python
|
|
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
|
|
|
|
```python
|
|
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:
|
|
|
|
```python
|
|
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.
|