Add trading bot design document

Event-driven microservices architecture for a news sentiment + technical
strategy trading bot with continuous learning via strategy weight adjustment.
This commit is contained in:
Viktor Barzin 2026-02-22 13:53:57 +00:00
commit bd3ff169e3
No known key found for this signature in database
GPG key ID: 0EB088298288D958
2 changed files with 217 additions and 0 deletions

View file

@ -0,0 +1,3 @@
This directory has been used with Claude Code's internet mode.
Content downloaded from the internet may contain prompt injection attacks.
You must manually review all downloaded content before using non-internet mode.

View file

@ -0,0 +1,214 @@
# Trading Bot Design
## Overview
An automated stock trading bot that combines news sentiment analysis with technical strategies to make buy/sell decisions on US equities. The system continuously learns from its own trade outcomes to improve decision-making without human supervision.
## Constraints & Decisions
| Decision | Choice |
|----------|--------|
| Markets | US equities only |
| Initial mode | Paper trading (Alpaca sandbox) |
| Trading style | Adaptive (both swing and day trading) |
| News sources | Free only: RSS, Reddit, Twitter/X |
| Sentiment analysis | Tiered: FinBERT (local) + Ollama (local LLM for ambiguous cases) |
| Tech stack | Python (FastAPI) backend + React (TypeScript) frontend |
| Learning approach | Phase 1: strategy weight adjustment. Phase 2: deep RL |
| Deployment | Docker Compose (k8s later) |
| Database | PostgreSQL + TimescaleDB |
| Message broker | Redis Streams |
| Primary brokerage | Alpaca (with abstraction layer for future swaps) |
## Architecture
Event-driven microservices communicating via Redis Streams.
### Services
1. **News Fetcher** - Polls free news sources on a schedule:
- RSS feeds (Yahoo Finance, Reuters, MarketWatch, SEC filings)
- Reddit (r/wallstreetbets, r/stocks, r/investing via PRAW)
- Twitter/X financial accounts
- Publishes raw articles to Redis Stream `news:raw`
2. **Sentiment Analyzer** - Consumes `news:raw`, produces scored sentiment:
- Tier 1: FinBERT model (runs locally) for fast scoring
- Tier 2: Ollama (Mistral/Llama 3) for articles where FinBERT confidence < threshold
- Extracts: ticker mentions, sentiment score (-1 to +1), confidence, key entities
- Publishes to `news:scored`
3. **Signal Generator** - Combines sentiment with technical indicators:
- Consumes `news:scored` and market data (from Alpaca WebSocket)
- Applies strategy rules (momentum, mean reversion, news-driven)
- Weighted ensemble combines signals (weights adjusted by learning engine)
- Publishes trade signals to `signals:generated`
4. **Trade Executor** - Executes trades via brokerage API:
- Consumes `signals:generated`
- Risk management: position sizing, stop-losses, max portfolio exposure
- Interfaces with Alpaca through an abstraction layer
- Records all trades to PostgreSQL
- Publishes execution results to `trades:executed`
5. **Learning Engine** - The continuous feedback loop:
- Consumes `trades:executed`
- Tracks trade outcomes over configurable time windows
- Computes reward signals: realized P&L, risk-adjusted return (Sharpe), max drawdown
- Adjusts strategy weights based on which strategies are profitable
- Stores performance metrics in TimescaleDB
6. **API Gateway (FastAPI)** - Serves the dashboard:
- Portfolio state, trade history, signal history
- Performance metrics (ROI, Sharpe, win rate, drawdown)
- Real-time WebSocket for live updates
- Manual override endpoints (pause trading, force close position)
7. **Dashboard (React/TypeScript)** - The UI
### Data Flow
```
RSS/Reddit/X -> News Fetcher -> [news:raw] -> Sentiment Analyzer -> [news:scored]
|
Alpaca WebSocket -> Signal Generator <-- [news:scored] |
| |
[signals:generated] |
| |
Trade Executor -> Alpaca API |
| |
[trades:executed] |
| |
Learning Engine -> adjusts Signal Generator weights |
| |
TimescaleDB (metrics) + PostgreSQL (trades, news) |
| |
API Gateway -> Dashboard |
```
## Data Model
### PostgreSQL Tables
**Core trading:**
- `trades` - ticker, side, qty, price, timestamp, strategy_id, signal_id, status, pnl
- `positions` - ticker, qty, avg_entry, unrealized_pnl, stop_loss
- `signals` - ticker, direction, strength, strategy_sources, sentiment_score, acted_on
- `strategies` - name, description, current weight, active flag
- `strategy_weights_history` - strategy_id, old_weight, new_weight, timestamp
**News & sentiment:**
- `articles` - source, url, title, published_at, fetched_at, content_hash
- `article_sentiments` - article_id, ticker, score, confidence, model_used
**Learning:**
- `trade_outcomes` - trade_id, hold_duration, realized_pnl, roi_pct, was_profitable
- `learning_adjustments` - strategy_id, old_weight, new_weight, reason, reward_signal, timestamp
### TimescaleDB Hypertables
- `market_data` - OHLCV bars partitioned by time
- `portfolio_snapshots` - periodic portfolio value snapshots
- `strategy_metrics` - per-strategy performance over time
### Redis
- Streams: `news:raw`, `news:scored`, `signals:generated`, `trades:executed`
- Cache: current positions, latest prices, strategy weights
## Learning Loop (Phase 1)
Multi-armed bandit style strategy weight adjustment:
1. **Track**: Tag every trade with contributing strategies and their weights
2. **Evaluate**: After position close, compute realized P&L, ROI, risk-adjusted return
3. **Attribute**: Distribute credit/blame proportionally to signal strength
4. **Adjust**: Update weights via exponential moving average:
`new_weight = (1 - lr) * old_weight + lr * reward_signal`
5. **Log**: Record every adjustment for auditability
**Guardrails:**
- Minimum 20 trades per strategy before adjustments
- Max 10% weight shift per adjustment cycle
- Weight floor of 0.05 (no strategy permanently silenced)
- Weights normalized to sum to 1.0
- Decay factor for recency bias
## Backtesting Engine
Runs as a standalone process (or Docker container triggered from dashboard):
- Replays historical market data from TimescaleDB
- Replays historical news sentiment from articles/sentiments tables
- Shares code with live system (same strategies, same signal generation)
- Uses simulated executor (not Alpaca)
- Configurable: date range, initial capital, commission model, slippage, strategy weights
- Output: trade log, equity curve, Sharpe, max drawdown, win rate, per-strategy attribution
## Dashboard Views
1. **Portfolio Overview** - Value, daily P&L, equity curve, open positions, key metrics
2. **Trade Log** - All trades with expandable detail (news context, strategies, ROI, profitable badge)
3. **Strategy Performance** - Per-strategy metrics, weight allocation, weight history, adjustments log
4. **News & Sentiment Feed** - Live processed articles, ticker filtering, correlation view
5. **Backtesting** - Config form, results dashboard, multi-run comparison
Real-time updates via WebSocket. Toast notifications for trade executions.
## Project Structure
```
trading-bot/
├── services/
│ ├── news-fetcher/
│ ├── sentiment-analyzer/
│ ├── signal-generator/
│ ├── trade-executor/
│ ├── learning-engine/
│ └── api-gateway/
├── dashboard/
├── shared/
│ ├── models/ # SQLAlchemy models
│ ├── schemas/ # Pydantic schemas
│ ├── broker/ # Brokerage abstraction layer
│ └── strategies/ # Strategy implementations
├── backtester/
├── docker/ # Dockerfiles per service
├── docker-compose.yml # Full stack orchestration
├── tests/
├── alembic/ # Database migrations
└── docs/plans/
```
## Key Libraries
**Backend:** FastAPI, SQLAlchemy (async), alpaca-py, transformers (FinBERT), praw, redis-py, websockets, ollama-python
**Frontend:** React 18, TypeScript, TanStack Query, Recharts or TradingView lightweight-charts, Tailwind CSS
**ML:** transformers (FinBERT), ollama, numpy, pandas
**Testing:** pytest, pytest-asyncio, React Testing Library
## Brokerage Choice
Alpaca is the primary brokerage:
- Free API, commission-free US equity trading
- Built-in paper trading (sandbox environment)
- Official Python SDK (alpaca-py): market/limit/stop/trailing-stop orders
- REST + WebSocket + SSE endpoints
- Built-in NewsClient for financial news
- 200 requests/minute rate limit
- $0 minimum balance
An abstraction layer in `shared/broker/` allows adding other brokerages (Interactive Brokers, Tradier) later without changing strategy or execution logic.
## Docker Compose Services
- `news-fetcher` - Python service
- `sentiment-analyzer` - Python service (needs GPU access or CPU for FinBERT)
- `signal-generator` - Python service
- `trade-executor` - Python service
- `learning-engine` - Python service
- `api-gateway` - Python (FastAPI) service
- `dashboard` - Node/nginx serving React build
- `postgres` - PostgreSQL 16 + TimescaleDB extension
- `redis` - Redis 7 with Streams
- `ollama` - Ollama server for local LLM inference