diff --git a/README.md b/README.md new file mode 100644 index 0000000..48551a2 --- /dev/null +++ b/README.md @@ -0,0 +1,323 @@ +# ACE-F v1 — US Stock Event Swing Trading System + +AI-powered event-driven swing trading system that uses SEC filings and free market data +to identify 1-5 day continuation trades in US equities. + +**Core principle:** AI/LLM is a document interpreter, not a price predictor. +Entry signals come from official filings + price confirmation, never from social data alone. + +``` +SEC Filings → Document Parser → Feature Builder → Signal Ranker + ↓ ↓ +Price/Volume Confirmation ←──── Backtest Engine ←── Risk Engine + ↓ ↓ +Attention Overlay (optional) ──→ Execution Engine → Post-trade Review +``` + +## Architecture + +``` +apps/ # Application entry points +├── backtester/ # Event-driven backtest simulation & CLI +├── pipeline/ # Multi-stage data processing +│ ├── filing_poller/ # Poll SEC EDGAR for new filings +│ ├── filing_fetcher/ # Download filing documents +│ ├── event_parser/ # Parse events from filings (rule + LLM) +│ ├── feature_builder/ # Generate scoring features +│ ├── label_generator/ # Create forward-return labels +│ └── dataset_export/ # Export Parquet snapshots for backtesting +├── sync/ # Data synchronization +│ ├── issuer_sync/ # Company metadata from Stock Oracle +│ ├── macro_sync/ # FRED macro indicators +│ └── short_volume_sync/ # FINRA short sale volume +├── tracker/ # Strategy improvement tracking CLI +├── tools/ # Analysis & utility scripts +├── review/ # Manual review queue +└── qa/ # Data quality checks + +libs/ # Core libraries +├── backtest/ # Backtesting engine +│ ├── domain.py # Pydantic domain models (30+) +│ ├── tracker.py # SQS scoring, journal I/O, leaderboard +│ ├── execution.py # Entry/exit simulation +│ ├── allocator.py # Position sizing & entry gates +│ ├── scoring.py # Candidate scoring (PEAD, composite) +│ ├── selector.py # Candidate filtering & ranking +│ ├── metrics.py # 21-metric performance bundle + bootstrap CIs +│ ├── artifacts.py # Run output writer (Parquet, JSON, CSV) +│ ├── manifests.py # Experiment config resolution +│ ├── snapshot_store.py # Parquet data loader +│ ├── splits.py # Walk-forward window generation +│ └── calendar.py # Trading day utilities +├── common/ # Logging, config, time utils +├── db/ # PostgreSQL models (async SQLAlchemy) +├── oracle_client/ # Stock Oracle API client +├── parser/ # Filing document parser +├── features/ # Feature engineering +├── labeler/ # Label generation +├── schemas/ # Shared data schemas +├── export/ # Snapshot export +├── review/ # Review logic +└── llm/ # LLM integration layer + +configs/ +├── backtest/ # Base backtest configs (defaults.json) +├── experiments/ # 66 experiment manifests +├── app.yaml # Application settings +└── symbols_*.yaml # Asset universe definitions + +data/ # Data storage (parquet snapshots, cache) +runs/ # Backtest execution outputs +journal/ # Strategy improvement journal & leaderboard +tests/ +├── unit/ # Unit tests (270+) +├── integration/ # Integration tests (requires PostgreSQL) +└── replay/ # Determinism replay tests +``` + +## Setup + +**Requirements:** Python 3.11+, PostgreSQL 16 (via Docker) + +```bash +# Install dependencies +pip install -e ".[dev]" + +# Start PostgreSQL +docker compose up -d + +# Run database migrations +alembic upgrade head + +# Copy and configure environment +cp .env.example .env +``` + +**Key environment variables:** + +| Variable | Default | Description | +|----------|---------|-------------| +| `STOCK_ORACLE_URL` | `http://localhost:18001` | Stock Oracle API endpoint | +| `POSTGRES_DSN` | `postgresql+asyncpg://acef:acef@localhost:5432/acef` | Database connection | +| `DATA_ROOT` | `./data` | Data storage root | +| `LOG_LEVEL` | `INFO` | Logging level | +| `LLM_ENABLED` | `false` | Enable LLM document parsing | + +## Usage + +### Data Pipeline + +```bash +# Sync company metadata +python -m apps.sync.issuer_sync.main + +# Fetch and parse filings +python -m apps.pipeline.filing_poller.main +python -m apps.pipeline.filing_fetcher.main +python -m apps.pipeline.event_parser.main + +# Build features and labels +python -m apps.pipeline.feature_builder.main +python -m apps.pipeline.label_generator.main + +# Export Parquet snapshot for backtesting +python -m apps.pipeline.dataset_export.main +``` + +### Backtesting + +```bash +# Single split backtest +python -m apps.backtester.run \ + --manifest configs/experiments/pead_midcap_step1_fixedr.json \ + --split test --output-root runs/midcap_steps + +# 3-split backtest (train/valid/test) +for split in train valid test; do + python -m apps.backtester.run \ + --manifest configs/experiments/pead_midcap_step1_fixedr.json \ + --split $split --output-root runs/midcap_steps +done + +# Walk-forward cross-validation +python -m apps.backtester.run \ + --manifest configs/experiments/pead_midcap_step1_fixedr.json \ + --walk-forward --wf-train-days 252 --wf-test-days 63 + +# Output includes SQS score after each run: +# Run complete: bt_baseline_swing_v1_... +# Trades: 95 +# Total return: -0.46% +# SQS: 39.7 (profitability=23.9, risk=52.4, consistency=24.8, robustness=80.7) +``` + +### Experiment Configuration + +Experiments are defined as JSON manifests in `configs/experiments/`: + +```json +{ + "experiment_name": "pead_midcap_step1_fixedr", + "dataset_snapshot_id": "midcap-filtered", + "base_config": "configs/backtest/defaults.json", + "overrides": { + "signal": { "scoring_model": "pead", "pead_reaction_threshold": 0.07 }, + "execution": { "target_model": "fixed_r", "target_1_r": 2.0 }, + "risk": { "max_positions": 8 } + }, + "tags": ["pead", "midcap"] +} +``` + +--- + +## Strategy Improvement Tracking System + +A structured system to prevent duplicate experiments, enable data-driven decisions, +and track the best strategy via a leaderboard. + +### Strategy Quality Score (SQS) + +Composite score (0-100) computed from **test split metrics only**. Higher is better. + +| Category | Weight | Sub-metric | Weight | 0 pts | 100 pts | +|----------|--------|------------|--------|-------|---------| +| **Profitability** | 40% | profit_factor | 60% | ≤0.8 | ≥2.0 | +| | | total_return_pct | 40% | ≤-5% | ≥+5% | +| **Risk** | 25% | max_drawdown_pct (inv) | 50% | ≥10% | ≤1% | +| | | sharpe_ratio | 50% | ≤-1.0 | ≥2.0 | +| **Consistency** | 20% | win_rate | 50% | ≤0.35 | ≥0.65 | +| | | monthly_win_rate | 50% | ≤0.30 | ≥0.70 | +| **Robustness** | 15% | equity_curve_r_squared | 50% | ≤0.0 | ≥0.80 | +| | | trade_count | 50% | ≤10 | ≥100 | + +**Low-trade penalty:** If test trades < 20, SQS is halved. + +| SQS Range | Interpretation | +|-----------|----------------| +| 0-20 | Losing strategy | +| 20-40 | Near breakeven | +| 40-55 | Promising, needs work | +| 55-70 | Good, has OOS edge | +| 70-85 | Strong, live candidate | +| 85-100 | Exceptional (check for data issues) | + +### Journal & Leaderboard + +``` +journal/ +├── improvement_journal.jsonl ← Append-only improvement cycle log +├── experiment_registry.json ← Leaderboard data (regenerated) +└── LEADERBOARD.md ← Human-readable leaderboard (regenerated) +``` + +Each journal entry records one improvement cycle: + +```json +{ + "entry_id": "IMP-0001", + "timestamp": "2026-03-16T19:30:00", + "experiment_name": "pead_midcap_step3_10pct", + "hypothesis": "Raise reaction threshold to 10% for stronger signals", + "results": { + "train": { "run_id": "bt_...", "trade_count": 420, "profit_factor": 0.95, ... }, + "valid": { "run_id": "bt_...", ... }, + "test": { "run_id": "bt_...", ... } + }, + "sqs_score": 38.5, + "sqs_breakdown": { "profitability": 35.2, "risk": 45.0, "consistency": 30.0, "robustness": 42.0 }, + "verdict": "better", + "verdict_reasoning": "Test PF 0.89 -> 1.00, breakeven achieved", + "next_direction": "Combine 10% threshold + maxcand3" +} +``` + +### Tracker CLI + +```bash +# Record experiment results to journal +python -m apps.tracker.cli record \ + --journal-dir journal/ \ + --runs-dir runs/midcap_steps/ \ + --experiment pead_midcap_step3_10pct \ + --hypothesis "Raise reaction threshold to 10%" \ + --baseline pead_7pct_midcap \ + --verdict better \ + --reasoning "Test PF improved from 0.89 to 1.00" \ + --next "Combine 10% threshold + maxcand3" + +# View leaderboard +python -m apps.tracker.cli leaderboard --journal-dir journal/ + +# # Experiment SQS PF Ret% Trades +# ------------------------------------------------------------------ +# 1 pead_7pct_longshort_v2 60.7 1.31 +2.0 55 +# 2 pead_midcap_step3_10pct 38.5 1.00 +0.0 85 + +# Show entry details +python -m apps.tracker.cli show --journal-dir journal/ IMP-0001 + +# Check for duplicate experiments +python -m apps.tracker.cli check-duplicate \ + --journal-dir journal/ --experiment pead_midcap_step3_10pct +``` + +### Improvement Workflow + +``` +1. Create experiment config configs/experiments/my_experiment.json +2. Run 3-split backtest for split in train valid test; do ... done +3. Record to journal python -m apps.tracker.cli record ... +4. Check leaderboard python -m apps.tracker.cli leaderboard ... +5. Plan next experiment based on verdict + SQS breakdown +6. Check for duplicates python -m apps.tracker.cli check-duplicate ... +7. Repeat from step 1 +``` + +--- + +## Testing + +```bash +# Unit tests (fast, no external deps) +pytest tests/unit/ -v + +# Backtest module tests only +pytest tests/unit/backtest/ -v + +# Integration tests (requires PostgreSQL) +pytest tests/integration/ -v + +# Full CI check (lint + typecheck + unit tests) +make ci +``` + +## Data Sources + +| Source | Role | Cost | +|--------|------|------| +| **SEC EDGAR** | Primary event source (8-K, 10-Q, 6-K filings) | Free | +| **Stock Oracle API** | Market data (OHLCV bars, company info) | Internal | +| **FRED** | Macro regime indicators (rates, spreads) | Free | +| **FINRA** | Short sale volume (crowding signal) | Free | +| Wikimedia | Retail attention via pageviews | Free | +| YouTube | Channel-based attention tracking | Free (quota limited) | +| Yahoo RSS | Headline burst detection | Free | + +## Tech Stack + +| Component | Technology | +|-----------|-----------| +| Language | Python 3.11+ | +| Models | Pydantic v2 | +| Database | PostgreSQL 16 + async SQLAlchemy | +| Research data | DuckDB + Parquet | +| Containers | Docker Compose | +| Linting | Ruff | +| Type checking | MyPy (strict) | +| Testing | Pytest + asyncio | +| Logging | structlog (JSON) | + +## License + +Private project. All rights reserved.