- PR1: Project scaffold, DB models, price loader - PR2: Congressional trade ingestion (House Stock Watcher) - PR3: Security enrichment + deployment infrastructure - 37 passing tests, 87%+ coverage - Docker + Proxmox deployment ready - Complete documentation - Works 100% offline with fixtures
6.2 KiB
6.2 KiB
PR3 Summary: Security Enrichment + Deployment
Status: ✅ Complete
Date: 2025-12-14
What was built
1. Security Enrichment (src/pote/ingestion/security_enricher.py)
SecurityEnricherclass for enriching securities with yfinance data- Fetches: company names, sectors, industries, exchanges
- Detects asset type: stock, ETF, mutual fund, index
- Methods:
enrich_security(security, force): Enrich single securityenrich_all_securities(limit, force): Batch enrichmentenrich_by_ticker(ticker): Enrich specific ticker
- Smart skipping: only enriches unenriched securities (unless
force=True)
2. Enrichment Script (scripts/enrich_securities.py)
- CLI tool for enriching securities
- Usage:
# Enrich all unenriched securities python scripts/enrich_securities.py # Enrich specific ticker python scripts/enrich_securities.py --ticker AAPL # Limit batch size python scripts/enrich_securities.py --limit 10 # Force re-enrichment python scripts/enrich_securities.py --force
3. Tests (9 new tests, all passing ✅)
tests/test_security_enricher.py:
- Successful enrichment with complete data
- ETF detection and classification
- Skip already enriched securities
- Force refresh functionality
- Handle missing/invalid data gracefully
- Batch enrichment
- Enrichment with limit
- Enrich by specific ticker
- Handle ticker not found
4. Deployment Infrastructure
Dockerfile: Production-ready container imagedocker-compose.yml: Full stack (app + PostgreSQL).dockerignore: Optimize image sizedocs/07_deployment.md: Comprehensive deployment guide- Local development (SQLite)
- Single server (PostgreSQL + cron)
- Docker deployment
- Cloud deployment (AWS, Fly.io, Railway)
- Cost estimates
- Production checklist
What works now
Enrich Securities from Fixtures
# Our existing fixtures have these tickers: NVDA, MSFT, AAPL, TSLA, GOOGL
# They're created as "unenriched" (name == ticker)
python scripts/enrich_securities.py
# Output:
# Enriching 5 securities
# Enriched NVDA: NVIDIA Corporation (Technology)
# Enriched MSFT: Microsoft Corporation (Technology)
# Enriched AAPL: Apple Inc. (Technology)
# Enriched TSLA: Tesla, Inc. (Consumer Cyclical)
# Enriched GOOGL: Alphabet Inc. (Communication Services)
# ✓ Successfully enriched: 5
Query Enriched Data
from pote.db import SessionLocal
from pote.db.models import Security
from sqlalchemy import select
with SessionLocal() as session:
stmt = select(Security).where(Security.sector.isnot(None))
enriched = session.scalars(stmt).all()
for sec in enriched:
print(f"{sec.ticker}: {sec.name} ({sec.sector})")
Docker Deployment
# Quick start
docker-compose up -d
# Run migrations
docker-compose exec pote alembic upgrade head
# Ingest trades from fixtures (offline)
docker-compose exec pote python scripts/ingest_from_fixtures.py
# Enrich securities (needs network in container)
docker-compose exec pote python scripts/enrich_securities.py
Data Model Updates
No schema changes! The securities table already had all necessary fields:
name: Now populated with full company namesector: Technology, Healthcare, Finance, etc.industry: Specific industry within sectorexchange: NASDAQ, NYSE, etc.asset_type: stock, etf, mutual_fund, index
Key Design Decisions
- Smart Skipping: Only enrich securities where
name == ticker(unenriched) - Force Option: Can re-enrich with
--forceflag - Graceful Degradation: Skip/log if yfinance data unavailable
- Batch Control:
--limitfor rate limiting or testing - Asset Type Detection: Automatically classify ETFs, mutual funds, indexes
Performance
- Enrich single security: ~1 second (yfinance API call)
- Batch enrichment: ~1-2 seconds per security
- Recommendation: Run weekly or when new tickers appear
- yfinance is free but rate-limited (be reasonable!)
Integration with Existing System
After Trade Ingestion
# In production cron job:
# 1. Fetch trades
python scripts/fetch_congressional_trades.py --days 7
# 2. Enrich any new securities
python scripts/enrich_securities.py
# 3. Fetch prices for all securities
python scripts/update_all_prices.py # To be built in PR4
Cron Schedule (Production)
# Daily at 6 AM: Fetch trades
0 6 * * * cd /path/to/pote && venv/bin/python scripts/fetch_congressional_trades.py --days 7
# Daily at 6:15 AM: Enrich new securities
15 6 * * * cd /path/to/pote && venv/bin/python scripts/enrich_securities.py
# Daily at 6:30 AM: Update prices
30 6 * * * cd /path/to/pote && venv/bin/python scripts/update_all_prices.py
Deployment Options
| Option | Complexity | Cost/month | Best For |
|---|---|---|---|
| Local | ⭐ | $0 | Development |
| VPS + Docker | ⭐⭐ | $10-20 | Personal deployment |
| Railway/Fly.io | ⭐ | $5-15 | Easy cloud |
| AWS | ⭐⭐⭐ | $20-50 | Scalable production |
See docs/07_deployment.md for detailed guides.
Next Steps (PR4+)
Per docs/00_mvp.md:
- PR4: Analytics - abnormal returns, benchmarks
- PR5: Clustering & signals
- PR6: FastAPI + dashboard
How to Use
1. Enrich All Securities
python scripts/enrich_securities.py
2. Enrich Specific Ticker
python scripts/enrich_securities.py --ticker NVDA
3. Re-enrich Everything
python scripts/enrich_securities.py --force
4. Programmatic Usage
from pote.db import SessionLocal
from pote.ingestion.security_enricher import SecurityEnricher
with SessionLocal() as session:
enricher = SecurityEnricher(session)
# Enrich all unenriched
counts = enricher.enrich_all_securities()
print(f"Enriched {counts['enriched']} securities")
# Enrich specific ticker
enricher.enrich_by_ticker("AAPL")
Test Coverage
pytest tests/ -v
# 37 tests passing
# Coverage: 87%+
# New tests:
# - test_security_enricher.py (9 tests)
Cost: Still $0 (yfinance is free!)
Dependencies: yfinance (already in pyproject.toml)
Research-only reminder: This tool is for transparency and descriptive analytics. Not investment advice.