Phase 0: Project Scaffold
Status: ✅ Complete
Duration: ~2 hours
Date: February 24, 2026
Objectives
Phase 0 established the complete project infrastructure before any business logic implementation:
- ✅ Git repository initialization
- ✅ Python environment with uv
- ✅ Full directory scaffold with module stubs
- ✅ Configuration system (TOML + Doppler secrets)
- ✅ Dev tooling (ruff, pre-commit, pytest)
- ✅ CI/CD pipelines (GitHub Actions)
- ✅ Deployment configuration (Heroku)
- ✅ Documentation scaffold (MkDocs)
- ✅ Initial commit and remote push
Deliverables
Repository Structure
quant-portfolio-monitor/
├── .devcontainer/ # GitHub Codespaces config
├── .github/workflows/ # CI/CD pipelines
├── bin/ # Heroku post-compile hook
├── docs/ # MkDocs documentation
├── quant_monitor/ # Main package
│ ├── agent/ # Fusion, optimizer, risk, alerts
│ ├── backtest/ # Walk-forward engine
│ ├── dashboard/ # Streamlit app
│ ├── data/ # Pipeline, cache, sources
│ ├── features/ # MA, volatility, sentiment
│ ├── models/ # Tech, fund, sentiment, macro
│ └── spiders/ # Scrapy spiders for Zyte
├── scripts/ # Utility scripts
├── tests/ # pytest test suite
├── pyproject.toml # uv project config
├── uv.lock # Dependency lockfile
├── Procfile # Heroku process definitions
├── doppler.yaml # Doppler project config
└── README.md # Project overview
Dependencies Installed
188 packages resolved in uv.lock, including:
| Category | Packages |
|---|---|
| Data Sources | alpaca-py, requests, feedparser |
| Database | duckdb, diskcache |
| NLP/ML | transformers, sentence-transformers, torch |
| Portfolio | pyportfolioopt |
| Data Processing | pandas, numpy, scipy |
| Dashboard | streamlit, plotly, matplotlib |
| Scheduling | apscheduler |
| Alerts | python-telegram-bot |
| Backend | appwrite |
| Scraping | scrapy |
| Dev Tools | pytest, ruff, mypy, pre-commit, mkdocs-material |
Configuration
config.toml contains all non-secret configuration: - 15 portfolio holdings with qty, price_paid, sector - Cache TTL values per data type - Regime-weighted fusion weights (5 regimes × 4 models) - Risk parameters per macro regime - Signal thresholds (confidence, drift, kill switch) - Moving average periods - Volatility classifier parameters - Sentiment model config - Macro model thresholds
Doppler manages secrets:
- ALPACA_API_KEY / ALPACA_SECRET_KEY
- FRED_API_KEY
- TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID
- APPWRITE_ENDPOINT / APPWRITE_PROJECT_ID / APPWRITE_API_KEY
- ZYTE_API_KEY
- SEC_EDGAR_USER_AGENT
Module Stubs
Every module has a stub with:
- Docstring explaining purpose
- Class/function signatures
- # TODO Phase N markers
- Type hints for all parameters/returns
Example from quant_monitor/agent/fusion.py:
class SignalFusion:
"""Fuses 4 model signals with dynamic regime-dependent weights."""
def fuse(
self,
technical: float,
fundamental: float,
sentiment: float,
macro: float,
regime: str,
) -> dict:
"""Compute fused signal for a single ticker.
Returns:
dict with keys: fused_score, confidence, action, dominant_model
"""
# TODO Phase 6
raise NotImplementedError
Tests
6 tests passing:
| Test | Purpose |
|---|---|
test_config_toml_exists |
Verify config.toml is present and parseable |
test_config_loader |
Verify config.py loads TOML + env vars |
test_all_holdings_have_required_fields |
Validate all 15 holdings have required fields |
test_pipeline_placeholder |
Placeholder for Phase 1 |
test_moving_averages_placeholder |
Placeholder for Phase 2 |
test_technical_model_placeholder |
Placeholder for Phase 3 |
CI/CD
ci.yml: - Triggers on push/PR to main - Installs uv, syncs deps - Runs ruff check + format check - Runs mypy (non-blocking) - Runs pytest
deploy.yml: - Triggers on push to main - Generates requirements.txt from uv - Deploys to Heroku via action - Builds and deploys MkDocs to GitHub Pages
Heroku Configuration
Procfile: web (Streamlit) + worker (APScheduler)runtime.txt: Python 3.11.11bin/post_compile: Installs uv in Heroku buildpack
Verification
All checks passed:
# Package imports
$ uv run python -c "import quant_monitor; print('OK')"
OK
# Config loads
$ uv run python -c "from quant_monitor.config import cfg; print(len(cfg.tickers))"
15
# Main runs
$ uv run python -m quant_monitor.main
2026-02-24 13:54:56 | Quant Portfolio Monitor starting
2026-02-24 13:54:56 | Tracking 15 positions | Benchmark: SPY
2026-02-24 13:54:56 | Scheduler not yet implemented — exiting cleanly
# Lint clean
$ uv run ruff check .
All checks passed!
# Tests pass
$ uv run pytest tests/ -v
6 passed in 0.11s
Git History
commit 4240600
Author: Kartavya Jharwal <kjisgreatforever@gmail.com>
Date: Mon Feb 24 13:55:00 2026
Initial scaffold: 5-layer quant portfolio monitoring system
- uv project with 188 resolved deps
- config.toml with all 15 holdings, regime weights, risk params
- Full module stubs: data, features, models, agent, backtest, dashboard
- Dev tooling: ruff, pre-commit, mypy, pytest (6 tests passing)
- CI/CD: GitHub Actions for lint/test/deploy
- Heroku: Procfile + runtime.txt + bin/post_compile
- MkDocs docs scaffold for post-sunset archive
- Scrapy Cloud config for Zyte spider deployment
68 files changed, 6244 insertions(+)
Lessons Learned
- torch download time: 108MB download took significant time. Fixed by:
- Setting
UV_CACHE_DIRto D: drive (avoids cross-drive copies) - Keeping torch as transitive dependency (via transformers)
-
Using pytorch-cpu index to avoid CUDA bloat
-
uv packaging warning: Needed
[build-system]in pyproject.toml for entry points -
Scrapy ClassVar: Ruff's RUF012 rule requires
ClassVarannotation for mutable class attributes in Scrapy spiders -
StrEnum migration: Ruff's UP042 recommends
enum.StrEnumover(str, Enum)inheritance
Next Steps
Phase 1: Data Pipeline - Implement Alpaca feed (real-time prices + news) - Implement FRED feed (macro indicators) - Implement Appwrite client (read/write) - Implement diskcache wrapper - Implement pipeline orchestrator with failover - Deploy SEC EDGAR + Google RSS spiders to Scrapy Cloud
Phase 0 completed: February 24, 2026