Initial commit: invest-copilot app

This commit is contained in:
2026-05-30 11:29:20 -04:00
commit c70d6035cc
193 changed files with 22423 additions and 0 deletions
+46
View File
@@ -0,0 +1,46 @@
# Invest Copilot — Vision & Positioning
## One-Liner
AI-native investment research and portfolio copilot for retail investors who want institutional-grade intelligence.
## The Problem
Retail investors have three choices:
1. **Free but shallow** — Yahoo Finance, Finviz, TradingView (free tier). No AI analysis. No alternative data. No smart alerts.
2. **Expensive & clunky** — Bloomberg Terminal ($25k/year), Koyfin ($300+/year), Morningstar. Legacy UI. No AI.
3. **Manual** — Read SEC filings, scan Reddit, track options flow across 10+ tabs. Time-inefficient, emotion-driven.
## Our Edge (Why This Wins)
| Capability | TradingView | Koyfin | Bloomberg | **Invest Copilot** |
|---|---|---|---|---|
| Real-time charts | ✅ | ✅ | ✅ | ✅ |
| Screener | ✅ basic | ✅ basic | ✅ pro | ✅ AI-assisted |
| SEC filing analysis | ❌ | ❌ | ✅ $25k/yr | ✅ LLM-powered |
| Insider trades | ✅ | ✅ | ✅ | ✅ + clustering signals |
| Institutional ownership | ✅ | ✅ | ✅ | ✅ + 13G amendment tracking |
| Alternative data | ❌ | ❌ | ✅ paid | ✅ free tier + paid |
| Sentiment analysis | ❌ | ❌ | ✅ paid | ✅ multi-source |
| Sector rotation alerts | ❌ | ❌ | ✅ | ✅ automated |
| Strategy backtesting | Pine Script only | ❌ | ✅ | ✅ multi-strategy |
| Watchlist agents | ❌ | ❌ | ❌ | ✅ intelligent alerts |
| Mobile-first UX | ❌ | ❌ | ❌ | ✅ native PWA |
| AI copilot chat | ❌ | ❌ | ❌ | ✅ context-aware |
## Target User
- Self-directed retail investors with $5k-$500k portfolios
- Tech-comfortable (use Robinhood, Webull, or similar)
- Want institutional-grade data without institutional price tags
- Active traders (swing trading, position trading)
- Value-time-rich (willing to research but want tools to accelerate)
## Core Principles
1. **Data depth first** — Better data than free tools, approachable pricing
2. **AI as amplifier, not replacement** — LLMs synthesize, humans decide
3. **Mobile-first PWA** — Works on phone, tablet, desktop. No app store dependency.
4. **Open data, open strategies** — Community-contributed strategies (like TradingView's Pine Script)
5. **Privacy-first** — Watchlists, strategies, and alerts are private
## Success Metrics
- **Day 1**: User can search a stock, see full profile, and get AI analysis in <10 seconds
- **Month 1**: User creates watchlist, applies 2 strategies, receives 1+ actionable alert
- **Month 3**: User has 3+ active watchlists, 5+ strategies, sector rotation alerts firing
- **Month 6**: User's strategy backtest results beat buy-and-hold by >5% annualized
+197
View File
@@ -0,0 +1,197 @@
# Invest Copilot — Architecture
## Tech Stack
### Frontend (SPA + Mobile-First PWA)
| Layer | Choice | Why |
|---|---|---|
| Framework | **Next.js 15** (App Router) | SSR for SEO, API routes for BFF, mature ecosystem |
| Language | **TypeScript 5** | Type safety across all layers |
| Styling | **TailwindCSS + Radix UI** | Design system foundation, accessible primitives |
| State | **Zustand** | Lightweight, no boilerplate, perfect for PWA |
| Charts | **Lightweight Charts (TradingView)** | Professional-grade financial charts |
| Real-time | **Server-Sent Events (SSE)** | Push alerts to browser, simpler than WebSockets |
| PWA | **next-pwa** | Offline support, installable, service worker |
| AI/LLM | **OpenAI GPT-4o / Claude Sonnet** | Context-aware copilot, SEC filing analysis |
### Backend (Node.js + Python Microservices)
| Service | Language | Why |
|---|---|---|
| API Gateway / BFF | **Node.js + Fastify** | TypeScript, fast, handles auth + routing |
| Data Pipeline | **Python 3.12+** | yfinance, SEC EDGAR, sentiment analysis, ML |
| Strategy Engine | **Python 3.12+** | Backtesting, signal generation, portfolio analytics |
| Alert Agent | **Python + APScheduler** | Scheduled monitoring, notification dispatch |
| Cache | **Redis** | Session store, rate limiting, hot data cache |
### Data Layer
| Source | Storage | Purpose |
|---|---|---|
| Market data (OHLCV) | **PostgreSQL + TimescaleDB** | Time-series price data, efficient queries |
| SEC filings | **PostgreSQL (JSONB)** | Structured filing data, full-text search |
| Alternative data | **PostgreSQL** | Sentiment scores, insider trades, institutional data |
| User data | **PostgreSQL** | Watchlists, strategies, screeners, preferences |
| Cache/realtime | **Redis** | Session state, rate limiting, real-time alerts |
| File storage | **S3-compatible (MinIO)** | SEC filing PDFs, backtest reports, exports |
### Infrastructure
| Component | Choice | Why |
|---|---|---|
| Container | **Docker Compose** (dev), **K8s** (prod) | Dev simplicity, prod scalability |
| CI/CD | **GitHub Actions** | Free, mature, integrates with everything |
| Monitoring | **Prometheus + Grafana** | Metrics, alerting, dashboards |
| Logging | **Loki** (via Docker Compose) | Structured logs, queryable |
| Domain | Self-hosted | Full control, no vendor lock-in |
## Architecture Diagram (Text)
```
┌─────────────────────────────────────────────────────────────────┐
│ CLIENT LAYER │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────────┐ │
│ │ Web App │ │ Mobile │ │ Tablet │ │ Desktop (PWA) │ │
│ │ (PWA) │ │ (PWA) │ │ (PWA) │ │ (installable) │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────────┬────────┘ │
│ │ │ │ │ │
│ └──────────────┴──────────────┴──────────────────┘ │
│ │ HTTPS / SSE │
├──────────────────────────────────────────────────────────────────┤
│ API GATEWAY (Node.js + Fastify) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────────┐ │
│ │ Auth │ │ Routing │ │ Rate │ │ Request │ │
│ │ (JWT) │ │ │ │ Limit │ │ Validation │ │
│ └──────────┘ └──────────┘ └──────────┘ └─────────────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ SERVICE LAYER │
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────────────┐ │
│ │ Stock │ │ Strategy │ │ Watchlist & Alert │ │
│ │ Service │ │ Engine │ │ Agent Service │ │
│ │ (Node.js) │ │ (Python) │ │ (Python + APSched) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────────┬────────────┘ │
│ │ │ │ │
│ ┌──────┴──────────────────┴──────────────────────┴──────────┐ │
│ │ DATA ACCESS LAYER │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ │ │
│ │ │PostgreSQL│ │ Timescale│ │ Redis │ │ MinIO │ │ │
│ │ │(user) │ │ (prices) │ │ (cache) │ │ (files) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └───────────┘ │ │
│ └───────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ DATA SOURCE LAYER │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────────┐ │
│ │ Massive │ │ Finnhub │ │ SEC │ │ Alternative │ │
│ │ / │ │ │ │ EDGAR │ │ Data Sources │ │
│ │ Polygon │ │ (free) │ │ │ │ (Reddit, │ │
│ └──────────┘ └──────────┘ └──────────┘ │ GDELT, │ │
│ │ yfinance) │ │
│ └─────────────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ AI / LAYER │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────────┐ │
│ │ SEC │ │ Sentiment│ │ Copilot │ │ Sector │ │
│ │ Filing │ │ Analysis │ │ Chat │ │ Rotation │ │
│ │ Parser │ │ (NLP) │ │ Agent │ │ Detection │ │
│ └──────────┘ └──────────┘ └──────────┘ └─────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
```
## Data Flow
### Stock Search & Profile
```
User searches "AAPL"
→ API Gateway validates request
→ Stock Service checks Redis cache (TTL: 5 min)
→ If miss: fetches from Massive/Polygon API
→ Enriches with:
- SEC filings (last 4 quarters)
- Insider trades (last 90 days)
- Institutional ownership
- News + sentiment (Finnhub)
- Peer group relative strength
→ Returns to frontend
→ AI Copilot generates summary analysis
```
### Watchlist Monitoring
```
User creates watchlist "AI Winners" with 10 stocks
→ Alert Agent subscribes to each ticker
→ Every 5 minutes:
- Check price vs strategy triggers
- Scan for new SEC filings (8-K, 4)
- Check news sentiment shift
- Check options unusual activity
→ If trigger fires:
- Generate alert message via AI
- Push via SSE to frontend
- Store alert in DB
- Optional: email/push notification
```
### Sector Rotation Detection
```
Every 24 hours at 6:00 AM UTC:
→ Fetch OHLCV for 11 sector ETFs
→ Compute: 20-day, 50-day, 200-day momentum
→ Rank sectors by relative strength vs SPY
→ Compare to previous day's ranking
→ If rank change ≥ 3: rotation detected
→ Generate analysis:
- What sector entered/rotated out
- Macro context (yield curve, inflation)
- Recommended ETF allocations
→ Store rotation event
→ Push to users with active sector rotation alerts
```
## Migration Strategy (Design → TDD → DDD)
### Phase 1: Design-Driven (Weeks 1-3)
- Use **Open Design** to generate UI mockups and visual directions
- Build frontend shell with static data
- Define API contracts (OpenAPI/Swagger)
- Set up CI/CD pipeline
- **Deliverable**: Clickable prototype, API spec, deployed pipeline
### Phase 2: Backend Foundation (Weeks 4-6)
- Implement data ingestion pipeline (Python)
- Build PostgreSQL + TimescaleDB schema
- Implement core API (Node.js/Fastify)
- Set up Redis cache layer
- **Deliverable**: Working data pipeline, REST API with real data
### Phase 3: TDD Frontend (Weeks 7-10)
- Implement stock search + profile (with tests)
- Implement watchlist management (with tests)
- Implement charting (with tests)
- Implement strategy engine (with tests)
- **Deliverable**: Functional SPA with 80%+ test coverage
### Phase 4: DDD Domain Layer (Weeks 11-14)
- Define domain models (Stock, Watchlist, Strategy, Screener)
- Implement aggregate roots and bounded contexts
- Implement domain events (RotationDetected, AlertTriggered)
- Implement CQRS for read/write separation
- **Deliverable**: Clean architecture with DDD primitives
### Phase 5: AI Integration (Weeks 15-18)
- SEC filing parser + NLP analysis
- Copilot chat interface
- Sentiment analysis pipeline
- Alternative data fusion
- **Deliverable**: AI-powered analysis on every stock page
### Phase 6: Alert Engine (Weeks 19-22)
- Watchlist monitoring agents
- Strategy trigger evaluation
- SSE notification system
- Email/push notification dispatch
- **Deliverable**: Real-time intelligent alerts
### Phase 7: Polish & Scale (Weeks 23-26)
- Performance optimization
- Load testing
- Security hardening
- UX polish
- Mobile PWA optimization
- **Deliverable**: Production-ready invest-copilot
+470
View File
@@ -0,0 +1,470 @@
# Invest Copilot — Data Model
## Entity-Relationship Overview
```
┌──────────────┐ ┌──────────────┐ ┌──────────────────┐
│ User │ │ Watchlist │ │ Screener │
│──────────────│ │──────────────│ │──────────────────│
│ id (PK) │◄──┐ │ id (PK) │ │ id (PK) │
│ email │ │ │ name │ │ name │
│ name │ │ │ user_id (FK) │ │ user_id (FK) │
│ avatar_url │ │ │ created_at │ │ created_at │
│ timezone │ │ │ updated_at │ │ conditions (JSONB)│
│ settings │ └────┬───────────┘ │ conditions_json │
│ created_at │ │ │ created_at │
└──────────────┘ │ └──────────────────┘
│
│ ┌──────────────────┐
└───►│ WatchlistItem │
│──────────────────│
│ id (PK) │
│ watchlist_id (FK)│
│ ticker │
│ type (stock/etf) │
│ added_at │
│ custom_notes │
└────────┬─────────┘
│
│ ┌──────────────────┐
└───►│ PriceHistory │
│──────────────────│
│ id (PK) │
│ ticker │
│ date (Timescale) │
│ open │
│ high │
│ low │
│ close │
│ volume │
│ adjusted_close │
└────────────────────┘
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Strategy │ │ WatchlistStrategy│ │ Alert │
│──────────────────│ │──────────────────│ │──────────────────│
│ id (PK) │◄────│ id (PK) │ │ id (PK) │
│ user_id (FK) │ │ watchlist_id(FK) │ │ watchlist_id(FK) │
│ name │ │ strategy_id(FK) │ │ strategy_id(FK) │
│ description │ │ is_active │ │ type │
│ type (technical/ │ │ created_at │ │ trigger_type │
│ fundamental) │ │ conditions (JSONB)│ │ message_template │
│ conditions (JSONB)│ │ created_at │ │ triggered_at │
│ backtest_result │ │ updated_at │ │ resolved_at │
│ created_at │ └────────┬─────────┘ │ resolved_at │
│ updated_at │ │ │ created_at │
└──────────────────┘ │ └──────────────────┘
│
│ ┌──────────────────┐
└───►│ SectorRotation │
│──────────────────│
│ id (PK) │
│ date │
│ sector_ticker │
│ rank_now │
│ rank_previous │
│ rank_change │
│ momentum_20d │
│ momentum_50d │
│ momentum_200d │
│ relative_strength │
│ rotation_signal │
│ macro_context │
│ analysis_summary │
└────────────────────┘
```
## Detailed Schema
### users
```sql
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255), -- NULL if OAuth-only
name VARCHAR(255),
avatar_url TEXT,
timezone VARCHAR(50) DEFAULT 'UTC',
settings JSONB DEFAULT '{}', -- {currency: 'USD', theme: 'dark', alerts_enabled: true}
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
```
### watchlists
```sql
CREATE TABLE watchlists (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
description TEXT,
is_default BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_watchlists_user ON watchlists(user_id);
```
### watchlist_items
```sql
CREATE TABLE watchlist_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
watchlist_id UUID NOT NULL REFERENCES watchlists(id) ON DELETE CASCADE,
ticker VARCHAR(20) NOT NULL,
type VARCHAR(20) NOT NULL CHECK (type IN ('stock', 'etf', 'index')),
custom_notes TEXT,
added_at TIMESTAMPTZ DEFAULT NOW()
);
-- Prevent duplicates: a watchlist can't have the same ticker twice
CREATE UNIQUE INDEX idx_watchlist_items_unique ON watchlist_items(watchlist_id, ticker);
```
### prices (TimescaleDB hypertable)
```sql
-- Hypertable for time-series price data
CREATE TABLE prices (
ticker VARCHAR(20) NOT NULL,
date TIMESTAMPTZ NOT NULL,
open DECIMAL(15,4),
high DECIMAL(15,4),
low DECIMAL(15,4),
close DECIMAL(15,4),
volume BIGINT,
adjusted_close DECIMAL(15,4),
PRIMARY KEY (ticker, date)
);
-- Convert to hypertable (TimescaleDB extension)
SELECT create_hypertable('prices', 'date');
-- Compression for older data (automated by Timescale policy)
CREATE POLICY prices_compress_policy ON prices
FOR ALL
USING (date < NOW() - INTERVAL '90 days');
-- Continuous aggregate for common timeframes
CREATE MATERIALIZED VIEW prices_daily
WITH (timescaledb.continuous) AS
SELECT ticker,
time_bucket('1 day', date) AS bucket,
first(open, date) AS open,
max(high) AS high,
min(low) AS low,
last(close, date) AS close,
sum(volume) AS volume
FROM prices
GROUP BY ticker, bucket;
```
### stock_profiles
```sql
CREATE TABLE stock_profiles (
ticker VARCHAR(20) PRIMARY KEY,
name VARCHAR(500),
exchange VARCHAR(20),
sector VARCHAR(100),
industry VARCHAR(200),
market_cap BIGINT,
description TEXT,
website TEXT,
ceo VARCHAR(255),
employees INTEGER,
pe_ratio DECIMAL(10,2),
eps DECIMAL(10,4),
dividend_yield DECIMAL(8,4),
beta DECIMAL(6,4),
last_updated TIMESTAMPTZ DEFAULT NOW()
);
```
### sec_filings
```sql
CREATE TABLE sec_filings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ticker VARCHAR(20) NOT NULL,
cik VARCHAR(20),
form_type VARCHAR(10) NOT NULL, -- 10-K, 10-Q, 8-K, 4, 13F, 13D, 13G
filing_date DATE NOT NULL,
report_date DATE,
accession_number VARCHAR(50),
url TEXT,
content_summary TEXT, -- AI-generated summary
key_metrics JSONB, -- Extracted financials from 10-K/10-Q
sentiment_score DECIMAL(5,4), -- NLP sentiment: -1 to +1
tags TEXT[], -- e.g., ['earnings', 'executive_change', 'litigation']
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_sec_filings_ticker ON sec_filings(ticker);
CREATE INDEX idx_sec_filings_form ON sec_filings(form_type);
CREATE INDEX idx_sec_filings_date ON sec_filings(filing_date);
```
### insider_trades
```sql
CREATE TABLE insider_trades (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ticker VARCHAR(20) NOT NULL,
insider_name VARCHAR(500),
insider_title VARCHAR(500),
transaction_date DATE NOT NULL,
transaction_type VARCHAR(10), -- Buy, Sell, Gift, In-Ex
shares INTEGER,
price_per_share DECIMAL(10,4),
total_value DECIMAL(15,4),
shares_owned_after INTEGER,
filing_date DATE,
source_url TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_insider_trades_ticker ON insider_trades(ticker);
CREATE INDEX idx_insider_trades_type ON insider_trades(transaction_type);
```
### strategies
```sql
CREATE TABLE strategies (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
description TEXT,
type VARCHAR(20) NOT NULL CHECK (type IN ('technical', 'fundamental', 'hybrid')),
conditions JSONB NOT NULL, -- Structured strategy conditions
backtest_results JSONB, -- Last backtest result
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
```
### strategy_conditions (JSONB schema example)
```json
{
"type": "technical",
"rules": [
{
"indicator": "rsi",
"operator": "lt",
"value": 30,
"description": "RSI below 30 (oversold)"
},
{
"indicator": "sma",
"params": {"period": 200, "source": "close"},
"operator": "gt",
"value": null,
"description": "Price above 200-day SMA"
},
{
"indicator": "volume",
"operator": "gt",
"value": 1.5,
"description": "Volume > 1.5x average 20-day volume"
}
],
"logic": "AND"
}
```
### watchlist_strategies
```sql
CREATE TABLE watchlist_strategies (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
watchlist_id UUID NOT NULL REFERENCES watchlists(id) ON DELETE CASCADE,
strategy_id UUID NOT NULL REFERENCES strategies(id) ON DELETE CASCADE,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE UNIQUE INDEX idx_watchlist_strategies_unique ON watchlist_strategies(watchlist_id, strategy_id);
```
### alerts
```sql
CREATE TABLE alerts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
watchlist_id UUID NOT NULL REFERENCES watchlists(id) ON DELETE CASCADE,
strategy_id UUID REFERENCES strategies(id),
ticker VARCHAR(20),
type VARCHAR(30) NOT NULL, -- strategy_trigger, sec_filing, sentiment, rotation, price
trigger_type VARCHAR(50),
message TEXT NOT NULL,
severity VARCHAR(10) DEFAULT 'info' CHECK (severity IN ('info', 'warning', 'critical')),
status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'resolved', 'dismissed')),
triggered_at TIMESTAMPTZ DEFAULT NOW(),
resolved_at TIMESTAMPTZ,
metadata JSONB DEFAULT '{}'
);
CREATE INDEX idx_alerts_watchlist ON alerts(watchlist_id);
CREATE INDEX idx_alerts_status ON alerts(status);
CREATE INDEX idx_alerts_triggered ON alerts(triggered_at);
```
### sector_rotations
```sql
CREATE TABLE sector_rotations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
detection_date DATE NOT NULL,
sector_ticker VARCHAR(20) NOT NULL, -- XLK, XLF, etc.
sector_name VARCHAR(100),
rank_now INTEGER,
rank_previous INTEGER,
rank_change INTEGER,
momentum_20d DECIMAL(8,4),
momentum_50d DECIMAL(8,4),
momentum_200d DECIMAL(8,4),
relative_strength DECIMAL(8,4),
rotation_signal VARCHAR(20), -- 'in', 'out', 'stable', 'accelerating'
macro_context JSONB,
analysis_summary TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_sector_rotations_date ON sector_rotations(detection_date);
CREATE INDEX idx_sector_rotations_signal ON sector_rotations(rotation_signal);
```
### screeners
```sql
CREATE TABLE screeners (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
description TEXT,
conditions JSONB NOT NULL,
results_count INTEGER DEFAULT 0,
last_run_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
```
### screener_results
```sql
CREATE TABLE screener_results (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
screener_id UUID NOT NULL REFERENCES screeners(id) ON DELETE CASCADE,
ticker VARCHAR(20) NOT NULL,
match_score DECIMAL(5,4),
ranked_position INTEGER,
result_data JSONB,
generated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_screener_results_screener ON screener_results(screener_id);
```
### peer_groups
```sql
CREATE TABLE peer_groups (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ticker VARCHAR(20) NOT NULL,
peer_ticker VARCHAR(20) NOT NULL,
similarity_score DECIMAL(5,4), -- Based on sector, industry, market cap
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE (ticker, peer_ticker)
);
CREATE INDEX idx_peer_groups_ticker ON peer_groups(ticker);
```
### rotation_alerts_preferences
```sql
CREATE TABLE rotation_alert_preferences (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
sectors TEXT[] NOT NULL DEFAULT '{}', -- ['tech', 'healthcare', 'energy', ...]
min_rank_change INTEGER DEFAULT 2,
email_enabled BOOLEAN DEFAULT TRUE,
push_enabled BOOLEAN DEFAULT TRUE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
```
## TimescaleDB Optimization
### Compression Policy
```sql
-- Compress data older than 90 days
SELECT add_compress_policy('prices', INTERVAL '90 days');
-- Reorder by ticker for better compression
SELECT add_reorder_policy('prices', 'ticker');
```
### Continuous Aggregates
```sql
-- 1-hour aggregates for intraday analysis
CREATE MATERIALIZED VIEW prices_hourly
WITH (timescaledb.continuous) AS
SELECT ticker,
time_bucket('1 hour', date) AS bucket,
first(open, date) AS open,
max(high) AS high,
min(low) AS low,
last(close, date) AS close,
sum(volume) AS volume
FROM prices
GROUP BY ticker, bucket;
-- 1-day aggregates for trend analysis
CREATE MATERIALIZED VIEW prices_daily
WITH (timescaledb.continuous) AS
SELECT ticker,
time_bucket('1 day', date) AS bucket,
first(open, date) AS open,
max(high) AS high,
min(low) AS low,
last(close, date) AS close,
sum(volume) AS volume
FROM prices
GROUP BY ticker, bucket;
```
### Indexes for Common Queries
```sql
-- Composite indexes for frequent query patterns
CREATE INDEX idx_prices_ticker_date ON prices(ticker, date DESC);
CREATE INDEX idx_prices_date_ticker ON prices(date, ticker);
CREATE INDEX idx_sec_filings_ticker_type ON sec_filings(ticker, form_type);
CREATE INDEX idx_insider_trades_ticker_date ON insider_trades(ticker, transaction_date DESC);
```
## Data Ingestion Pipeline
```
┌─────────────────────────────────────────────────────────────┐
│ DATA INGESTION PIPELINE │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ Price │ │ SEC │ │ Alternative │ │
│ │ Ingestor │ │ Filing │ │ Data │ │
│ │ (hourly) │ │ Parser │ │ Pipeline │ │
│ │ │ │ (daily) │ │ (daily) │ │
│ └──────┬──────┘ └──────┬──────┘ └────────┬────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ PostgreSQL + TimescaleDB │ │
│ │ (prices, sec_filings, insider_trades) │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### Ingestion Schedules
| Data | Source | Frequency | Rate Limit |
|---|---|---|---|
| OHLCV (1min) | Massive/Polygon | Every 1 min (market hours) | Unlimited (paid tier) |
| OHLCV (1day) | Massive/Polygon | Daily close | Unlimited (paid tier) |
| SEC filings | EDGAR RSS/API | Every 15 min | 10 req/sec |
| Insider trades | EDGAR | Every 6 hours | 10 req/sec |
| Institutional holdings | EDGAR 13F | Quarterly (Feb, May, Aug, Nov) | 10 req/sec |
| Company news | Finnhub | Every 5 min | 60 req/min (free) |
| Sentiment scores | Finnhub + NLP pipeline | Every hour | Internal |
| Sector rotation | Computed from prices | Daily 6 AM UTC | Internal |
| Google Trends | pytrends | Daily | Rate limited |
| Reddit sentiment | Reddit API | Every 6 hours | Rate limited |
+374
View File
@@ -0,0 +1,374 @@
# Invest Copilot — Domain Model (DDD)
## Bounded Contexts
```
┌─────────────────────────────────────────────────────────────────┐
│ INVEST COPILOT SYSTEM │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────────────┐ │
│ │ RESEARCH │ │ PORTFOLIO │ │ ALERTEVENTS │ │
│ │ CONTEXT │ │ CONTEXT │ │ CONTEXT │ │
│ │ │ │ │ │ │ │
│ │ Stock │ │ Watchlist │ │ Watchlist │ │
│ │ Profile │ │ Strategy │ │ Agent │ │
│ │ Peer Group │ │ Screener │ │ Alert Engine │ │
│ │ SEC Filing │ │ Backtest │ │ Notification │ │
│ │ Sentiment │ │ Rotation │ │ Monitoring │ │
│ └──────┬───────┘ └──────┬───────┘ └──────────┬──────────┘ │
│ │ │ │ │
│ │ ┌──────────────┴──────────────────────┐ │
│ │ │ SHARED KERNEL │ │
│ │ │ MarketData, Ticker, Sector, │ │
│ │ │ PriceEvent, SectorRotation │ │
│ │ └───────────────────────────────────────┘ │
│ │
├──────────────────────────────────────────────────────────────────┤
│ APPLICATION LAYER │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────────┐ │
│ │ Stock │ │ Watch │ │ Strategy│ │ Alert │ │
│ │ Service │ │ list │ │ Service │ │ Service │ │
│ └──────────┘ └──────────┘ └──────────┘ └─────────────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ DOMAIN LAYER │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────────┐ │
│ │ Stock │ │ Watch- │ │ Strategy │ │ Alert │ │
│ │ Entity │ │ list │ │ Entity │ │ Entity │ │
│ │ Aggr │ │ Aggr │ │ Aggr │ │ Aggr │ │
│ └──────────┘ └──────────┘ └──────────┘ └─────────────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ INFRASTRUCTURE LAYER │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────────┐ │
│ │ Price │ │ SEC │ │ Strategy│ │ SSE │ │
│ │ Rep │ │ Rep │ │ Rep │ │ Push │ │
│ └──────────┘ └──────────┘ └──────────┘ └─────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
```
## Bounded Context 1: RESEARCH
**Responsibility**: Provide comprehensive stock information and analysis.
### Entities & Value Objects
```
Stock (Aggregate Root)
├── ticker: Ticker
├── name: string
├── sector: Sector (Value Object)
├── industry: string
├── marketCap: Money (Value Object)
├── exchange: string
└── profile: CompanyProfile (Value Object)
CompanyProfile (Value Object)
├── description: string
├── website: string
├── ceo: string
├── employees: int
├── peRatio: decimal
├── eps: decimal
├── dividendYield: decimal
└── beta: decimal
Sector (Value Object)
├── code: string // e.g., "XLK"
├── name: string // e.g., "Technology"
├── gicsCode: string // e.g., "45"
└── peers: List<Ticker>
PeerGroup (Aggregate Root)
├── ticker: Ticker
├── peers: List<Peer>
└── similarityScores: Map<Ticker, float>
Peer (Value Object)
├── ticker: Ticker
├── name: string
├── similarityScore: float
└── relativeStrength: decimal
SecFiling (Entity within Stock aggregate)
├── formType: FormType (enum: 10K, 10Q, 8K, 4, 13F, 13D, 13G)
├── filingDate: Date
├── reportDate: Date
├── accessionNumber: string
├── url: string
├── contentSummary: string
├── sentimentScore: decimal
└── tags: List<string>
InsiderTrade (Entity within Stock aggregate)
├── insiderName: string
├── insiderTitle: string
├── transactionDate: Date
├── transactionType: TransactionType (enum: BUY, SELL, GIFT, IN_EX)
├── shares: int
├── pricePerShare: Money
├── totalValue: Money
└── sharesOwnedAfter: int
SentimentSignal (Value Object)
├── source: string // "finnhub", "reddit", "gdelt"
├── score: decimal // -1.0 to +1.0
├── confidence: float
├── timestamp: DateTime
└── context: string
```
### Domain Events
- `StockProfileUpdated` — Stock profile refreshed from data source
- `SecFilingReceived` — New SEC filing detected
- `InsiderTradeDetected` — New insider trade filed
- `SentimentShifted` — Sentiment score changed significantly
### Aggregates
- **Stock** is the root aggregate. All research data (filings, insider trades, sentiment, peer info) are either entities within this aggregate or related via repository.
## Bounded Context 2: PORTFOLIO (WATCHLIST + STRATEGY)
**Responsibility**: Manage watchlists, strategies, screeners, and sector rotation.
### Entities & Value Objects
```
Watchlist (Aggregate Root)
├── id: UUID
├── name: string
├── owner: UserId
├── items: List<WatchlistItem>
├── strategies: List<StrategyReference>
└── created/updated timestamps
WatchlistItem (Entity)
├── ticker: Ticker
├── type: AssetType (enum: STOCK, ETF, INDEX)
├── addedAt: DateTime
├── customNotes: string
└── priceAtAddition: Money
Strategy (Aggregate Root)
├── id: UUID
├── name: string
├── description: string
├── type: StrategyType (enum: TECHNICAL, FUNDAMENTAL, HYBRID)
├── conditions: StrategyConditions (Value Object)
├── backtestResults: BacktestResult (Value Object)
├── createdBy: UserId
└── created/updated timestamps
StrategyConditions (Value Object)
├── rules: List<StrategyRule>
├── logic: LogicOperator (AND / OR)
└── timeframe: string // e.g., "1D", "1W", "1M"
StrategyRule (Value Object)
├── indicator: string // "rsi", "sma", "macd", "pe_ratio", etc.
├── operator: Operator (enum: LT, GT, LTE, GTE, EQ, NEQ, CROSSOVER, CROSSBELOW)
├── value: decimal
├── period: int // optional, for indicators like SMA
├── source: string // optional, for SMA: "close", "volume"
└── description: string
BacktestResult (Value Object)
├── startDate: Date
├── endDate: Date
├── totalReturn: decimal
├── annualizedReturn: decimal
├── maxDrawdown: decimal
├── sharpeRatio: decimal
├── winRate: float
├── totalTrades: int
├── avgHoldTime: string
└── equityCurve: List<Decimal>
Screener (Aggregate Root)
├── id: UUID
├── name: string
├── description: string
├── conditions: ScreenerConditions (Value Object)
├── lastRunAt: DateTime
├── createdBy: UserId
└── results: List<ScreenerResult> (stored in screener_results table)
ScreenerConditions (Value Object)
├── filters: List<ScreenerFilter>
├── sortBy: string
├── sortOrder: string // "asc" / "desc"
└── limit: int
ScreenerFilter (Value Object)
├── field: string // "market_cap", "pe_ratio", "rsi", etc.
├── operator: Operator
├── value: decimal
└── description: string
SectorRotation (Entity within Watchlist context)
├── date: Date
├── sector: Sector
├── rankNow: int
├── rankPrevious: int
├── rankChange: int
├── momentum20d: decimal
├── momentum50d: decimal
├── momentum200d: decimal
├── relativeStrength: decimal
├── signal: RotationSignal (enum: IN, OUT, STABLE, ACCELERATING)
├── macroContext: jsonb
└── analysisSummary: string
```
### Domain Events
- `WatchlistCreated` — New watchlist created
- `WatchlistItemAdded` — Ticker added to watchlist
- `WatchlistItemRemoved` — Ticker removed from watchlist
- `StrategyCreated` — New strategy defined
- `StrategyTriggered` — Strategy condition met for a ticker
- `SectorRotationDetected` — Sector rotation event
- `ScreenerResultsGenerated` — Screener completed run
### Aggregates
- **Watchlist** is the root. Items and strategies are entities within it.
- **Strategy** is independent (can be shared across watchlists).
- **Screener** is independent per user.
- **SectorRotation** is stored as events, queried for history.
## Bounded Context 3: ALERTEVENTS
**Responsibility**: Monitor watchlists, evaluate triggers, dispatch notifications.
### Entities & Value Objects
```
Alert (Aggregate Root)
├── id: UUID
├── watchlist: Watchlist (reference)
├── strategy: Strategy? (nullable, some alerts are non-strategy)
├── ticker: Ticker
├── type: AlertType (enum: STRATEGY_TRIGGER, SEC_FILING, SENTIMENT, ROTATION, PRICE)
├── triggerType: string
├── message: string
├── severity: Severity (enum: INFO, WARNING, CRITICAL)
├── status: AlertStatus (enum: ACTIVE, RESOLVED, DISMISSED)
├── triggeredAt: DateTime
├── resolvedAt: DateTime?
└── metadata: jsonb
AlertTrigger (Value Object)
├── source: string // strategy name, filing type, etc.
├── condition: string // what triggered
├── currentValue: decimal
├── thresholdValue: decimal
└── timestamp: DateTime
Notification (Value Object)
├── channel: NotificationChannel (enum: SSE, EMAIL, PUSH)
├── recipient: UserId
├── alertId: UUID
├── sentAt: DateTime
├── delivered: boolean
└── error: string?
```
### Domain Events
- `AlertTriggered` — Alert condition met
- `AlertResolved` — Alert condition no longer applies
- `AlertDismissed` — User dismissed alert
- `NotificationSent` — Alert dispatched via channel
- `NotificationFailed` — Delivery failed
### Aggregates
- **Alert** is the root aggregate.
- Notifications are derived from alerts (not part of the same aggregate).
## Shared Kernel
These concepts are shared across bounded contexts with consistent definitions:
```
Ticker (Value Object)
├── symbol: string // e.g., "AAPL"
├── exchange: string // e.g., "NASDAQ"
└── isPrimary: boolean // for tickers with multiple listings
Sector (Value Object)
├── code: string // e.g., "XLK"
├── name: string // e.g., "Technology"
└── gicsCode: string // e.g., "45"
PriceEvent (Value Object)
├── date: DateTime
├── open: Money
├── high: Money
├── low: Money
├── close: Money
└── volume: long
Money (Value Object)
├── amount: decimal
├── currency: string // ISO 4217
UserId (Value Object)
├── id: UUID
└── email: string
```
## Anti-Corruption Layer
**External APIs → Domain Models**:
- Massive/Polygon API → PriceEvent (no external IDs leak in)
- SEC EDGAR → SecFiling (parse raw XML/JSON, produce clean domain object)
- Finnhub → SentimentSignal, InsiderTrade, NewsEvent
- Reddit API → SentimentSignal (from subreddit analysis)
- FRED → MacroeconomicData (for sector rotation context)
**Pattern**: Every external data source has a dedicated adapter that translates API responses into our domain models. No external schema leaks into the domain layer.
## Repository Interfaces (Domain Layer)
```typescript
// Domain layer defines interfaces, infrastructure implements them
interface IStockRepository {
findByTicker(ticker: Ticker): Promise<Stock | null>
findByTickers(tickers: Ticker[]): Promise<Stock[]>
save(stock: Stock): Promise<void>
getSecFilings(ticker: Ticker, limit?: number): Promise<SecFiling[]>
getInsiderTrades(ticker: Ticker, limit?: number): Promise<InsiderTrade[]>
getPeerGroup(ticker: Ticker): Promise<PeerGroup>
}
interface IPriceRepository {
getHistory(ticker: Ticker, from: Date, to: Date, interval: string): Promise<PriceEvent[]>
getLatest(ticker: Ticker): Promise<PriceEvent>
saveBatch(prices: PriceEvent[]): Promise<void>
getMomentum(ticker: Ticker, period: number): Promise<decimal>
}
interface IWatchlistRepository {
findByUser(userId: UserId): Promise<Watchlist[]>
findById(id: UUID): Promise<Watchlist | null>
save(watchlist: Watchlist): Promise<void>
addItem(watchlistId: UUID, item: WatchlistItem): Promise<void>
removeItem(watchlistId: UUID, ticker: Ticker): Promise<void>
}
interface IStrategyRepository {
findByUser(userId: UserId): Promise<Strategy[]>
findById(id: UUID): Promise<Strategy | null>
save(strategy: Strategy): Promise<void>
}
interface IAlertRepository {
findByWatchlist(watchlistId: UUID, status?: AlertStatus): Promise<Alert[]>
save(alert: Alert): Promise<void>
resolve(id: UUID): Promise<void>
dismiss(id: UUID): Promise<void>
}
interface ISectorRotationRepository {
getRotations(date: Date): Promise<SectorRotation[]>
save(rotations: SectorRotation[]): Promise<void>
getHistorical(dateFrom: Date, dateTo: Date): Promise<SectorRotation[]>
}
```
+260
View File
@@ -0,0 +1,260 @@
# Invest Copilot — Open Design Integration Guide
## What is Open Design?
Open Design is an open-source, local-first design tool that uses AI coding agents to generate:
- **UI/UX mockups** — HTML/CSS prototypes from natural language
- **Brand design systems** — Color palettes, typography, spacing, component styles
- **Visual directions** — Curated design moods (editorial, modern minimal, tech utility, etc.)
- **Interactive prototypes** — Clickable HTML/CSS that can be directly used as starting points
- **Export formats** — HTML, PDF, PPTX, MP4
It runs on any coding agent CLI (Claude Code, Codex, Cursor, Qwen, Hermes, etc.) and uses brand-grade design systems (Stripe, Linear, Vercel, Apple, etc.) as visual foundations.
## How Open Design Fits Into Our Project
### Phase 1: Visual Design Direction (Week 1)
**Goal**: Define the visual identity of Invest Copilot using Open Design.
```
Command pattern for Hermes/other CLI agents:
"Using Open Design, generate a visual direction for an AI-native investment copilot app.
Target audience: retail investors, ages 25-45, tech-savvy.
Design constraints:
- Dark mode primary (trading platforms default to dark)
- Data-dense but not cluttered (like Bloomberg but modern)
- Mobile-first responsive layouts
- Financial data visualization (charts, heatmaps, tables)
- Color palette: professional finance (deep navy, electric blue accents, green/red for gains/losses)
- Brand tone: trustworthy, intelligent, cutting-edge
- Reference: Bloomberg Terminal meets Linear.app meets TradingView
Generate 3 visual directions with:
1. Color palette in CSS custom properties (OKLch recommended by Open Design)
2. Font stack recommendation
3. Component style definitions
4. Layout spacing scale
5. Example chart and data table styling"
```
### Phase 2: UI Mockup Generation (Week 1-2)
**Goal**: Generate HTML/CSS prototypes for each key screen.
Screens to generate:
1. **Dashboard** — Watchlist overview with portfolio summary
2. **Stock Search & Profile** — Search bar, stock cards, detailed profile view
3. **Stock Detail Page** — Charts (OHLCV, volume), SEC filings, insider trades, peer comparison
4. **Watchlist Management** — Create/edit watchlists, add/remove tickers
5. **Strategy Builder** — Visual strategy condition builder
6. **Screener** — Filter-based stock screening (TradingView-style)
7. **Alerts Center** — Real-time alert feed with severity indicators
8. **Sector Rotation Dashboard** — Sector heatmaps, momentum rankings, rotation alerts
```
Command pattern:
"Generate a fully responsive HTML/CSS prototype for the [Screen Name] page.
Use the design system from [direction].
Include:
- Layout structure (mobile-first)
- All interactive elements
- Data visualization placeholders
- Responsive breakpoints
- CSS custom properties for theming
Output: Complete HTML file with embedded CSS and minimal JS for interactivity."
```
### Phase 3: Component Library (Week 2)
**Goal**: Generate reusable component specs that map to Radix UI + Tailwind.
```
Command pattern:
"Generate a component library specification for Invest Copilot using TailwindCSS.
Components:
1. StockCard — ticker, price, change %, mini-chart sparkline
2. PriceChart — OHLCV candlestick chart (placeholder for Lightweight Charts)
3. SEC Filing Card — form type, date, summary, sentiment badge
4. Insider Trade Row — name, title, transaction type, shares, value
5. Strategy Condition Builder — visual rule builder (AND/OR logic)
6. Screener Filter — field selector, operator, value input
7. Alert Badge — severity-based color coding (info/warning/critical)
8. Sector Heatmap — color-coded sector performance grid
9. Watchlist Table — sortable, filterable ticker list
10. Navigation — mobile-first bottom nav + desktop sidebar
For each component:
- HTML structure
- TailwindCSS classes
- State variants (hover, active, disabled, error)
- Responsive behavior
- Accessibility attributes (ARIA)"
```
### Phase 4: Brand Design System (Week 2-3)
**Goal**: Create a complete design token system using Open Design's brand-grade systems.
```
Design tokens structure:
{
"color": {
"background": {
"primary": "OKLch(0.08 0 0)", // near-black
"secondary": "OKLch(0.12 0 0)", // dark gray
"tertiary": "OKLch(0.18 0 0)" // lighter gray
},
"surface": {
"card": "OKLch(0.15 0 0)",
"hover": "OKLch(0.20 0 0)",
"active": "OKLch(0.25 0 0)"
},
"text": {
"primary": "OKLch(0.95 0 0)",
"secondary": "OKLch(0.70 0 0)",
"tertiary": "OKLch(0.50 0 0)"
},
"semantic": {
"positive": "OKLch(0.65 0.18 140)", // green
"negative": "OKLch(0.55 0.20 20)", // red
"accent": "OKLch(0.65 0.18 250)", // blue
"warning": "OKLch(0.70 0.18 80)", // amber
"critical": "OKLch(0.50 0.22 20)" // deep red
}
},
"typography": {
"fontFamily": {
"display": "Inter, system-ui, sans-serif",
"mono": "JetBrains Mono, monospace",
"body": "Inter, system-ui, sans-serif"
},
"size": {
"xs": "0.75rem",
"sm": "0.875rem",
"base": "1rem",
"lg": "1.125rem",
"xl": "1.25rem",
"2xl": "1.5rem",
"3xl": "1.875rem"
},
"weight": {
"normal": "400",
"medium": "500",
"semibold": "600",
"bold": "700"
}
},
"spacing": {
"1": "0.25rem",
"2": "0.5rem",
"3": "0.75rem",
"4": "1rem",
"6": "1.5rem",
"8": "2rem",
"12": "3rem",
"16": "4rem"
},
"radius": {
"sm": "0.375rem",
"md": "0.5rem",
"lg": "0.75rem",
"xl": "1rem",
"full": "9999px"
},
"breakpoints": {
"mobile": "375px",
"tablet": "768px",
"desktop": "1024px",
"wide": "1280px"
}
}
```
### Phase 5: Interactive Prototype to Code Bridge (Week 3)
**Goal**: Convert Open Design HTML/CSS prototypes into Next.js components.
Process:
1. Open Design generates HTML/CSS prototype
2. Developer maps HTML structure to React/Next.js components
3. Tailwind classes transfer directly (same syntax)
4. Replace static data with API-driven data
5. Add interactivity (Zustand state, API calls)
6. Ensure accessibility (ARIA, keyboard navigation)
```
Mapping guide:
┌────────────────────┬─────────────────────────────────────────┐
│ Open Design Output │ Next.js Implementation │
├────────────────────┼─────────────────────────────────────────┤
│ HTML <div> │ React <div> (same) │
│ HTML <a> │ Next.js <Link> │
│ CSS classes │ TailwindCSS classes (same syntax) │
│ CSS custom props │ tailwind.config.js theme extension │
│ Static data │ API call → Zustand store → component │
│ Hover effects │ Tailwind hover: classes │
│ Responsive │ Tailwind responsive prefixes (sm:, md:) │
│ Interactivity │ React useState, useEffect, API calls │
└────────────────────┴───────────────────────────────────────────────┘
```
## Open Design Skill Integration
### For Hermes Agent
Use Open Design as a design-phase skill for the invest-copilot project:
```yaml
# In your agent session context for invest-copilot:
skills:
- name: open-design # if installed as a skill
- name: architecture-diagram # for system architecture SVGs
- name: sketch # for quick UI mockup comparisons
```
### For Other CLI Agents
Open Design works with all 16 supported coding agents. When working with:
- **Claude Code**: Use natural language design prompts with Open Design conventions
- **Cursor**: Use Open Design's brand systems as autocomplete context
- **Qwen (your model)**: Generate design specs that map to the TailwindCSS + Radix UI stack
## Design System Selection
For Invest Copilot's visual direction, Open Design provides these brand systems:
| Brand System | Why It Works | Application |
|---|---|---|
| **Stripe** | Clean, data-dense, professional | Dashboard, data tables, cards |
| **Linear** | Modern, minimal, dark mode | Navigation, sidebar, controls |
| **Bloomberg** | Financial data visualization | Charts, heatmaps, trading UI |
| **Vercel** | Developer-friendly, clean | Settings, configuration screens |
| **Apple** | Premium, accessible, intuitive | Onboarding, empty states |
### Recommended Blend
```
Primary: Stripe (layout + spacing principles)
Dark mode: Linear (dark mode design system)
Financial charts: Bloomberg (data density)
Navigation: Vercel (clean, minimal)
Typography: Apple (readability at small sizes)
```
## Design Validation Checklist
Before moving from design to implementation, validate:
- [ ] All screens are responsive at 375px, 768px, 1024px, 1280px
- [ ] Dark mode contrast ratios meet WCAG AA (4.5:1 for text)
- [ ] Touch targets are ≥ 44px on mobile
- [ ] Charts are readable at 375px width
- [ ] Color-coding for profit/loss works for colorblind users (add icons + labels)
- [ ] All interactive elements have hover and focus states
- [ ] Loading states defined for all data-fetching screens
- [ ] Empty states designed for watchlists, strategies, alerts
- [ ] Error states defined for API failures
- [ ] Keyboard navigation works on all screens (not just mouse/touch)
- [ ] Semantic HTML structure (header, main, nav, aside, footer)
## Anti-Patterns to Avoid
1. **Bloomberg clutter** — Don't make it look like Bloomberg Terminal. It's a modern PWA, not a desktop trading terminal.
2. **Over-charting** — Every stock page should have at most 3-4 charts max. More than that overwhelms.
3. **Desktop-first thinking** — Design for 375px width first, then expand. Not the other way around.
4. **Ignoring loading states** — Financial data takes time to fetch. Skeleton screens are mandatory.
5. **Color-only signaling** — Never use color alone to indicate profit/loss. Use arrows, icons, and labels too.
6. **Ignoring accessibility** — Financial tools serve all users. Screen reader support is non-negotiable.
+612
View File
@@ -0,0 +1,612 @@
# Invest Copilot — Phase 1: Design-Driven Foundation
> **Goal**: Establish the project foundation, generate UI directions via Open Design, set up the development environment, and define all API contracts.
>
> **Duration**: Weeks 1-3
>
> **Deliverables**: Clickable UI prototype, API specification, deployed dev environment, CI/CD pipeline
## Week 1: Visual Identity & UI Prototypes
### Day 1-2: Design Direction via Open Design
**Task 1: Generate 3 visual directions**
Use Open Design (or equivalent) with these prompts:
```
Direction A: "Dark Finance Professional"
- Deep navy background (#0a1628) with electric blue accents (#3b82f6)
- Data-dense layout (like Bloomberg but modern)
- Monospace numbers (JetBrains Mono), sans-serif labels (Inter)
- Green/red for gains/losses with +/− icons (not color alone)
- Reference: Bloomberg meets Linear
Direction B: "Minimal Intelligence"
- Near-black background (#0d0d0d) with subtle blue tints
- Maximum white space between data elements
- Large typography for key metrics
- Charts as the hero element
- Reference: Apple Health meets Koyfin
Direction C: "Modern Terminal"
- Dark gray background (#1a1a1a) with accent colors
- Terminal-inspired typography and borders
- Monospace throughout
- Command-like navigation
- Reference: TradingView dark mode meets VS Code
```
**Task 2: Select direction and create design tokens**
Based on the generated directions, create `tailwind.config.ts` with:
- Custom color palette (OKLch-based)
- Font families (Inter + JetBrains Mono)
- Spacing scale
- Breakpoint definitions
- Animation definitions
**Task 3: Generate key screen prototypes**
Generate HTML/CSS prototypes for:
1. Dashboard (watchlist overview)
2. Stock profile (search → profile)
3. Sector rotation dashboard
### Day 3-5: Component Library
Generate reusable components:
- StockCard, PriceChart placeholder, SEC Filing Card
- Insider Trade Row, Strategy Rule Builder, Alert Badge
- Sector Heatmap, Watchlist Table, Navigation
## Week 2: Development Environment
### Task 4: Initialize Next.js 15 project
```bash
npx create-next-app@latest invest-copilot \
--typescript \
--tailwind \
--app \
--src-dir \
--import-alias "@/*" \
--turbopack \
--use-npm
```
### Task 5: Install core dependencies
```bash
# State management
npm install zustand
# UI primitives
npm install @radix-ui/react-dialog @radix-ui/react-dropdown-menu
npm install @radix-ui/react-tabs @radix-ui/react-tooltip
npm install @radix-ui/react-select @radix-ui/react-switch
# Charts
npm install lightweight-charts
# Data fetching
npm install @tanstack/react-query
# Forms
npm install react-hook-form zod @hookform/resolvers
# PWA
npm install next-pwa
# Icons
npm install lucide-react
# Date handling
npm install date-fns
# Development
npm install -D @types/node @types/react @types/react-dom
npm install -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
npm install -D prettier prettier-plugin-tailwindcss
```
### Task 6: Set up Docker Compose for infrastructure
Create `docker-compose.dev.yml`:
```yaml
services:
postgres:
image: timescale/timescaledb:latest-pg16
environment:
POSTGRES_DB: invest_copilot
POSTGRES_USER: dev
POSTGRES_PASSWORD: dev_password
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redisdata:/data
minio:
image: minio/minio
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: dev
MINIO_ROOT_PASSWORD: dev_password
ports:
- "9000:9000"
- "9001:9001"
volumes:
- miniodata:/data
volumes:
pgdata:
redisdata:
miniodata:
```
### Task 7: Set up CI/CD with GitHub Actions
Create `.github/workflows/ci.yml`:
```yaml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run lint
- run: npm run build
```
## Week 3: API Contracts & Data Pipeline
### Task 8: Define OpenAPI/Swagger specification
Create `docs/api/openapi.yaml` with:
```yaml
openapi: 3.1.0
info:
title: Invest Copilot API
version: 0.1.0
description: AI-native investment research and portfolio copilot
paths:
# Stock Search & Profile
/api/v1/search:
get:
summary: Search stocks by ticker or name
parameters:
- name: q
in: query
required: true
schema: { type: string }
- name: limit
in: query
schema: { type: integer, default: 10, maximum: 50 }
responses:
200:
description: Search results
/api/v1/stocks/{ticker}:
get:
summary: Get full stock profile
parameters:
- name: ticker
in: path
required: true
schema: { type: string }
responses:
200:
description: Stock profile with all data
/api/v1/stocks/{ticker}/peers:
get:
summary: Get peer group and relative performance
parameters:
- name: ticker
in: path
required: true
schema: { type: string }
responses:
200:
description: Peer group with relative strength
/api/v1/stocks/{ticker}/price/history:
get:
summary: Get historical prices
parameters:
- name: ticker
in: path
required: true
schema: { type: string }
- name: interval
in: query
schema: { type: string, enum: [1m, 5m, 15m, 30m, 1h, 1d, 1w, 1M] }
- name: start
in: query
schema: { type: string, format: date-time }
- name: end
in: query
schema: { type: string, format: date-time }
responses:
200:
description: Price history
/api/v1/stocks/{ticker}/sec-filings:
get:
summary: Get SEC filings
parameters:
- name: ticker
in: path
required: true
schema: { type: string }
- name: form_type
in: query
schema: { type: string, enum: [10-K, 10-Q, 8-K, 4, 13F, 13D, 13G] }
- name: limit
in: query
schema: { type: integer, default: 20 }
responses:
200:
description: SEC filings
/api/v1/stocks/{ticker}/insider-trades:
get:
summary: Get insider trades
parameters:
- name: ticker
in: path
required: true
schema: { type: string }
- name: limit
in: query
schema: { type: integer, default: 20 }
responses:
200:
description: Insider trades
/api/v1/stocks/{ticker}/sentiment:
get:
summary: Get sentiment signals
parameters:
- name: ticker
in: path
required: true
schema: { type: string }
responses:
200:
description: Sentiment signals from all sources
# Watchlists
/api/v1/watchlists:
get:
summary: Get user's watchlists
responses:
200:
description: List of watchlists
post:
summary: Create a new watchlist
requestBody:
content:
application/json:
schema:
type: object
required: [name]
properties:
name: { type: string }
description: { type: string }
responses:
201:
description: Watchlist created
/api/v1/watchlists/{id}:
get:
summary: Get watchlist with items and prices
put:
summary: Update watchlist name
delete:
summary: Delete watchlist
/api/v1/watchlists/{id}/items:
get:
summary: Get watchlist items with live prices
post:
summary: Add ticker to watchlist
delete:
summary: Remove ticker from watchlist
# Strategies
/api/v1/strategies:
get:
summary: Get user's strategies
post:
summary: Create a new strategy
/api/v1/strategies/{id}:
get:
summary: Get strategy details
put:
summary: Update strategy
delete:
summary: Delete strategy
# Screener
/api/v1/screeners:
get:
summary: Get user's screeners
post:
summary: Create a new screener
/api/v1/screeners/{id}/run:
post:
summary: Run screener and get results
/api/v1/screeners/{id}/results:
get:
summary: Get screener results
# Sector Rotation
/api/v1/sectors/rotation:
get:
summary: Get current sector rotation analysis
post:
summary: Trigger manual rotation scan
/api/v1/sectors/rotation/history:
get:
summary: Get historical rotation data
# Alerts
/api/v1/alerts:
get:
summary: Get user's alerts
delete:
summary: Clear resolved alerts
/api/v1/alerts/{id}/resolve:
post:
summary: Mark alert as resolved
/api/v1/alerts/{id}/dismiss:
post:
summary: Dismiss alert
# Real-time (SSE)
/api/v1/stream/alerts:
get:
summary: Server-Sent Events stream for real-time alerts
responses:
200:
description: SSE stream
content:
text/event-stream:
schema:
type: string
```
### Task 9: Set up Python data pipeline
```bash
mkdir -p src/data-pipeline
cd src/data-pipeline
pip install yfinance finnhub-python requests beautifulsoup4
```
Create `src/data-pipeline/ingest_prices.py`:
```python
"""Price data ingestion using yfinance (free tier)."""
import yfinance as yf
import psycopg2
from datetime import datetime, timedelta
def fetch_prices(ticker: str, period: str = "5y") -> list[dict]:
"""Fetch OHLCV data using yfinance."""
tk = yf.Ticker(ticker)
df = tk.history(period=period, auto_adjust=True)
records = []
for date, row in df.iterrows():
records.append({
"ticker": ticker,
"date": date,
"open": row["Open"],
"high": row["High"],
"low": row["Low"],
"close": row["Close"],
"volume": int(row["Volume"]),
"adjusted_close": row["Close"], # adjusted = close for now
})
return records
def save_prices(records: list[dict]) -> None:
"""Save prices to PostgreSQL/TimescaleDB."""
conn = psycopg2.connect(
host="localhost",
database="invest_copilot",
user="dev",
password="dev_password"
)
cur = conn.cursor()
for r in records:
cur.execute("""
INSERT INTO prices (ticker, date, open, high, low, close, volume, adjusted_close)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
ON CONFLICT (ticker, date) DO UPDATE SET
open = EXCLUDED.open,
high = EXCLUDED.high,
low = EXCLUDED.low,
close = EXCLUDED.close,
volume = EXCLUDED.volume,
adjusted_close = EXCLUDED.adjusted_close
""", (
r["ticker"], r["date"], r["open"], r["high"], r["low"],
r["close"], r["volume"], r["adjusted_close"]
))
conn.commit()
cur.close()
conn.close()
if __name__ == "__main__":
import sys
tickers = sys.argv[1:] if len(sys.argv) > 1 else ["AAPL", "MSFT", "GOOGL", "AMZN", "META"]
for ticker in tickers:
print(f"Ingesting {ticker}...")
records = fetch_prices(ticker)
save_prices(records)
print(f" Saved {len(records)} records")
```
### Task 10: Set up SEC EDGAR ingestion
Create `src/data-pipeline/ingest_sec.py`:
```python
"""SEC EDGAR filing ingestion."""
import requests
import json
from datetime import datetime
EDGAR_BASE = "https://data.sec.gov"
def get_cik(ticker: str) -> str | None:
"""Get CIK number for a ticker."""
url = f"{EDGAR_BASE}/cgi-bin/browse-edgar?action=getcompany&CIK=TICKER&type=&date=coverage&date_range=365&count=1"
url = url.replace("TICKER", ticker.upper())
resp = requests.get(url, timeout=10)
# Parse HTML to extract CIK
import re
match = re.search(r'CIK=(0{0,10}\d{6,10})', resp.text)
return match.group(1) if match else None
def get_filings(cik: str, form_type: str | None = None, limit: int = 20) -> list[dict]:
"""Get filings for a CIK."""
url = f"{EDGAR_BASE}/submissions/CIK{int(cik):010d}.json"
resp = requests.get(url, timeout=10)
data = resp.json()
filings = []
for i in range(min(limit * 20, len(data["filings"]["recent"]["form"]))):
form = data["filings"]["recent"]["form"][i]
if form_type and form != form_type:
continue
filings.append({
"cik": cik,
"form_type": form,
"filing_date": data["filings"]["recent"]["filingDate"][i],
"report_date": data["filings"]["recent"]["reportDate"][i],
"accession_number": data["filings"]["recent"]["accessionNumber"][i],
"primary_document": data["filings"]["recent"]["primaryDocument"][i],
"url": f"{EDGAR_BASE}/Archives/edgar/data/{int(cik):010d}/"
f"{data['filings']['recent']['accessionNumber'][i].replace('-', '')}/"
f"{data['filings']['recent']['primaryDocument'][i]}",
})
if len([f for f in filings if "form_type" in f]) >= limit:
break
return filings
if __name__ == "__main__":
# Test: Get filings for AAPL
cik = get_cik("AAPL")
print(f"AAPL CIK: {cik}")
if cik:
filings = get_filings(cik, limit=5)
print(json.dumps(filings, indent=2))
```
### Task 11: Create project structure
```
invest-copilot/
├── docs/ # Documentation (we already have this)
│ ├── 00-vision.md
│ ├── 01-architecture.md
│ ├── 02-data-model.md
│ ├── 03-domain-model.md
│ ├── 04-open-design-integration.md
│ ├── 05-phase1-plan.md
│ └── api/
│ └── openapi.yaml
├── src/
│ ├── frontend/ # Next.js app
│ │ ├── app/
│ │ ├── components/
│ │ ├── lib/
│ │ ├── styles/
│ │ └── store/ # Zustand stores
│ ├── backend/ # Node.js API (future)
│ │ ├── src/
│ │ └── tests/
│ ├── data-pipeline/ # Python ingestion scripts
│ │ ├── ingest_prices.py
│ │ ├── ingest_sec.py
│ │ ├── ingest_sentiment.py
│ │ └── sector_rotation.py
│ └── shared/ # Shared types (TypeScript)
│ └── types.ts
├── docker-compose.dev.yml
├── docker-compose.prod.yml # (future)
├── .github/
│ └── workflows/
│ ├── ci.yml
│ └── deploy.yml # (future)
├── prisma/ # (future, for DDD repo implementations)
├── .eslintrc.json
├── .prettierrc
├── next.config.mjs
├── tailwind.config.ts
├── tsconfig.json
├── package.json
└── README.md
```
## Acceptance Criteria for Phase 1
- [ ] 3 visual directions generated via Open Design (or manual)
- [ ] Selected design direction converted to TailwindCSS design tokens
- [ ] Next.js 15 project running with TypeScript, TailwindCSS, Radix UI
- [ ] Docker Compose dev environment with PostgreSQL+TimescaleDB, Redis, MinIO
- [ ] GitHub Actions CI pipeline (lint + build)
- [ ] Complete OpenAPI specification for all endpoints
- [ ] Python data pipeline ingesting prices for at least 10 tickers
- [ ] SEC EDGAR ingestion working for at least 5 companies
- [ ] Dashboard UI mockup working with static data
- [ ] Stock search UI mockup working with static data
- [ ] Stock profile UI mockup working with static data
- [ ] README.md with project overview, setup instructions, and architecture
## Pre-Phase 2 Checklist
Before moving to Phase 2 (Backend Foundation):
- [ ] All Phase 1 acceptance criteria met
- [ ] Design direction finalized and approved
- [ ] API contracts reviewed and agreed upon
- [ ] Data pipeline tested and verified
- [ ] Dev environment stable and documented
## Resource Estimation
| Task | Effort |
|---|---|
| Visual directions + design tokens | 2 days |
| Component library | 3 days |
| Next.js project setup | 0.5 days |
| Docker Compose infrastructure | 0.5 days |
| CI/CD pipeline | 0.5 days |
| OpenAPI specification | 1 day |
| Price data pipeline | 2 days |
| SEC EDGAR pipeline | 2 days |
| UI mockups (3 screens) | 3 days |
| README + documentation | 1 day |
| **Total** | **~16 days (3 weeks)** |
+49
View File
@@ -0,0 +1,49 @@
# Project Status — Invest Copilot
## Overview
- **Phase 1: Foundation** — ✅ COMPLETE
- 6 design docs (vision, architecture, data model, domain model, open design integration, phase 1 plan)
- Docker compose (PostgreSQL/TimescaleDB, Redis, MinIO)
- Data pipeline scripts (price ingestion, SEC filings, sector rotation)
- Shared types, OpenAPI spec, CI/CD, design tokens
- **Phase 2: Implementation** — ✅ COMPLETE
- **Backend (FastAPI BFF)** — 49 files
- Core: main.py, config, database, cache, storage
- Models: price, stock, watchlist, strategy, screener, sector_rotation, sec_filing, insider_trade, alert
- Schemas: Pydantic response models for all entities
- Routers: 14 endpoints (search, stocks, prices, sec_filings, insider_trades, peers, sentiment, watchlists, strategies, screeners, sectors, alerts, stream)
- Services: PriceService, SecService, SentimentService, RotationService, ScreenerService
- Tasks: ingest_prices, ingest_sec, sector_scan
- 14 API endpoints matching OpenAPI spec
- **Frontend (Next.js 15 PWA)** — 49 files
- Layout: Sidebar (6 nav items), Header (search bar)
- Dashboard: Portfolio summary cards, sector heatmap, watchlist table, alerts feed
- Stock detail: Profile, price chart (lightweight-charts), SEC filings, insider trades
- Watchlists: CRUD with sidebar selection
- Strategies: Grid of strategy cards with backtest results
- Screeners: ScreenerBuilder + ScreenerResults
- Sectors: Sector heatmap + detailed rankings
- Alerts: Filterable alert feed
- Hooks: useStockData, useWatchlistData, useSSE
- Stores: useUIStore, useWatchlistStore, useStrategiesStore
- UI Components: Button, Badge, Card, Input, Modal, Skeleton, Tooltip
- Lib: API client (axios), constants, utils, types
- PWA with Workbox config
## Current State
- **Total files**: 187 (excluding node_modules, .next)
- **Stack**: Next.js 15 (app router, Turbopack) + Tailwind + FastAPI + TimescaleDB + Redis + MinIO
- **API**: Full OpenAPI spec implemented (14 endpoints)
- **Data models**: All 8 entity types defined with SQLAlchemy models
- **Database**: init.sql with TimescaleDB hypertables for prices, sector_rotation, equity_scores
- **CI/CD**: GitHub Actions for lint/test/build/deploy
## Next Steps (Phase 3)
1. **Infrastructure**: Fix Docker bridge (kernel issue) — may need nftables/iptables fix or podman alternative
2. **Data sources**: Replace mock data with real APIs (Alpha Vantage, SEC EDGAR, Finnhub)
3. **Authentication**: Add JWT-based auth (login/register endpoints)
4. **Real-time**: Implement SSE stream for live price updates
5. **Testing**: Add pytest tests for backend, Playwright E2E for frontend
6. **Deployment**: Docker compose production config, Nginx reverse proxy
File diff suppressed because it is too large Load Diff
+640
View File
@@ -0,0 +1,640 @@
# Invest Copilot — Data Edge Research
> Created: 2025-05-26
> Purpose: Identify all data sources, signals, and alternative data that create an investment "edge" — information that gives our users an informational advantage over retail competitors.
>
---
## Table of Contents
1. [Core Market Data (Table Stakes)](#1-core-market-data-table-stakes)
2. [Fundamental Data (The Foundation)](#2-fundamental-data-the-foundation)
3. [Institutional & Insider Signals](#3-institutional--insider-signals)
4. [Options Flow & Sentiment](#4-options-flow--sentiment)
5. [Short Interest & Squeeze Potential](#5-short-interest--squeeze-potential)
6. [SEC Filings & Regulatory Intelligence](#6-sec-filings--regulatory-intelligence)
7. [Alternative Data (True Alpha)](#7-alternative-data-true-alpha)
8. [Macro & Economic Indicators](#8-macro--economic-indicators)
9. [Sector & Rotation Signals](#9-sector--rotation-signals)
10. [AI/ML Feature Engineering](#10-aiml-feature-engineering)
11. [API Providers & Cost Analysis](#11-api-providers--cost-analysis)
---
## 1. Core Market Data (Table Stakes)
*Everyone has this. You need it, but it doesn't create an edge by itself.*
| Data Point | Why It Matters | Frequency |
|-----------|---------------|-----------|
| Real-time price (bid/ask/last) | Entry/exit timing | Tick-by-tick |
| Volume (absolute + relative) | Conviction behind moves | Tick-by-tick |
| VWAP (Volume Weighted Avg Price) | Institutional benchmark | Real-time |
| 52-week high/low | Psychological levels | Daily |
| Market cap / Float | Liquidity assessment | Daily |
| Average volume (10d/30d/90d) | Normalization baseline | Daily |
| Intraday OHLCV (1m/5m/15m/1h) | Chart patterns, entry timing | Intraday |
| Pre-market / After-hours price | Gap risk, overnight sentiment | Extended hours |
| Split/dividend-adjusted prices | Historical accuracy | Event-driven |
| Relative strength vs sector/index | Outperformance/underperformance | Daily |
---
## 2. Fundamental Data (The Foundation)
*Where the real story lives. This is where you separate investors from gamblers.*
### Income Statement
- Revenue (quarterly + YoY + QoQ growth rates)
- Gross margin, operating margin, net margin (trend analysis)
- EBITDA / EBIT
- EPS (GAAP + non-GAAP + diluted)
- R&D spend (critical for tech — shows future investment)
- SG&A as % of revenue (efficiency metric)
- Free cash flow conversion
### Balance Sheet
- Total assets/liabilities/debt
- Net debt / EBITDA ratio (solvency)
- Current ratio, quick ratio (liquidity)
- Share count changes (dilution detection)
- Cash & equivalents vs short-term debt
- Goodwill & intangible assets (quality of earnings)
### Cash Flow
- Operating cash flow (quality of earnings)
- Capex (growth vs maintenance)
- Free cash flow (FCF = OCF − Capex)
- Share buybacks (management confidence signal)
- Dividend payments & changes
### Key Ratios (Computed)
- P/E, PEG, P/S, P/B, P/FCF
- ROE, ROA, ROIC
- Debt/Equity, Interest Coverage
- Altman Z-Score (bankruptcy risk)
- Piotroski F-Score (9-factor quality score)
---
## 3. Institutional & Insider Signals
*One of the strongest predictive signals available to retail.*
### Institutional Ownership
- Top 10 holders (Vanguard, BlackRock, Fidelity, etc.)
- % of float held by institutions
- **Quarterly change in institutional ownership** (rising = bullish signal)
- 13F filings (lagged 45 days, but comprehensive)
- Hedge fund holdings (13F — track specific funds like Renaissance, Citadel, Bridgewater)
- Mutual fund net inflows/outflows
- **New positions** vs **increased positions** vs **sold positions**
### Insider Activity (FORM 4)
- **Insider buys** — strongest signal (they spend their own money)
- CEO/CFO buys are highest conviction
- Open market buys > exercise of options
- Cluster buying (multiple insiders buying) = very strong signal
- **Insider sells** — need context
- 10b5-1 plans = routine, not signal
- Unplanned sells = potential red flag
- Cluster sells = very bearish
- **Form 4 filing date vs transaction date** — speed matters
- **SEC Form 144** (proposed sales — early warning)
---
## 4. Options Flow & Sentiment
*Options market often moves before the stock. This is real-time institutional positioning.*
### Options Data
- **Unusual options activity** — volume >> open interest
- Large block trades (100+ contracts)
- Out-of-the-money calls (bullish speculation)
- Put/call ratio spikes (fear/greed)
- **Put/Call ratio** by ticker and overall market
- **Implied volatility** (IV) vs historical volatility (HV)
- IV > HV = options expensive (potential move)
- IV rank / IV percentile
- **Options chain** — max pain, gamma exposure
- **Block trades** — dark pool prints
- **Dark pool volume %**
### Sentiment Indicators
- **Put/Call ratio** breakdown (equity, index, single stock)
- **CBOE Volatility Index (VIX)** and components
- **CNN Fear & Greed Index**
- **AAII sentiment survey**
- **Google Trends** for stock/sector searches
- **Reddit/Twitter sentiment** (r/wallstreetbets, r/investing)
---
## 5. Short Interest & Squeeze Potential
*Short squeeze setups can create 100%+ moves in days.*
### Short Data
- **Short interest** (% of float)
- **Days to cover** (short ratio)
- **Short interest trend** (rising = bearish, but also squeeze fuel)
- **Squeeze probability score**:
- High short interest (>20%)
- Low float (<50M shares)
- High days-to-cover (>5)
- Rising price + volume
- Recent catalyst (earnings, FDA, product)
### Borrowing Data
- **Stock borrow fees** (high fees = hard to borrow = squeeze potential)
- **Locate availability**
- **Cost to borrow** (% annual)
---
## 6. SEC Filings & Regulatory Intelligence
*Raw regulatory filings are the most authoritative source — before analysts catch up.*
### Key Filings
- **10-K** (annual) — comprehensive financial picture
- **10-Q** (quarterly) — quarterly updates
- **8-K** (current) — material events (earnings, M&A, leadership changes)
- **DEF 14A** (proxy) — executive comp, board changes
- **S-1** / **S-3** — new offerings (dilution risk)
- **SC 13D/G** — activist positions (>5% ownership)
- **Form 4** — insider transactions (daily)
- **Form 144** — proposed insider sales
### NLP Extraction Targets
- **MD&A changes** — management commentary shifts
- **Risk factor additions** — new risks = new concerns
- **Auditor changes** — red flag if auditor resigns
- **Going concern** mentions = existential threat
- **Related party transactions** — potential tunneling
- **Segment revenue breakdown** — growth drivers
---
## 7. Alternative Data (True Alpha)
*This is where you create real edge. These are hedge fund-grade signals.*
### Consumer Behavior
| Signal | Source | Edge |
|--------|--------|------|
| App download counts | Sensor Tower, App Annie | Early revenue signal for consumer apps |
| App usage/engagement | SimilarWeb, data.ai | Retention, engagement trends |
| Web traffic | SimilarWeb, SEMrush | Interest, funnel performance |
| Credit card spend | YipitData, Earnest Research | Real-time revenue proxy |
| Grocery/retail receipts | Earnest Research | Consumer discretionary health |
| Shipping/tracking data | Project44, Descartes | Supply chain visibility, inventory |
### Corporate Activity
| Signal | Source | Edge |
|--------|--------|------|
| Job postings | Employment data, LinkedIn | Growth signaling, expansion plans |
| Job posting changes | Indeed, LinkedIn | Hiring freeze = cost cutting signal |
| Patent filings | USPTO, Google Patents | Innovation pipeline |
| Building permits | Municipal records | Physical expansion plans |
| Executive hires/leaves | LinkedIn, SEC filings | Leadership quality, stability |
| Earnings call transcripts | Seeking Alpha, Motley Fool | NLP on management tone, guidance |
### Supply Chain
| Signal | Source | Edge |
|--------|--------|------|
| Supplier revenue changes | Supplier financials | Proxy for customer demand |
| Supplier capex increases | Supplier filings | Capacity expansion = demand confidence |
| Supplier stock performance | Supplier tickers | Leading indicator for customers |
| Container shipping rates | Drewry, Clarksons | Global trade volume proxy |
| Oil/commodity prices | Bloomberg, CME | Input cost pressure |
### Sentiment & Social
| Signal | Source | Edge |
|--------|--------|------|
| Reddit sentiment | Pushshift, Reddit API | Retail sentiment extremes = contrarian |
| Twitter/X sentiment | X API | Real-time reaction, influencer moves |
| StockTwits sentiment | StockTwits API | Retail trader positioning |
| Google Trends | Google Trends API | Interest spike detection |
| YouTube/video content | YouTube Data API | Media coverage analysis |
| News sentiment | NewsAPI, GDELT | Sentiment scoring, event detection |
### Physical/Economic Proxies
| Signal | Source | Edge |
|--------|--------|------|
| Satellite imagery | Planet, Sentinel | Retail parking lots, construction |
| Credit card transaction data | YipitData, Flexport | Consumer spending in real-time |
| Mobile location data | SafeGraph, Foursquare | Foot traffic to stores |
| Energy consumption | Utility data | Industrial activity proxy |
| Water usage data | Various providers | Agricultural/industrial activity |
### Macro Indicators (Beyond the headline)
| Signal | Source | Edge |
|--------|--------|------|
| Yield curve (2s10, 3m10) | FRED, Treasury.gov | Recession predictor |
| Inverted yield curve depth/duration | FRED | Recession probability |
| Leading Economic Index (LEI) | Conference Board | 6-12 month outlook |
| PMI (ISM Manufacturing/Services) | ISM | Economic activity pulse |
| Consumer confidence | Conference Board | Consumer spending predictor |
| Jobless claims (weekly) | DOL | Labor market health |
| Initial vs continuing claims ratio | DOL | Trend vs noise |
| Building permits/housing starts | Census Bureau | Housing market leading indicator |
| Consumer credit changes | NY Fed | Consumer financial stress |
---
## 8. Macro & Economic Indicators
*For sector rotation and macro regime detection.*
### Interest Rate Environment
- Fed funds rate / Fed expectations (CME FedWatch)
- Treasury yields (2Y, 5Y, 10Y, 30Y)
- **Yield curve spread** (10Y-2Y, 10Y-3M) — recession signal
- **TED spread** (credit risk)
- **TIPS breakeven** (inflation expectations)
- SOFR, LIBOR successor rates
- **Commercial paper spreads**
- **High yield spreads** (ICE BofA HY OAS)
### Inflation
- CPI (headline + core)
- PCE (Fed's preferred measure)
- PPI (producer prices — leading indicator)
- Wage growth (average hourly earnings)
- Shelter/rent component (largest CPI component)
### Growth
- GDP growth (advance, second, final)
- Non-farm payrolls
- Unemployment rate
- ISM Manufacturing PMI (>50 = expansion)
- ISM Services PMI
- Retail sales
- Industrial production
### Currency & Commodities
- DXY (US Dollar Index)
- USD/EUR, USD/JPY, USD/CNY
- Gold (fear/deflation hedge)
- Oil (WTI/Brent — inflation, growth)
- Copper (economic activity — "Dr. Copper")
- Bitcoin (risk-on proxy)
---
## 9. Sector & Rotation Signals
*For the ETF/Index tracking and rotation detection feature.*
### ETF-Level Data
| ETF | Sector | Signal |
|-----|--------|--------|
| XLK | Technology | Tech leadership |
| XLF | Financials | Risk appetite, rate sensitivity |
| XLI | Industrial | Economic activity |
| XLY | Consumer Discretionary | Consumer confidence |
| XLP | Consumer Staples | Defensive positioning |
| XLE | Energy | Commodity cycle |
| XLV | Healthcare | Defensive, innovation |
| XLU | Utilities | Defensive, rate sensitivity |
| XLB | Materials | Cyclical, commodities |
| XLR | Real Estate | Rate sensitivity, housing |
| XLRE | Real Estate | Same as above (alternate) |
| XLG | Large Cap Growth | Growth tilt |
| XSC | Small Cap | Economic outlook (IWR alternative) |
### Rotation Indicators (The Edge)
1. **Relative Strength Score** — sector vs SPY over 20d/50d/200d
2. **RSI Divergence** — sector making new high while SPY doesn't = leadership
3. **Money Flow** — sector inflow vs outflow tracking
4. **Sector ETF spread** — XLK vs XLE ratio changing
5. **Breadth** — stocks above 50MA and 200MA within sector
6. **Volume concentration** — volume shifting to specific sectors
### Rotation Detection Algorithm
```
Rotation = when 3+ of these conditions align:
1. Sector ETF breaks above 50-day MA
2. Sector ETF RSI crosses above 50
3. Sector ETF volume > 20-day average
4. Sector's top 3 stocks outperform SPY
5. Sector relative strength vs SPY trending up (10d)
6. Institutional money flow data shows inflows
7. Analyst upgrades concentrated in sector
```
---
## 10. AI/ML Feature Engineering
*Transforming raw data into predictive features.*
### Technical Indicators (Engineered)
- Moving averages (20, 50, 100, 200 day) + crossovers
- RSI (14-day) + overbought/oversold
- MACD (12, 26, 9) + signal line crossovers
- Bollinger Bands (20, 2) + position relative to bands
- ATR (14-day) — volatility measure
- Volume MA + volume spike detection (3x avg)
- Gap analysis (pre-market gap % + fill probability)
- Support/resistance levels (pivot points, swing highs/lows)
- Fibonacci retracement levels
- Ichimoku Cloud components
### Sentiment Features
- Put/Call ratio (10-day rolling avg + spike)
- Short interest change (weekly)
- Insider buy/sell ratio (quarterly)
- Analyst rating changes (upgrades - downgrades)
- Analyst price target revisions (upgrades - downgrades)
- Social sentiment score (normalized -3 to +3)
- News sentiment (Vader/BERT-based score)
### Fundamental Features
- Revenue growth acceleration/deceleration
- Margin expansion/contraction rate
- Cash flow vs net income divergence
- Working capital changes
- Inventory turnover changes
- Days sales outstanding (DSO) changes
- Altman Z-Score trend
- Piotroski F-Score
### Composite Scores (The Real Edge)
1. **Momentum Score** (0-100) — price + volume + relative strength
2. **Value Score** (0-100) — P/E vs sector, P/B, PEG, FCF yield
3. **Quality Score** (0-100) — ROIC, margin stability, debt, FCF conversion
4. **Sentiment Score** (0-100) — insider activity + institutional flows + analyst ratings
5. **Catalyst Score** (0-100) — upcoming events, earnings proximity, news flow
6. **Risk Score** (0-100) — volatility, beta, short interest, debt
---
## 11. API Providers & Cost Analysis
### Free / Low-Cost Tier
| Provider | Data | Cost | Rate Limit |
|----------|------|------|-----------|
| **Yahoo Finance** (yfinance) | Prices, fundamentals, options | Free | ~1,000/hr |
| **Finnhub** | Real-time + fundamentals + alternatives | Free tier | 60 calls/min |
| **Alpha Vantage** | Prices, fundamentals, alternatives | Free tier | 5 calls/min |
| **FRED** | Macro/economic data | Free | None |
| **SEC EDGAR** | All filings | Free | None |
| **Quandl/Nasdaq Data** | Economic data | Free tier | Limited |
| **Polygon.io** | Real-time + options | Free tier | Limited |
### Paid Tier
| Provider | Data | Cost | Edge Level |
|----------|------|------|-----------|
| **Finnhub** Pro | All + alternatives + sentiment | $100/mo | Medium |
| **Polygon.io** | Real-time + options + fundamentals | $29-$199/mo | Medium |
| **Twelve Data** | Prices, fundamentals, crypto | $49-$299/mo | Medium |
| **Dataroma** | Institutional holdings | $50/mo | Medium |
| **InsiderMonkey** | Insider + institutional | $50-$200/mo | Medium |
| **YipitData** | Consumer spending, shipping | $500+/mo | High |
| **Seeking Alpha Pro** | Earnings transcripts, articles | $240/yr | Medium |
| **Koyfin** | Bloomberg-lite terminal | $50-$200/mo | Medium |
| **Bloomberg Terminal** | Everything | $25k/yr | Highest |
| **Refinitiv (LSEG)** | Everything | $25k+/yr | Highest |
### Recommended Stack (MVP → Scale)
**Phase 1 (MVP — Free/Low Cost):**
- `yfinance` or `Finnhub Free` — prices + fundamentals
- `FRED` — macro data (all free, official government source)
- `SEC EDGAR API` — all filings (free, official)
- `Alpha Vantage Free` — alternatives (sentiment, tech indicators)
**Phase 2 (Growth — ~$150/mo):**
- `Finnhub Pro` — real-time data + alternatives
- `Polygon.io` — options data + real-time
- `Dataroma` — clean institutional ownership data
- `Seeking Alpha Pro` — earnings transcripts
**Phase 3 (Scale — ~$500/mo):**
- `YipitData` or `Earnest Research` — consumer spending
- `Project44` or `Descartes` — supply chain
- `SimilarWeb` — web traffic
- `SafeGraph` — foot traffic
---
## Recommended Data Model (Database Schema)
### Core Tables
```sql
-- Time series price data (granular)
stock_prices (
ticker VARCHAR,
date DATE,
open DECIMAL, high DECIMAL, low DECIMAL, close DECIMAL,
volume BIGINT,
vwap DECIMAL,
source VARCHAR,
PRIMARY KEY (ticker, date, source)
);
-- Fundamental data (quarterly)
fundamentals (
ticker VARCHAR,
quarter DATE,
revenue DECIMAL,
gross_margin DECIMAL,
operating_margin DECIMAL,
net_margin DECIMAL,
eps DECIMAL,
pe_ratio DECIMAL,
market_cap DECIMAL,
pb_ratio DECIMAL,
ps_ratio DECIMAL,
roe DECIMAL,
roic DECIMAL,
debt_equity DECIMAL,
current_ratio DECIMAL,
fcf DECIMAL,
shares_outstanding BIGINT,
PRIMARY KEY (ticker, quarter)
);
-- Institutional ownership (quarterly)
institutional_holdings (
ticker VARCHAR,
date DATE,
holder_name VARCHAR,
shares BIGINT,
pct_float DECIMAL,
holding_type VARCHAR,
filing_form VARCHAR,
PRIMARY KEY (ticker, date, holder_name)
);
-- Insider transactions (daily)
insider_transactions (
ticker VARCHAR,
date DATE,
insider_name VARCHAR,
title VARCHAR,
transaction_type VARCHAR, -- BUY, SELL, EXERCISE
shares BIGINT,
price DECIMAL,
value DECIMAL,
form_4_date DATE,
PRIMARY KEY (ticker, date, insider_name, shares)
);
-- SEC filings
sec_filings (
ticker VARCHAR,
date DATE,
form_type VARCHAR, -- 10-K, 10-Q, 8-K, DEF 14A, etc.
url VARCHAR,
filing_date DATE,
period_end DATE,
nlp_summary TEXT,
nlp_sentiment DECIMAL,
risk_factors_added INT,
risk_factors_removed INT,
PRIMARY KEY (ticker, date, form_type)
);
-- Options data
options_chain (
ticker VARCHAR,
date DATE,
expiry DATE,
strike DECIMAL,
option_type VARCHAR, -- CALL, PUT
volume BIGINT,
open_interest BIGINT,
implied_vol DECIMAL,
last_price DECIMAL,
PRIMARY KEY (ticker, date, expiry, strike, option_type)
);
-- Short interest (bi-monthly)
short_interest (
ticker VARCHAR,
date DATE,
short_shares BIGINT,
float BIGINT,
short_pct FLOAT,
days_to_cover FLOAT,
borrow_fee FLOAT,
PRIMARY KEY (ticker, date)
);
-- Sector rotation (daily)
sector_performance (
ticker VARCHAR, -- ETF ticker (XLK, XLF, etc.)
date DATE,
close DECIMAL,
change_pct DECIMAL,
volume BIGINT,
rs_vs_spy DECIMAL, -- relative strength vs SPY
above_ma50 BOOLEAN,
above_ma200 BOOLEAN,
rsi_14 DECIMAL,
PRIMARY KEY (ticker, date)
);
-- Watchlists
watchlists (
id UUID PRIMARY KEY,
user_id UUID,
name VARCHAR,
created_at TIMESTAMP,
updated_at TIMESTAMP
);
watchlist_items (
watchlist_id UUID REFERENCES watchlists(id),
ticker VARCHAR,
added_at TIMESTAMP,
notes TEXT,
PRIMARY KEY (watchlist_id, ticker)
);
-- Strategies
strategies (
id UUID PRIMARY KEY,
user_id UUID,
name VARCHAR,
description TEXT,
created_at TIMESTAMP,
updated_at TIMESTAMP,
is_active BOOLEAN
);
strategy_rules (
strategy_id UUID REFERENCES strategies(id),
rule_type VARCHAR, -- TECHNICAL, FUNDAMENTAL, SENTIMENT
condition VARCHAR,
threshold DECIMAL,
direction VARCHAR, -- ABOVE, BELOW, CROSS_ABOVE, CROSS_BELOW
PRIMARY KEY (strategy_id, condition)
);
-- Alerts
alerts (
id UUID PRIMARY KEY,
user_id UUID,
watchlist_id UUID,
strategy_id UUID,
triggered_at TIMESTAMP,
ticker VARCHAR,
alert_type VARCHAR,
message TEXT,
is_read BOOLEAN,
data JSONB -- raw data that triggered the alert
);
```
---
## Data Pipeline Architecture
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ API/Scraper │───▶│ Raw Data │───▶│ Normalization │
│ (yfinance, │ │ Lake (S3/MinIO)│ │ & Enrichment │
│ FRED, EDGAR) │ │ │ │ (PostgreSQL) │
└─────────────────┘ └─────────────────┘ └─────────┬───────┘
│
▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Real-time │◀───│ Feature │◀───│ API Layer │
│ WebSocket │ │ Engineering │ │ (FastAPI) │
│ (prices, │ │ (technical, │ │ │
│ options, │ │ sentiment) │ │ │
│ alerts) │ └─────────────────┘ └─────────────────┘
└─────────────────┘
```
---
## Summary: The Edge Pyramid
```
┌─────────────────┐
│ AI/ML Signals │ ← Composite scores, anomaly detection
├─────────────────┤
│ Alternative Data │ ← Consumer spend, web traffic, jobs
├─────────────────┤
│ Institutional │ ← 13F flows, insider buys, hedge funds
├─────────────────┤
│ Options/Short │ ← Put/call, squeeze potential
├─────────────────┤
│ SEC Filings │ ← NLP on 8-Ks, MD&A changes
├─────────────────┤
│ Fundamentals │ ← Financials, ratios, quality scores
├─────────────────┤
│ Technical │ ← Charts, indicators, volume
└─────────────────┘
│ Market Data │ ← Prices, volume (table stakes)
```
**The real edge lives in layers 4-7.** Layers 1-3 everyone has. Layer 8 (AI/ML) is where you combine all signals into predictive composites.