diff --git a/docs/plans/2026-02-23-strategies-fundamentals-design.md b/docs/plans/2026-02-23-strategies-fundamentals-design.md new file mode 100644 index 0000000..6ebd41c --- /dev/null +++ b/docs/plans/2026-02-23-strategies-fundamentals-design.md @@ -0,0 +1,299 @@ +# Design: Extended Strategies + Fundamental Data + +**Date:** 2026-02-23 +**Status:** Approved + +## Summary + +Add 6 new trading strategies and a fundamental data pipeline to the existing 3-strategy ensemble. Introduces fundamental analysis data (EPS, P/E, PEG, etc.) from three providers with rotation and DB-backed caching, plus additional technical indicators computed from existing OHLCV bars. + +**Result:** 9-strategy weighted ensemble (3 existing + 6 new). + +--- + +## 1. Fundamental Data Provider System + +### 1.1 Architecture + +New module `shared/fundamentals/` with a provider abstraction: + +``` +FundamentalsProvider (ABC) +├── AlphaVantageProvider (25 req/day free tier) +├── FMPProvider (250 req/day free tier) +├── YahooFinanceProvider (no API key, yfinance library) +└── RotatingProvider (wraps all three, rotates on rate limit) +``` + +### 1.2 Provider Interface + +```python +class FundamentalsProvider(ABC): + @abstractmethod + async def fetch(self, ticker: str) -> FundamentalsSnapshot | None: + """Fetch fundamental data for a single ticker.""" + +class RotatingProvider(FundamentalsProvider): + """Tries providers in order, rotating to the next on rate limit or error.""" + def __init__(self, providers: list[FundamentalsProvider]): ... + async def fetch(self, ticker: str) -> FundamentalsSnapshot | None: ... +``` + +### 1.3 Data Model + +```python +class FundamentalsSnapshot(BaseModel): + ticker: str + eps_ttm: float | None = None # Earnings per share (trailing 12 months) + pe_ratio: float | None = None # Price-to-earnings ratio + peg_ratio: float | None = None # Price/earnings-to-growth ratio + revenue_growth_yoy: float | None = None # Year-over-year revenue growth (decimal) + profit_margin: float | None = None # Net profit margin (decimal) + debt_to_equity: float | None = None # Total debt / shareholder equity + market_cap: float | None = None # Total market capitalization + fetched_at: datetime # When this data was fetched +``` + +### 1.4 DB-Backed Caching + +- New `fundamentals` table (Alembic migration required). +- On startup: load from DB. If `fetched_at` is within 24h, skip API calls. +- Daily refresh: background task re-fetches and updates DB. +- Prevents wasting free-tier API calls during local dev / restarts. + +### 1.5 Configuration + +New `.env` variables: +``` +TRADING_ALPHA_VANTAGE_API_KEY= +TRADING_FMP_API_KEY= +TRADING_FUNDAMENTALS_CACHE_TTL_HOURS=24 +``` + +No API key needed for Yahoo Finance (yfinance library). + +--- + +## 2. New Technical Indicators + +Computed in `MarketDataManager.get_snapshot()` from the existing OHLCV rolling window. No new data source needed. + +### 2.1 Indicators + +| Indicator | Computation | Added to MarketSnapshot | +|-----------|-------------|------------------------| +| MACD | EMA-12 minus EMA-26 | `macd: float \| None` | +| MACD Signal | EMA-9 of MACD line | `macd_signal: float \| None` | +| MACD Histogram | MACD minus signal | `macd_histogram: float \| None` | +| Bollinger Upper | SMA-20 + 2σ | `bollinger_upper: float \| None` | +| Bollinger Mid | SMA-20 | `bollinger_mid: float \| None` | +| Bollinger Lower | SMA-20 − 2σ | `bollinger_lower: float \| None` | +| VWAP | Cumulative(price × volume) / cumulative(volume) | `vwap: float \| None` | +| ATR (14) | Average true range, 14-period | `atr: float \| None` | +| EMA-9 | 9-period exponential moving average | `ema_9: float \| None` | +| EMA-21 | 21-period exponential moving average | `ema_21: float \| None` | +| SMA-200 | 200-period simple moving average | `sma_200: float \| None` | + +### 2.2 Historical Bars Increase + +`TRADING_HISTORICAL_BARS` bumped from 100 → 250 to support SMA-200 computation. + +--- + +## 3. New Strategies (6 total) + +All strategies implement `BaseStrategy.evaluate(ticker, market, sentiment) -> TradeSignal | None`. + +### 3.1 Value Strategy (fundamental) + +**File:** `shared/strategies/value.py` +**Name:** `"value"` + +Uses fundamental data (EPS, P/E, PEG, profit margin, debt-to-equity). + +| Condition | Signal | +|-----------|--------| +| PEG < 1.0 AND P/E < 25 AND EPS growth > 0 | LONG | +| PEG > 3.0 OR (P/E > 50 AND negative EPS growth) | SHORT | +| Strength: composite of how far metrics deviate from thresholds | 0–1 | + +Fundamentals data passed via a new optional `fundamentals` field on `MarketSnapshot`: +```python +fundamentals: FundamentalsSnapshot | None = None +``` + +### 3.2 MACD Crossover Strategy (technical) + +**File:** `shared/strategies/macd_crossover.py` +**Name:** `"macd_crossover"` + +| Condition | Signal | +|-----------|--------| +| MACD crosses above signal line AND histogram > 0 | LONG | +| MACD crosses below signal line AND histogram < 0 | SHORT | +| Strength: abs(histogram) normalized by ATR | 0–1 | + +Requires tracking previous MACD/signal values to detect crossovers. Stores last state per ticker in instance dict. + +### 3.3 Bollinger Bands Breakout Strategy (technical) + +**File:** `shared/strategies/bollinger_breakout.py` +**Name:** `"bollinger_breakout"` + +| Condition | Signal | +|-----------|--------| +| Price above upper band + volume > 1.5× average | LONG (momentum breakout) | +| Price below lower band | LONG (mean reversion bounce) | +| Price was above upper band, now back inside | SHORT (failed breakout) | +| Strength: distance from band / band width | 0–1 | + +### 3.4 VWAP Strategy (technical, intraday) + +**File:** `shared/strategies/vwap.py` +**Name:** `"vwap"` + +| Condition | Signal | +|-----------|--------| +| Price crosses above VWAP with increasing volume | LONG | +| Price crosses below VWAP with increasing volume | SHORT | +| Strength: distance from VWAP as % of price, weighted by volume ratio | 0–1 | + +### 3.5 Liquidity Strategy (volume-based) + +**File:** `shared/strategies/liquidity.py` +**Name:** `"liquidity"` + +| Indicator | Computation | +|-----------|-------------| +| Relative Volume | Current volume / 20-bar average volume | +| Volume Trend | Slope of volume over recent bars | +| Volume-Price Divergence | Price moving without volume confirmation | + +| Condition | Signal | +|-----------|--------| +| Relative volume > 2.0 AND price rising AND volume trend increasing | LONG | +| Relative volume > 2.0 AND price falling AND volume trend increasing | SHORT | +| Relative volume < 0.5 (thin liquidity) | Neutral — skip | +| Price rising on declining volume (divergence) | SHORT (weak rally) | +| Strength: relative volume magnitude, clamped to [0, 1] | 0–1 | + +### 3.6 MA Stack Strategy (trend alignment) + +**File:** `shared/strategies/ma_stack.py` +**Name:** `"ma_stack"` + +Reads the full 5-MA stack: EMA-9, EMA-21, SMA-50, SMA-200 (plus price). + +| Condition | Signal | +|-----------|--------| +| Full bull alignment: price > EMA-9 > EMA-21 > SMA-50 > SMA-200 | LONG, high strength | +| Partial bull: price > EMA-9 > EMA-21, below SMA-200 | LONG, lower strength | +| Full bear alignment: price < EMA-9 < EMA-21 < SMA-50 < SMA-200 | SHORT, high strength | +| Golden cross: SMA-50 crosses above SMA-200 | LONG boost | +| Death cross: SMA-50 crosses below SMA-200 | SHORT boost | +| MAs tangled / no clear order | Neutral — no signal | +| Strength: alignment count / 5, adjusted by fan spread | 0–1 | + +--- + +## 4. Updated Ensemble + +### 4.1 Default Weights (equal, 9 strategies) + +```python +_DEFAULT_WEIGHTS = { + "momentum": 0.111, + "mean_reversion": 0.111, + "news_driven": 0.111, + "value": 0.111, + "macd_crossover": 0.111, + "bollinger_breakout": 0.111, + "vwap": 0.111, + "liquidity": 0.112, + "ma_stack": 0.111, +} +``` + +### 4.2 Learning Engine + +The existing learning engine (multi-armed bandit) will automatically adjust weights for the new strategies based on trade outcomes. No changes needed to the learning engine itself — it already handles arbitrary strategy names. + +### 4.3 Strategy Seeding + +`scripts/seed_strategies.py` updated to seed all 9 strategies into the `strategies` DB table. + +--- + +## 5. Integration Points + +### 5.1 Signal Generator Changes + +1. Import and instantiate all 6 new strategies in `run()`. +2. Add fundamentals fetching as a background task (daily refresh). +3. Inject `FundamentalsSnapshot` into `MarketSnapshot.fundamentals` before calling ensemble. +4. Update `_DEFAULT_WEIGHTS` to include all 9 strategies. + +### 5.2 MarketDataManager Changes + +1. Add EMA computation method (exponential moving average). +2. Compute MACD, Bollinger, VWAP, ATR, EMA-9, EMA-21, SMA-200 in `get_snapshot()`. +3. Track previous MACD state for crossover detection (or let strategy handle it). + +### 5.3 Schema Changes + +1. Add new optional fields to `MarketSnapshot` (all technical indicators + fundamentals). +2. Add `FundamentalsSnapshot` Pydantic model. + +### 5.4 Database Changes + +1. New `fundamentals` table (Alembic migration). +2. Seed 6 new strategies via `seed_strategies.py`. + +### 5.5 Configuration Changes + +```env +TRADING_ALPHA_VANTAGE_API_KEY=M0I3TWB6VKU0UF51 +TRADING_FMP_API_KEY=34zqbQFeRxYvPtzp3Y5QLKPVPztkZyfK +TRADING_FUNDAMENTALS_CACHE_TTL_HOURS=24 +TRADING_HISTORICAL_BARS=250 +``` + +### 5.6 Dependencies + +```toml +# pyproject.toml — new deps +yfinance # Yahoo Finance fundamentals (no API key) +# httpx/aiohttp already available for Alpha Vantage + FMP REST calls +``` + +--- + +## 6. File Changes Summary + +### New Files +- `shared/fundamentals/__init__.py` +- `shared/fundamentals/base.py` — `FundamentalsProvider` ABC + `FundamentalsSnapshot` +- `shared/fundamentals/alpha_vantage.py` — Alpha Vantage provider +- `shared/fundamentals/fmp.py` — Financial Modeling Prep provider +- `shared/fundamentals/yahoo.py` — Yahoo Finance provider (yfinance) +- `shared/fundamentals/rotating.py` — `RotatingProvider` with failover +- `shared/strategies/value.py` — Value strategy +- `shared/strategies/macd_crossover.py` — MACD Crossover strategy +- `shared/strategies/bollinger_breakout.py` — Bollinger Breakout strategy +- `shared/strategies/vwap.py` — VWAP strategy +- `shared/strategies/liquidity.py` — Liquidity strategy +- `shared/strategies/ma_stack.py` — MA Stack strategy +- `alembic/versions/xxx_add_fundamentals_table.py` — Migration +- `tests/test_fundamentals.py` — Unit tests for providers +- `tests/test_new_strategies.py` — Unit tests for 6 new strategies +- `tests/test_indicators.py` — Unit tests for technical indicator computations + +### Modified Files +- `shared/schemas/trading.py` — Add indicator fields to `MarketSnapshot` +- `services/signal_generator/market_data.py` — Add EMA, MACD, Bollinger, VWAP, ATR, SMA-200 computations +- `services/signal_generator/main.py` — Import new strategies, add fundamentals fetching, update weights +- `shared/strategies/__init__.py` — Export new strategies +- `scripts/seed_strategies.py` — Seed 6 new strategies +- `.env` — Add API keys and config +- `pyproject.toml` — Add yfinance dependency +- `shared/models/trading.py` — Add `Fundamentals` DB model (or new file in models/)