Imported from austinyuch/finance_algorithms (
AGENTS.md). Install upstream withnpx skills add austinyuch/finance_algorithms. Copyright stays with the author.
Agent Guide
This file is the operating guide for coding agents working in this repository.
First Reads
Start with these files before making non-trivial changes:
.agents/specs/SPECS.md.agents/specs/NEXT_STEPS.md- The relevant spec folder under
.agents/specs/ quantlab/CORRECTNESS_CHECKLIST.mdfor backtest correctness constraintsquantlab/TESTS.mdfor the test registry
Project Shape
invest_algorithms/is the legacy FastAPI pyramid calculator. Preserve existing behavior unless a task explicitly targets it.quantlab/is the newer research platform built through SDD specs..agents/specs/is the source of truth for requirements, designs, reviews, and task history.data/vintage/raw/is append-only point-in-time data. Do not overwrite existing daily snapshots.
Development Commands
Use uv:
uv sync
uv run pytest -q
uv run mypy quantlab/ --ignore-missing-imports
uv run lint-imports
Useful demo commands:
uv run python scripts/run_tsmc_hedge_slice.py
uv run python scripts/run_vintage_slice.py
uv run python scripts/daily_snapshot.py --dry-run
To run the legacy API:
cd invest_algorithms
uv run uvicorn api:app --host 127.0.0.1 --port 2224
Generated Documentation
Stakeholder-facing docs live under docs/ and are regenerated from the specs
plus refreshed gate evidence. Keep readiness claims copied from
.agents/specs/**/review.md (never derived from task counts):
- User manual —
docs/manual/{en,zh-tw}/index.{md,html}. Regeneration steps:docs/MANUAL_GENERATION_GUIDE.md. The bilingual manual is regenerated per that guide with real CLI/API evidence and briefly-started services (CLI demos,frontendsmoke + headless screenshot, and a transient legacyuvicorncurl), and reconciled against the spec governance set (.agents/specs/{NEXT_STEPS,SPECS,ISSUE_LOG,RTM}.md+docs/FEATURES.md). - Executive review —
docs/review/index.html. Regeneration steps:docs/REVIEW_GENERATION_GUIDE.md. Regenerated per that guide with real gate/CLI evidence and started services, a Gap Analysis that separates resolved-since-last-check from still-open (no false greens, claim cap fromreview.md), and an audit row recorded in.agents/specs/ISSUE_LOG.md. - Both the manual and review now cover Epic H through slice H-3
(interactive research UI): the manual's bilingual Flow 8 and the review's H-3
core-feature card. Its dedicated evidence path is the real-Chromium
cd frontend && npm run e2e:interactivefail-closed VRT (computed→ seed change →fail_closed, 0-pixel diff vsfrontend/visual-baselines/interactive-research-failclosed.png); readiness is copied from.agents/specs/h-interactive-research-ui/review.md. - Deploy-coupling / count-refresh caveat (manual & review): the committed
docs/manual/**+docs/review/index.htmlgate counts, thedocs/showcase.jsonpayload, itsdataHash, and the public-hosting proof are a single deploy-coupled snapshot — refresh them only as part of a real GitHub Pages deploy, never as a standalone "make the published number current" edit (it shifts thedataHash, flips hosting toconfigured_not_observeduntil a post-deploy live re-probe, and the Copilot PR reviewer + bilingual surface make it non-converging — see each guide's "Deploy-coupling & count-refresh policy" section and the abandoned PR #131 in.agents/specs/NEXT_STEPS.md). The current validated numbers live in the governance SoT (quantlab/TESTS.md,.agents/specs/{SPECS,RTM,NEXT_STEPS}.md,docs/FEATURES.md); the manual/review HTML reflect the last-deployed snapshot. Worked example (2026-06-21): the H-4 deploy (PRs #135 payload+counts, #136 re-prove) advanced the snapshot to pytest 478 / frontend 70 / Python mutation 123 atdataHash 6c18e572…(public hostingproven/matched) — the step-by-step follows the deploy-coupling & count-refresh policy indocs/{MANUAL,REVIEW}_GENERATION_GUIDE.md. - Shared contracts —
docs/FEATURES.md,docs/EVIDENCE_METADATA_CONTRACT.md,docs/DEMO_RISK_WARNING_TAXONOMY.md. - Traceability bridge —
.agents/specs/RTM.md(verification context only, not a readiness authority).
Live, port-bound services for evidence capture must go through
local-infra-registry-governance; CLI demos and the committed static export
need no port allocation and are the default evidence path.
Architecture Rules
quantlab.engineandquantlab.datamust not importtorch,tensorflow,jax, orflax.- Keep ML framework code behind strategy adapters or environment-specific modules.
- Epic H (deep-learning research lab) keeps frameworks behind
quantlab/models/dl/backends.py(FrameworkAdapterRegistry): torch/jax/tf are resolved lazily and degrade honestly to the framework-freereferencebackend when absent. A second import-linter contract forbidsengine/datafrom importing the DL backend boundary.quantlab/models/dl_forecaster.py(reference MLP),quantlab/research/model_performance_report.py+model_report_viz.py(stats/viz), andscripts/run_dl_experiment.py(parameterized experiment CLI →ExperimentRegistrylineage) are allno_alpha_claim. Epic H slice H-2 (h-deep-learning-real-training) adds a real PyTorch training path inquantlab/models/dl/torch_trainer.py(lazyimport torch, float64, seed-init parity with the reference within1e-3), reached only via theNumpyMLPForecasterbackend dispatch whenbackend="pytorch"resolves; it runs in an optional default-skipped torch lane (tests/quantlab/test_h2_torch_training.py,pytest.importorskip("torch")) and degrades honestly toreferencewhen torch is absent. Torch stays out of the default lock; the canonical no-skip pytest count is captured in a torch-enabled venv. Epic H slice H-3 (h-interactive-research-ui) adds an interactive parameter UI over the existing H artifacts on the showcase dashboard: a deterministicstatic_replayblock inquantlab/showcase/scenario.pyfeedsfrontend/lib/interactive-research.ts+frontend/components/InteractiveResearchPanel.tsx, which keep OOS-net-only ranking with a visible baseline,no_alpha_claim, approximate-data warnings, and fail-closed behavior on unsupported parameter sets or stale checksums. It is local/static-replay only — no live backend rerun API, real JAX/TF training, GPU/native models, or production Tier3 claim — and is proven bytests/quantlab/test_h3_interactive_showcase.py,frontend/tests/interactive-research.test.ts, and a real-Chromiumnpm run e2e:interactivefail-closed VRT. - Keep
quantlab/contracts/interfaces.pystructurally aligned with.agents/specs/a0-backtest-foundation/contract/interfaces.py. - For schema changes, update the spec contract first, regenerate generated models if needed, and run tests plus mypy.
- Backtest results should report out-of-sample net metrics when used for leaderboard comparisons.
- PIT access must respect
available_date <= asof; avoid any shortcut that can introduce lookahead. - Preserve survivorship handling through listings data.
- Cost, tax, slippage, FX, and walk-forward behavior are correctness-sensitive. Add or update tests when touching them.
Data Rules
- Vintage snapshots are immutable. If a daily file exists, skip it instead of overwriting it.
available_daterepresents when the project captured or could have known a value.- If historical data is reconstructed without a true vintage source, mark it approximate and keep strict/lenient behavior explicit. The CR-B21 deep historical backfill (
scripts/backfill_history.py→data/vintage/raw/backfill-1990-01-01/, 1990+) is exactly this case: every record isis_approximate=true+backfill=true, strict PIT mode excludes it, and onlyapproximate_availability=True(research mode) exposes it underno_alpha_claim. - Snapshot fetching should degrade per source: one failed external source should not corrupt other captures (the CR-B21 backfill follows the same per-source degradation + idempotent-skip contract).
- The daily loop needs outbound HTTPS to
fred.stlouisfed.org,query1.finance.yahoo.com, andwww.cpc.ncep.noaa.gov. When it runs in a Claude Code remote environment, the egress proxy must allowlist those hosts; a blanket403 Forbidden/ProxyError: Tunnel connection failedon every source is an egress-policy denial (operator allowlists the hosts), not a code or data bug. See.agents/specs/allweather-portfolio-platform/03-data-vintage-snapshot-policy.mdDecision 6.
Testing Expectations
- For documentation-only edits, no full test run is required.
- For code touching
quantlab/engine,quantlab/data, contracts, costs, metrics, or portfolio logic, runuv run pytest -q. - For typed QuantLab changes, run
uv run mypy quantlab/ --ignore-missing-imports. - For imports involving
quantlab.engineorquantlab.data, runuv run lint-imports. - For legacy
invest_algorithms/changes, runuv run pytest -q tests/test_algo_pyramid.pyat minimum.
Local-First CI Policy
Hosted GitHub Actions are cost-sensitive. Use .agents/skills/local-first-ci/
when a task mentions CI, workflow cost, pre-merge gates, smoke tests, mutation
tests, or "run what CI would run". Run the matching local gates first and do not
trigger or rerun GitHub Actions unless the user explicitly asks or the proof
genuinely depends on GitHub-hosted state. Use local subagents or parallel local
shells for independent CI-equivalent gates when that can reduce hosted workflow
usage without weakening evidence. Treat routine CI as local subagent gate
bundles first: Python, static typing/import architecture, mutation, frontend,
smoke, visual, audit, and evidence-regeneration checks should complete locally
before hosted CI is used for confirmation. Normal tests and workflow steps that
would usually be queued in CI should be treated as local completion work first.
When this repo has an equivalent command, split the gate into subagent-owned
bundles when possible. Treat "CI would catch this" as a
local/subagent responsibility first; use hosted Actions only for confirmation or
claims that require GitHub-hosted event semantics, secrets, permissions,
artifact transport, scheduled triggers, or Pages deployment state. Do not leave
unit/integration, line coverage, PBT, mutation, smoke, build, visual, audit,
type/import, or generated-evidence sync gates for hosted CI when the repo has a
local command that can prove them. Before a push intended to trigger Actions,
complete the local/subagent matrix or record the exact hosted-only gap; do not
use GitHub Actions as the routine queue for CI-equivalent work that local
subagents can finish.
Commit, push, and PR-prep requests inherit this policy unless the user
explicitly asks to skip local gates. Split independent CI-equivalent bundles
across local subagents when available, but keep file-mutating gates such as
mutation tests isolated and reconcile all evidence in the main agent before
claiming readiness. Subagent-owned gates should return the command, exit status,
key evidence, and any hosted-only gap; treat that as the local CI decision path,
not just a preflight before spending GitHub Actions minutes. Use the handoff
fields from .agents/skills/local-first-ci/: Scope, Command, Isolation,
Evidence, Remainder, changed files if any, and a fail-closed stop rule for the
first unexplained failure.
Completion means producing the same local pass/fail decision the hosted CI step would have produced, not merely a preflight before Actions. If workflow or Actions cost is the concern, maximize local/subagent completion of the normal CI test and workflow matrix. Slow local execution is not by itself a hosted-only gap.
When reducing Actions cost, treat the normal CI flow as a local/subagent takeover target: inspect the workflow or documented gate, map ordinary test, coverage, mutation, smoke, build, visual, audit, type/import, dependency, and generated-evidence steps to repo-local commands, and finish those locally before hosted confirmation. Only GitHub event semantics, secrets/permissions, artifact transport, scheduled triggers, Pages deployment state, protected environments, and remote production identity should remain hosted-only. If the user explicitly says GitHub workflows or Actions are expensive, complete the ordinary CI test and workflow matrix through local commands, subagents, or isolated local shells as far as practical. Do not leave a repo-runnable CI step for Actions merely because it is slow or normally belongs to the hosted workflow. Prompts such as "盡可能在local", "CI流程都subagent完成", or "gh workflow and actions很貴" mean the normal CI queue should be taken over locally first: inspect workflow YAML, translate ordinary steps to local commands, split independent gates across local subagents or shells, serialize file-mutating mutation/generated-artifact gates, and keep only GitHub-hosted semantics in the hosted-only ledger.
For push/PR readiness, build a local CI replacement matrix from the touched files and finish it before using hosted Actions for confirmation. The matrix should cover any repo-available unit, integration, line coverage, PBT, mutation, smoke, build, visual, audit, type/import, dependency, and generated-evidence checks. If a remaining gate is truly hosted-only, record the expected workflow, why local/subagent evidence is insufficient, the smallest hosted run needed, and the local evidence already completed.
Style Notes
- Prefer small, spec-aligned changes over broad refactors.
- Use existing local patterns before adding abstractions.
- Keep public behavior stable unless the relevant spec or user request calls for a change.
- Do not remove user-created files or untracked files unless explicitly asked.
- Keep docs and comments concise, but record decisions in the spec artifacts when they affect future work.