# 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/)