Files
fxhnt/docs/architecture/0001-architecture.md
jgrusewski 58bbb4520c feat: fxhnt foundation — hexagonal architecture + proven gauntlet + vertical slice
Enterprise clean-rebuild (no foxhunt code). Hexagonal/ports-and-adapters: pure domain (gauntlet
math, strategies, backtest, models) | ports (DataProvider, repositories) | adapters (Yahoo data,
SQLAlchemy operational [Postgres/SQLite], DuckDB analytical) | application (ResearchService, DI) |
CLI composition root. Gauntlet-first: Deflated Sharpe (Bailey-LdP) built + falsification-tested
(kills best-of-N-on-noise, keeps real premium). Full vertical slice runs end-to-end on real data:
data -> strategy(trend) -> backtest(net of costs) -> IS/OOS gauntlet -> persistence. 4/4 tests green.
Postgres+DuckDB split, pydantic contracts, typed, DRY via one-contract-per-port. ADR + README.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 12:21:47 +02:00

2.8 KiB
Raw Blame History

ADR 0001 — Foundational architecture

Status: accepted · Date: 2026-06-09

Context

fxhnt is an agentic platform that systematically discovers, backtests and OOS-validates trading strategies across many markets — and runs the survivors live (multiple strategies at once). The value is NOT a secret edge; it is breadth + discipline + automation. The #1 existential risk is multiple-testing: a fast search over thousands of (strategy × market) combos manufactures false positives unless the statistics correct for the full search. This must be designed-in, not bolted-on.

Decisions

  1. Hexagonal / ports-and-adapters (clean architecture).

    • domain/ — pure business logic (gauntlet math, strategies, backtest, portfolio). No I/O.
    • ports/ — abstract contracts (DataProvider, Broker, repositories).
    • adapters/ — concrete infra (Yahoo/Databento data, IBKR broker, SQLAlchemy/DuckDB stores).
    • application/ — use-case services that orchestrate the domain via ports (dependency-injected).
    • cli.py — the single composition root that wires concrete adapters.
    • Rationale: swappable infra, isolated testability, DRY (one contract per port, no copy-paste adapters).
  2. Gauntlet first. The Deflated-Sharpe validation engine (Bailey & López de Prado) is built and falsification-tested (must kill best-of-N-on-noise, keep a real premium) BEFORE any search is built on top. n_trials/sr_variance carry the full search size into the verdict.

  3. Persistence split: Postgres (operational) + DuckDB (analytical). Relational store for runs, verdicts, the survivor library, positions, trades; columnar store for market data + backtest timeseries. Both behind repository ports; SQLAlchemy makes the operational store DB-agnostic (SQLite for dev/test, Postgres in production via FXHNT_OPERATIONAL_DSN).

  4. Contracts via pydantic; numeric value objects via frozen dataclasses. Serializable, validated models cross boundaries; numpy-holding objects (PriceSeries, BacktestResult) stay in-memory.

  5. Clean rebuild (no foxhunt code). A pristine codebase; proven ideas are re-implemented cleanly.

Non-negotiable principles

  • domain/ imports nothing infrastructural (enforced by review/structure).
  • Every strategy must declare a structural rationale to register (the gauntlet requires one).
  • Conservative validation defaults (DSR ≥ 0.95 over the full search; OOS must hold).

Build order (so we never ship a POC pretending to be an app)

gauntlet → contracts/domain → data adapter → persistence → application slice → execution layer (multi-strategy) → discovery/agentic search → portfolio assembly → live execution. This pass delivers a full vertical slice (data → strategy → backtest → gauntlet → persistence).