11 KiB
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)
# 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
# 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
# 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/:
{
"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:
{
"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
# 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
# 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.