441 lines
17 KiB
Markdown
441 lines
17 KiB
Markdown
# OpenBB Investment Analysis API
|
|
|
|
REST API wrapping OpenBB SDK, providing stock data, sentiment analysis, technical indicators, quantitative risk metrics, macro data, market data (ETF/index/crypto/forex/options), and rule-based investment analysis for US and Swedish markets. Designed to be called by OpenClaw (or any AI assistant) -- the API returns structured data, all LLM reasoning happens on the caller side.
|
|
|
|
## API Keys
|
|
|
|
### Required: None
|
|
|
|
The core functionality uses **yfinance** (free, no API key). The API works without any keys configured.
|
|
|
|
### Recommended Free Keys
|
|
|
|
| Provider | Env Variable | How to Get | What It Unlocks | Free Limit |
|
|
|----------|-------------|------------|-----------------|------------|
|
|
| **Finnhub** | `INVEST_API_FINNHUB_API_KEY` | https://finnhub.io/register | Insider trades, analyst upgrades, recommendation trends | 60 calls/min |
|
|
| **FRED** | `INVEST_API_FRED_API_KEY` | https://fred.stlouisfed.org/docs/api/api_key.html | Macro data: Fed rate, CPI, GDP, unemployment, treasury yields | 120 calls/min |
|
|
| **Alpha Vantage** | `INVEST_API_ALPHAVANTAGE_API_KEY` | https://www.alphavantage.co/support/#api-key | News sentiment scores (bullish/bearish per article per ticker) | 25 calls/day |
|
|
|
|
### Optional Paid Keys (for higher quality data)
|
|
|
|
| Provider | Env Variable | What It Adds |
|
|
|----------|-------------|--------------|
|
|
| **FMP** | `OBB_FMP_API_KEY` | More granular financials, earnings transcripts (250 calls/day free) |
|
|
| **Intrinio** | `OBB_INTRINIO_API_KEY` | Institutional-grade fundamentals |
|
|
| **Tiingo** | `OBB_TIINGO_TOKEN` | Reliable historical price data |
|
|
| **Benzinga** | `OBB_BENZINGA_API_KEY` | Real-time news, analyst ratings |
|
|
|
|
### Configuration
|
|
|
|
Set environment variables before starting, or add to a `.env` file:
|
|
|
|
```bash
|
|
export INVEST_API_FINNHUB_API_KEY=your_finnhub_key
|
|
export INVEST_API_FRED_API_KEY=your_fred_key
|
|
export INVEST_API_ALPHAVANTAGE_API_KEY=your_alphavantage_key
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
### 1. Create conda environment
|
|
|
|
```bash
|
|
conda env create -f environment.yml
|
|
conda activate openbb-invest-api
|
|
pip install openbb-quantitative openbb-econometrics
|
|
```
|
|
|
|
### 2. Start the server
|
|
|
|
```bash
|
|
python main.py
|
|
```
|
|
|
|
Server starts at `http://localhost:8000`. Visit `http://localhost:8000/docs` for Swagger UI.
|
|
|
|
### 3. Test it
|
|
|
|
```bash
|
|
# Health check
|
|
curl http://localhost:8000/health
|
|
|
|
# US stock quote
|
|
curl http://localhost:8000/api/v1/stock/AAPL/quote
|
|
|
|
# Swedish stock quote
|
|
curl http://localhost:8000/api/v1/stock/VOLV-B.ST/quote
|
|
|
|
# Sentiment analysis (Finnhub + Alpha Vantage)
|
|
curl http://localhost:8000/api/v1/stock/AAPL/sentiment
|
|
|
|
# News sentiment with per-article scores (Alpha Vantage)
|
|
curl http://localhost:8000/api/v1/stock/AAPL/news-sentiment
|
|
|
|
# Technical indicators
|
|
curl http://localhost:8000/api/v1/stock/AAPL/technical
|
|
|
|
# Quantitative risk metrics
|
|
curl http://localhost:8000/api/v1/stock/AAPL/performance
|
|
curl http://localhost:8000/api/v1/stock/AAPL/capm
|
|
|
|
# SEC insider trading
|
|
curl http://localhost:8000/api/v1/stock/AAPL/sec-insider
|
|
|
|
# ETF info
|
|
curl http://localhost:8000/api/v1/etf/SPY/info
|
|
|
|
# Crypto price history
|
|
curl http://localhost:8000/api/v1/crypto/BTC-USD/historical?days=30
|
|
|
|
# Macro overview (requires FRED key)
|
|
curl http://localhost:8000/api/v1/macro/overview
|
|
|
|
# Portfolio analysis
|
|
curl -X POST http://localhost:8000/api/v1/portfolio/analyze \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"holdings":[{"symbol":"AAPL","shares":100,"buy_in_price":150},{"symbol":"VOLV-B.ST","shares":50,"buy_in_price":250}]}'
|
|
```
|
|
|
|
## API Endpoints
|
|
|
|
### Health
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/health` | Health check |
|
|
|
|
### Stock Data (yfinance, no key needed)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/v1/stock/{symbol}/quote` | Current price and volume |
|
|
| GET | `/api/v1/stock/{symbol}/profile` | Company overview (sector, industry, description) |
|
|
| GET | `/api/v1/stock/{symbol}/metrics` | Key ratios (PE, PB, ROE, EPS, etc.) |
|
|
| GET | `/api/v1/stock/{symbol}/financials` | Income statement + balance sheet + cash flow |
|
|
| GET | `/api/v1/stock/{symbol}/historical?days=365` | Historical OHLCV data |
|
|
| GET | `/api/v1/stock/{symbol}/news` | Recent company news |
|
|
| GET | `/api/v1/stock/{symbol}/summary` | Aggregated: quote + profile + metrics + financials |
|
|
|
|
### Sentiment & Analyst Data (Finnhub + Alpha Vantage, free keys)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/v1/stock/{symbol}/sentiment` | Aggregated: news sentiment + recommendations + upgrades |
|
|
| GET | `/api/v1/stock/{symbol}/news-sentiment?limit=30` | News articles with per-ticker sentiment scores (Alpha Vantage) |
|
|
| GET | `/api/v1/stock/{symbol}/insider-trades` | Insider transactions via Finnhub |
|
|
| GET | `/api/v1/stock/{symbol}/recommendations` | Monthly analyst buy/hold/sell counts |
|
|
| GET | `/api/v1/stock/{symbol}/upgrades` | Recent analyst upgrades and downgrades |
|
|
|
|
### Technical Analysis (local computation, no key needed)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/v1/stock/{symbol}/technical` | RSI, MACD, SMA, EMA, Bollinger Bands + signal interpretation |
|
|
|
|
### Quantitative Analysis (openbb-quantitative, no key needed)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/v1/stock/{symbol}/performance?days=365` | Sharpe ratio, summary statistics, volatility |
|
|
| GET | `/api/v1/stock/{symbol}/capm` | CAPM: market risk, systematic risk, idiosyncratic risk |
|
|
| GET | `/api/v1/stock/{symbol}/normality?days=365` | Normality tests: Jarque-Bera, Shapiro-Wilk, Kolmogorov-Smirnov |
|
|
| GET | `/api/v1/stock/{symbol}/unitroot?days=365` | Unit root tests: ADF, KPSS for stationarity |
|
|
|
|
### Calendar Events (no key needed)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/v1/calendar/earnings?start_date=&end_date=` | Upcoming earnings announcements |
|
|
| GET | `/api/v1/calendar/dividends?start_date=&end_date=` | Upcoming dividend dates |
|
|
| GET | `/api/v1/calendar/ipo?start_date=&end_date=` | Upcoming IPOs |
|
|
| GET | `/api/v1/calendar/splits?start_date=&end_date=` | Upcoming stock splits |
|
|
|
|
### Estimates & Ownership (yfinance + SEC, no key needed)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/v1/stock/{symbol}/estimates` | Analyst consensus estimates |
|
|
| GET | `/api/v1/stock/{symbol}/share-statistics` | Float, shares outstanding, short interest |
|
|
| GET | `/api/v1/stock/{symbol}/sec-insider` | Insider trading from SEC (Form 4) |
|
|
| GET | `/api/v1/stock/{symbol}/institutional` | Institutional holders from SEC 13F filings |
|
|
| GET | `/api/v1/screener` | Stock screener |
|
|
|
|
### ETF Data (yfinance, no key needed)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/v1/etf/{symbol}/info` | ETF profile, issuer, holdings |
|
|
| GET | `/api/v1/etf/{symbol}/historical?days=365` | ETF price history |
|
|
| GET | `/api/v1/etf/search?query=` | Search ETFs by name |
|
|
|
|
### Index Data (yfinance, no key needed)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/v1/index/available` | List available indices |
|
|
| GET | `/api/v1/index/{symbol}/historical?days=365` | Index price history (^GSPC, ^DJI, ^IXIC) |
|
|
|
|
### Crypto Data (yfinance, no key needed)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/v1/crypto/{symbol}/historical?days=365` | Crypto price history (BTC-USD, ETH-USD) |
|
|
| GET | `/api/v1/crypto/search?query=` | Search cryptocurrencies |
|
|
|
|
### Currency / Forex (yfinance, no key needed)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/v1/currency/{symbol}/historical?days=365` | Forex price history (EURUSD, USDSEK) |
|
|
|
|
### Derivatives (yfinance, no key needed)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/v1/options/{symbol}/chains` | Options chain data |
|
|
| GET | `/api/v1/futures/{symbol}/historical?days=365` | Futures price history |
|
|
| GET | `/api/v1/futures/{symbol}/curve` | Futures term structure/curve |
|
|
|
|
### Macro Economics (FRED, free key)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/v1/macro/overview` | Key indicators: Fed rate, treasury yields, CPI, unemployment, GDP, VIX |
|
|
| GET | `/api/v1/macro/series/{series_id}?limit=30` | Any FRED time series by ID |
|
|
|
|
### Portfolio Analysis (no key needed)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| POST | `/api/v1/portfolio/analyze` | Rule-based analysis of holdings (max 50) |
|
|
|
|
Request body:
|
|
```json
|
|
{
|
|
"holdings": [
|
|
{"symbol": "AAPL", "shares": 100, "buy_in_price": 150.0},
|
|
{"symbol": "VOLV-B.ST", "shares": 50, "buy_in_price": 250.0}
|
|
]
|
|
}
|
|
```
|
|
|
|
Response includes per-holding: current price, P&L, key metrics, analyst target price, and a rule-engine recommendation (BUY_MORE / HOLD / SELL) with confidence level and reasons.
|
|
|
|
### Stock Discovery (no key needed)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/v1/discover/gainers` | Top gainers |
|
|
| GET | `/api/v1/discover/losers` | Top losers |
|
|
| GET | `/api/v1/discover/active` | Most active |
|
|
| GET | `/api/v1/discover/undervalued` | Undervalued large caps |
|
|
| GET | `/api/v1/discover/growth` | Growth tech stocks |
|
|
|
|
## Rule Engine
|
|
|
|
The portfolio analysis endpoint uses a rule-based engine (no LLM) that scores each holding on four signals:
|
|
|
|
| Signal | BUY_MORE (+1) | HOLD (0) | SELL (-1) |
|
|
|--------|---------------|----------|-----------|
|
|
| Price vs analyst target | >15% upside | -10% to +15% | >10% downside |
|
|
| PE ratio | < 15 | 15 - 35 | > 35 or negative |
|
|
| Revenue growth | > 10% YoY | 0 - 10% | Negative |
|
|
| P&L vs cost basis | Loss > 20% | -20% to +50% | Profit > 50% |
|
|
|
|
Scores are summed. Total >= 2 = BUY_MORE, <= -2 = SELL, otherwise HOLD. Confidence is HIGH/MEDIUM/LOW based on how many signals agree.
|
|
|
|
## Configuration
|
|
|
|
All settings are configurable via environment variables with the `INVEST_API_` prefix:
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `INVEST_API_HOST` | `0.0.0.0` | Server bind address |
|
|
| `INVEST_API_PORT` | `8000` | Server port |
|
|
| `INVEST_API_CORS_ORIGINS` | `["http://localhost:3000"]` | Allowed CORS origins (JSON array) |
|
|
| `INVEST_API_LOG_LEVEL` | `info` | Logging level |
|
|
| `INVEST_API_DEBUG` | `false` | Enable debug mode (auto-reload) |
|
|
| `INVEST_API_FINNHUB_API_KEY` | _(empty)_ | Finnhub API key for analyst data |
|
|
| `INVEST_API_FRED_API_KEY` | _(empty)_ | FRED API key for macro data |
|
|
| `INVEST_API_ALPHAVANTAGE_API_KEY` | _(empty)_ | Alpha Vantage API key for news sentiment |
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
openbb-invest-api/
|
|
├── main.py # FastAPI app entry point
|
|
├── config.py # Settings (env-based)
|
|
├── models.py # Pydantic request/response models
|
|
├── mappers.py # Dict-to-model mapping functions
|
|
├── route_utils.py # Shared route utilities (validation, error handling)
|
|
├── obb_utils.py # Shared OpenBB result conversion utilities
|
|
├── openbb_service.py # OpenBB SDK wrapper (async)
|
|
├── finnhub_service.py # Finnhub REST client (insider, analyst data)
|
|
├── alphavantage_service.py # Alpha Vantage REST client (news sentiment)
|
|
├── quantitative_service.py # Risk metrics, CAPM, normality tests
|
|
├── calendar_service.py # Calendar events, screening, ownership
|
|
├── market_service.py # ETF, index, crypto, currency, derivatives
|
|
├── macro_service.py # FRED macro data via OpenBB
|
|
├── technical_service.py # Technical indicators via openbb-technical
|
|
├── analysis_service.py # Rule engine for portfolio analysis
|
|
├── routes.py # Core stock data + portfolio + discovery routes
|
|
├── routes_sentiment.py # Sentiment & analyst routes (Finnhub + Alpha Vantage)
|
|
├── routes_quantitative.py # Quantitative analysis routes
|
|
├── routes_calendar.py # Calendar, estimates, ownership routes
|
|
├── routes_market.py # ETF, index, crypto, currency, derivatives routes
|
|
├── routes_macro.py # Macro economics routes (FRED)
|
|
├── routes_technical.py # Technical analysis routes
|
|
├── environment.yml # Conda environment
|
|
├── pyproject.toml # Project metadata
|
|
└── tests/ # 102 tests
|
|
```
|
|
|
|
## Running Tests
|
|
|
|
```bash
|
|
conda activate openbb-invest-api
|
|
python -m pytest tests/ -v
|
|
```
|
|
|
|
## Swedish Stocks
|
|
|
|
Swedish stocks are supported via the `.ST` suffix (Stockholm exchange):
|
|
- `VOLV-B.ST` (Volvo)
|
|
- `ERIC-B.ST` (Ericsson)
|
|
- `HM-B.ST` (H&M)
|
|
- `SEB-A.ST` (SEB)
|
|
- `SAND.ST` (Sandvik)
|
|
|
|
## Integration with OpenClaw
|
|
|
|
This API is designed to be called by OpenClaw as an MCP tool or HTTP data source. OpenClaw sends requests to this API to fetch structured stock data and rule-based analysis, then uses its LLM to generate natural language investment advice.
|
|
|
|
Example OpenClaw workflow:
|
|
1. User asks: "Should I buy more AAPL?"
|
|
2. OpenClaw calls `GET /api/v1/stock/AAPL/summary` for fundamental data
|
|
3. OpenClaw calls `GET /api/v1/stock/AAPL/sentiment` for news/analyst sentiment
|
|
4. OpenClaw calls `GET /api/v1/stock/AAPL/technical` for technical signals
|
|
5. OpenClaw calls `GET /api/v1/stock/AAPL/performance` for risk metrics (Sharpe, volatility)
|
|
6. OpenClaw calls `GET /api/v1/stock/AAPL/sec-insider` for insider trading activity
|
|
7. OpenClaw calls `GET /api/v1/macro/overview` for market context
|
|
8. OpenClaw calls `POST /api/v1/portfolio/analyze` with user's holdings
|
|
9. OpenClaw's LLM synthesizes all structured data into a personalized recommendation
|
|
|
|
## Kubernetes Deployment
|
|
|
|
### Prerequisites
|
|
|
|
- Kubernetes cluster with ingress-nginx
|
|
- Docker Registry at `192.168.68.11:30500`
|
|
- Drone CI connected to Gitea
|
|
- ArgoCD installed
|
|
|
|
### Architecture
|
|
|
|
```
|
|
git push → Gitea → Drone CI (kaniko) → Docker Registry → ArgoCD → K8s
|
|
```
|
|
|
|
### Cluster Info
|
|
|
|
| Component | Value |
|
|
|-----------|-------|
|
|
| API URL | `https://invest-api.k8s.home` |
|
|
| Namespace | `invest-api` |
|
|
| Image | `192.168.68.11:30500/invest-api:latest` |
|
|
| Resources | 100m-500m CPU, 256Mi-512Mi memory |
|
|
| Health check | `GET /health` on port 8000 |
|
|
|
|
### K8s Manifests
|
|
|
|
Located in `k8s/base/` (Kustomize):
|
|
|
|
| File | Description |
|
|
|------|-------------|
|
|
| `namespace.yaml` | `invest-api` namespace |
|
|
| `deployment.yaml` | App deployment with health probes |
|
|
| `service.yaml` | ClusterIP service on port 8000 |
|
|
| `ingress.yaml` | Ingress for `invest-api.k8s.home` |
|
|
| `secret.yaml` | Template for API keys |
|
|
| `kustomization.yaml` | Kustomize resource list |
|
|
|
|
ArgoCD Application defined in `k8s/argocd-app.yaml`.
|
|
|
|
### CI/CD Pipeline
|
|
|
|
`.drone.yml` uses kaniko to build and push:
|
|
|
|
```yaml
|
|
kind: pipeline
|
|
type: kubernetes
|
|
name: build-and-push
|
|
|
|
trigger:
|
|
branch: [main, develop]
|
|
event: [push, custom]
|
|
|
|
steps:
|
|
- name: build-and-push
|
|
image: gcr.io/kaniko-project/executor:debug
|
|
commands:
|
|
- /kaniko/executor
|
|
--context=/drone/src
|
|
--dockerfile=Dockerfile
|
|
--destination=192.168.68.11:30500/invest-api:${DRONE_COMMIT_SHA:0:8}
|
|
--destination=192.168.68.11:30500/invest-api:latest
|
|
--insecure --skip-tls-verify
|
|
```
|
|
|
|
### Deploy from Scratch
|
|
|
|
1. Deploy Docker Registry:
|
|
```bash
|
|
kubectl apply -k k8s-infra/registry/
|
|
```
|
|
|
|
2. Configure containerd on worker nodes to trust insecure registry (see `HomeLab Infrastructure` doc)
|
|
|
|
3. Push code to Gitea -- Drone builds and pushes image automatically
|
|
|
|
4. Apply ArgoCD Application:
|
|
```bash
|
|
kubectl apply -f k8s/argocd-app.yaml
|
|
```
|
|
|
|
5. Create API key secrets (optional):
|
|
```bash
|
|
kubectl -n invest-api create secret generic invest-api-secrets \
|
|
--from-literal=INVEST_API_FINNHUB_API_KEY=your_key \
|
|
--from-literal=INVEST_API_FRED_API_KEY=your_key \
|
|
--from-literal=INVEST_API_ALPHAVANTAGE_API_KEY=your_key
|
|
```
|
|
|
|
6. Add DNS: `invest-api.k8s.home → 192.168.68.22`
|
|
|
|
7. Verify:
|
|
```bash
|
|
curl -k https://invest-api.k8s.home/health
|
|
curl -k https://invest-api.k8s.home/api/v1/stock/AAPL/quote
|
|
```
|
|
|
|
### Docker
|
|
|
|
Build and run locally:
|
|
|
|
```bash
|
|
docker build -t invest-api .
|
|
docker run -p 8000:8000 invest-api
|
|
```
|
|
|
|
## Data Sources
|
|
|
|
| Source | Cost | Key Required | Data Provided |
|
|
|--------|------|-------------|---------------|
|
|
| **yfinance** | Free | No | Quotes, fundamentals, financials, historical prices, news, discovery, ETF, index, crypto, forex, options, futures |
|
|
| **SEC** | Free | No | Insider trading (Form 4), institutional holdings (13F), company filings |
|
|
| **Finnhub** | Free | Yes (free registration) | Insider trades, analyst recommendations, upgrades/downgrades |
|
|
| **Alpha Vantage** | Free | Yes (free registration) | News sentiment scores (bullish/bearish per ticker per article), 25 req/day |
|
|
| **FRED** | Free | Yes (free registration) | Fed rate, treasury yields, CPI, unemployment, GDP, VIX, 800K+ economic series |
|
|
| **openbb-technical** | Free | No (local computation) | RSI, MACD, SMA, EMA, Bollinger Bands |
|
|
| **openbb-quantitative** | Free | No (local computation) | Sharpe ratio, CAPM, normality tests, unit root tests, summary statistics |
|