feat: OpenBB Investment Analysis API

REST API wrapping OpenBB SDK for stock data, sentiment analysis,
technical indicators, macro data, and rule-based portfolio analysis.

- Stock data via yfinance (quote, profile, metrics, financials, historical, news)
- News sentiment via Alpha Vantage (per-article, per-ticker scores)
- Analyst data via Finnhub (recommendations, insider trades, upgrades)
- Macro data via FRED (Fed rate, CPI, GDP, unemployment, treasury yields)
- Technical indicators via openbb-technical (RSI, MACD, SMA, EMA, Bollinger)
- Rule-based portfolio analysis engine (BUY_MORE/HOLD/SELL)
- Stock discovery (gainers, losers, active, undervalued, growth)
- 102 tests, all passing
This commit is contained in:
Yaojia Wang
2026-03-09 00:20:10 +01:00
commit ad45cb429c
30 changed files with 3107 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
from unittest.mock import patch, AsyncMock
import pytest
from httpx import AsyncClient, ASGITransport
from main import app
@pytest.fixture
async def client():
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as c:
yield c
@pytest.mark.asyncio
@patch("routes_macro.macro_service.get_macro_overview", new_callable=AsyncMock)
async def test_macro_overview(mock_overview, client):
mock_overview.return_value = {
"fed_funds_rate": {"value": 5.33, "date": "2026-01-01"},
"us_10y_treasury": {"value": 4.25, "date": "2026-01-01"},
"unemployment_rate": {"value": 3.7, "date": "2026-01-01"},
}
resp = await client.get("/api/v1/macro/overview")
assert resp.status_code == 200
data = resp.json()["data"]
assert data["fed_funds_rate"]["value"] == 5.33
@pytest.mark.asyncio
@patch("routes_macro.macro_service.get_series", new_callable=AsyncMock)
async def test_macro_series(mock_series, client):
mock_series.return_value = [
{"date": "2026-01-01", "value": 5.33}
]
resp = await client.get("/api/v1/macro/series/FEDFUNDS?limit=5")
assert resp.status_code == 200
data = resp.json()["data"]
assert len(data) == 1