hurst-framework
v0.2.0
Published
**Hurst Trading Framework** — a TypeScript algorithmic trading engine for Interactive Brokers (IBKR) and beyond. Write a strategy once, run it unchanged in backtest, paper, and live modes.
Downloads
293
Readme
hurst-framework
Hurst Trading Framework — a TypeScript algorithmic trading engine for Interactive Brokers (IBKR) and beyond. Write a strategy once, run it unchanged in backtest, paper, and live modes.
License: ISO NORD CA Commercial & Source-Available (LicenseRef-ISO-NORD-CA-1.0) · Status: ✅ Phase 1+ implemented (backtest engine, CSV+Parquet adapters, extended metrics, JSON output) · npm: [email protected]
Current Status
Phase 1 is implemented. src/ contains a working hexagonal backtest engine —
core types, IDataFeed/ParquetAdapter, IBroker/BacktestBroker, Portfolio with
isolated sub-portfolios, BacktestEngine, two example strategies (SMA crossover,
mean-reversion), Sharpe/Sortino/max-drawdown/win-rate metrics, and a hurst backtest
CLI — with a passing Vitest suite (72 tests) and a clean npm run build. Still
pending (Phase 2+, per the design spec): IBKR connection (PaperBroker/IBBroker are
stub classes only), Docker packaging, npm publish, and the full 55-strategy library.
The Full Vision section below is the end-state
blueprint; the Phase 1 section below is what's built now.
Full design detail: docs/superpowers/specs/2026-08-12-core-engine-design.md.
Implementation plan: docs/superpowers/plans/2026-08-12-core-engine-implementation.md.
Repo uses a single branch (main) — no master; work lands via short-lived feature
branches merged directly into main.
Quick Start
Runnable today, against the bundled sample fixture:
git clone https://github.com/iso-nord-ca/hurst-framework
cd hurst-framework
npm install
npm run build
node dist/cli/index.js backtest --strategies sma,mean-reversion --data test/fixtures/sample.parquet --from 2024-01-01 --to 2024-01-30test/fixtures/sample.parquet is a small synthetic 2-ticker, 30-day fixture generated
by scripts/generate-fixture.ts (regenerate with npx tsx scripts/generate-fixture.ts).
For real data, write a Parquet or CSV file in the same 7-column schema (ticker,
timestamp,open,high,low,close,volume) — see src/data/import/generic-importer.ts
for the importer contract — then point --data at it.
CLI options
| Option | Required | Default | Description |
|---|---|---|---|
| --strategies <names> | ✅ | — | Comma-separated strategy names (sma, mean-reversion) |
| --data <path> | ✅ | — | Path to a Parquet (.parquet) or CSV (.csv) data file |
| --from <date> | ✅ | — | Start date YYYY-MM-DD (filters the data feed) |
| --to <date> | ✅ | — | End date YYYY-MM-DD (filters the data feed) |
| --ticker <symbol> | — | SPY | Ticker symbol passed to strategies |
| --initial-cash <amount> | — | 100000 | Initial cash per strategy |
| --json | — | off | Output the full report as JSON on stdout |
Phase 1: Core Engine
Implemented. This section describes what's built, matching the spec.
Architecture
Hexagonal architecture (ports & adapters): the engine's domain logic never talks to a data source or broker directly, only through interfaces. This is what will let backtest, paper, and live modes reuse identical strategy code without changes.
flowchart TB
subgraph domain["Domain (Phase 1 scope)"]
STRAT["Strategy\n(onBar → Signal)"]
ENGINE["BacktestEngine\n(the loop)"]
PORT["Portfolio\n(sub-portfolios, one per strategy)"]
STRAT -->|Signal| ENGINE
ENGINE -->|Fill| PORT
end
subgraph ports["Ports (interfaces)"]
IDF["IDataFeed"]
IBR["IBroker"]
end
subgraph adapters["Adapters (Phase 1 scope)"]
PARQ["ParquetAdapter"]
BTB["BacktestBroker"]
end
subgraph future["Adapters (later phases)"]
IBKRD["IBKRDataAdapter"]
PAPB["PaperBroker"]
IBB["IBBroker (live)"]
end
IDF --> ENGINE
ENGINE --> IBR
PARQ -.implements.-> IDF
BTB -.implements.-> IBR
IBKRD -.implements.-> IDF
PAPB -.implements.-> IBR
IBB -.implements.-> IBR
style future fill:#00000000,stroke-dasharray: 4 3Data flow
flowchart LR
IMPORT["import script\n(generic source / CSV)"] -->|writes| PARQUET[("data/*.parquet")]
PARQUET --> ADAPTER["ParquetAdapter\n(IDataFeed, streaming)"]
ADAPTER --> LOOP["BacktestEngine.run(strategies[])"]
subgraph fanout["fan-out per bar — concurrent"]
direction TB
SA["Strategy A.onBar"]
SB["Strategy B.onBar"]
SC["Strategy C.onBar"]
end
LOOP --> fanout
SA --> ORD["Signal → Order"]
SB --> ORD
SC --> ORD
ORD --> BROKER["BacktestBroker\n(fills at current bar OHLC)"]
BROKER --> SUBP["Sub-Portfolio\nper strategy"]
SUBP --> REPORT["Per-strategy + aggregate\nBacktestReport"]Parallelism — two independent kinds
flowchart TB
subgraph run1["One BacktestEngine run"]
direction LR
A1["Strategy A"] --> P1["Sub-Portfolio A"]
A2["Strategy B"] --> P2["Sub-Portfolio B"]
A3["Strategy C"] --> P3["Sub-Portfolio C"]
note1["Isolated ledgers — A's fills\nnever touch B's positions,\neven on the same ticker"]
end
subgraph sweep["Concurrent independent runs"]
direction LR
R1["Engine run 1\n(strategy set X, 2020-2022)"]
R2["Engine run 2\n(strategy set Y, 2022-2024)"]
R3["Engine run N…"]
note2["Plain async concurrency\n(Promise.all) — for\nsweeps / leaderboards"]
endComponents — build checklist
| Layer | Component | Status |
|---|---|---|
| Core types | Bar, Signal, Order, Fill, Position | ✅ done |
| Data | IDataFeed interface, ParquetAdapter, CsvAdapter | ✅ done |
| Data | generic import script | ✅ done |
| Data | IBKRImporter | ⏭ later phase (stub only) |
| Broker | IBroker interface, BacktestBroker | ✅ done |
| Broker | PaperBroker, IBBroker | ⏭ later phase (stub only) |
| Engine | Portfolio (sub-portfolios), BacktestEngine | ✅ done |
| Strategy | BaseStrategy, SMA-crossover, mean-reversion examples | ✅ done |
| Metrics | Sharpe, Sortino, max drawdown, win rate, total trades, exposure, annualized return | ✅ done |
| CLI | hurst backtest with --json, --ticker, --initial-cash, date-range filtering | ✅ done |
| Packaging | npm-ready package.json/tsup build, published to npm | ✅ done |
| Docker | — | ⏭ later phase |
| Live/Paper trading | — | ⏭ later phase |
| Risk manager | — | ⏭ later phase |
| 55-strategy library | — | ⏭ later phase |
This table is the single source of truth for what's actually built — update it as pieces land instead of trusting prose elsewhere in this file to stay in sync.
Folder structure
hurst-framework/
├── src/
│ ├── core/ # types.ts, config.ts
│ ├── engine/ # portfolio.ts, backtest-engine.ts
│ ├── data/
│ │ ├── feed.ts
│ │ ├── adapters/parquet-adapter.ts, csv-adapter.ts
│ │ └── import/ # generic-importer.ts, ibkr-importer.ts (stub)
│ ├── brokers/
│ │ ├── broker-interface.ts
│ │ ├── backtest-broker.ts
│ │ ├── paper-broker.ts # stub
│ │ └── ibkr/ibkr-broker.ts # stub
│ ├── strategies/
│ │ ├── base.ts
│ │ └── examples/sma-crossover.ts, mean-reversion.ts
│ ├── metrics/calculator.ts, ratios.ts
│ └── cli/index.ts
├── scripts/ # generate-fixture.ts
├── test/ # Vitest specs mirroring src/, fixtures/ for sample data
├── package.json
├── tsconfig.json
└── tsup.config.tsThe data/ directory is for your own Parquet files; the bundled sample fixture
lives under test/fixtures/sample.parquet for tests and the Quick Start demo.
Error handling
- A strategy's
onBarthrowing fails only that strategy's run (caught per-strategy in the fan-out) — one bad strategy shouldn't abort concurrent runs of the others. ParquetAdapterfails fast on missing/malformed files at construction, not mid-stream.BacktestBrokerrejects orders for tickers absent from the current bar set, logged as a rejected-order count on the report rather than thrown.
Testing
Vitest unit tests cover Portfolio fill isolation, the BacktestEngine loop
against a fake in-memory feed, metrics calculations against hand-computed values, and
an integration test running both example strategies concurrently to confirm
independent, non-interfering reports.
Next phases
- IBKR paper broker + IBKR historical/live data adapter
- Docker packaging (IB Gateway container + engine container)
- npm publish
- Risk manager overlay
- Expand strategy library toward the full 55-strategy set
Full Vision (end-state blueprint)
Everything below describes where the framework is headed once every phase lands — kept here as the reference blueprint, none of it exists today.
Core Principles
- Write Once, Run Anywhere — zero code changes switching between backtest, paper, live
- Multi-Strategy Parallelism — run dozens of strategies concurrently on different symbols/timeframes
- Zero-Dependency Deployment — self-contained Docker images for Proxmox, AWS, Raspberry Pi, or local
- Developer-First — TypeScript-native, fully typed, powerful CLI, modular architecture
Planned Features
🎯 marks planned/end-state features — none of these are implemented yet (see the build checklist above for what's actually in progress).
- 🎯 3 execution modes: Backtest, Paper, Live
- 🎯 Parallel strategy execution with isolated per-strategy state
- 🎯 Native IBKR integration (
@stoqey/ibkr) with auto-reconnect and IBC auto-login - 🎯 High-performance streaming data layer (Parquet for backtest, WebSocket for live)
- 🎯 Comprehensive metrics: Sharpe, Sortino, Calmar, Win Rate, Max Drawdown, Exposure, Equity Curve
- 🎯 Portfolio-level risk management via sub-portfolios
- 🎯 Docker-first universal deployment
- 🎯 Extensible CLI:
hurst init,hurst backtest,hurst run,hurst list
End-state architecture
flowchart TB
CLI["CLI / Programmatic API"]
MGR["Strategy Manager\n(multi-strategy lifecycle & routing)"]
subgraph runners["Runner Layer"]
direction LR
BR["Backtest Runner"]
PR["Paper Runner"]
LR2["Live Runner"]
end
subgraph core["Core Engine (Domain)"]
LOOP2["Engine Loop"] --> OM["Order Manager"] --> RM["Risk Manager"] --> PORT2["Portfolio"]
end
subgraph ports2["Ports (interfaces)"]
IDF2["IDataFeed"]
IBR2["IBroker"]
end
subgraph adapters2["Adapters"]
CSVA["CSVAdapter"]
PARQA["ParquetAdapter"]
IBKRA["IBKRDataAdapter"]
BTB2["BacktestBroker"]
PAPB2["PaperBroker"]
IBB2["IBBroker (live)"]
end
subgraph infra["External Infrastructure"]
FILES["CSV / Parquet files"]
GATE["IBKR Gateway (TWS / IBC)"]
end
CLI --> MGR --> runners --> core
core --> ports2
IDF2 --- CSVA & PARQA & IBKRA
IBR2 --- BTB2 & PAPB2 & IBB2
CSVA & PARQA --> FILES
IBKRA & IBB2 & PAPB2 --> GATEDocker deployment
flowchart LR
subgraph host["Any host — Proxmox / AWS / RPi / local"]
subgraph gw["ib-gateway container"]
IBC["IBC (auto-login, 2FA handling)"]
TWS["IB Gateway"]
end
subgraph eng["hurst-engine container"]
HE["Hurst CLI\n(backtest / paper / live)"]
end
HE -->|"port 4002"| TWS
end
IBKR_CLOUD["IBKR"] <--> TWSCLI (end state)
hurst init my-bot # scaffold a new project
hurst backtest --strategy ./strategies/sma-cross.ts \
--symbol AAPL --from 2024-01-01 --to 2024-12-31 # backtest
hurst run --mode paper --strategy ./strategies/mean-revert.ts # paper trade
hurst run --mode live --strategy ./strategies/hurst-trend.ts # live trade
hurst list # running strategies/statusDeployment (end state)
git clone https://github.com/iso-nord-ca/hurst-framework
cd hurst-framework
cp .env.example .env # add IBKR credentials
docker-compose -f docker/docker-compose.yml up -d
docker logs -f hurst-engineMetrics output shape
{
"totalReturn": 24.5,
"annualizedReturn": 18.3,
"sharpeRatio": 1.42,
"sortinoRatio": 2.1,
"maxDrawdown": -12.4,
"winRate": 62.5,
"totalTrades": 145,
"avgTrade": 0.18,
"exposure": 0.72,
"equityCurve": [100000, 100500, 101200]
}The "Hurst" indicator
Named after the Hurst Exponent — a rescaled-range (R/S) regime detector: H > 0.5
trending, H < 0.5 mean-reverting. Planned as a built-in indicator once the strategy
library expands beyond the Phase 1 examples.
Coming Soon
Planned features beyond the phases above — none decided as final except where noted:
- Multi-broker support (planned) — the
IBrokerport already abstracts execution away from any single vendor (that's the point of the ports & adapters design), so adding a broker will be a new adapter, not an engine change. IBKR is the first adapter being built. A SnapTrade adapter is planned as a way to trade through whichever brokerage you already have credentials for (Alpaca, Robinhood, TD/Schwab, Questrade, and others SnapTrade supports) instead of being locked into IBKR alone — not yet finalized as the specific integration, but the leading candidate. - Risk manager overlay (volatility targeting, drawdown gates, correlation monitoring)
- Expansion of the strategy library toward the full 55-strategy set
- Docker packaging and npm publish
- Web dashboard for live monitoring of running strategies
CONTRIBUTING.md,SECURITY.md, and a dedicateddocs/roadmap.mdas the project grows past a single spec file
License
Proprietary Software — Copyright © 2026 Théodore Beaupré, operating as ISO NORD CA. All rights reserved.
This repository is made available for limited viewing and evaluation only. It is not open source. No permission is granted to use, copy, modify, distribute, deploy, sell, sublicense, reverse engineer, scrape, or use this repository for artificial-intelligence or machine-learning training except where expressly authorized in writing by ISO NORD CA or unavoidably permitted by applicable law. Public GitHub repositories remain subject to GitHub's Terms of Service, including GitHub's platform-level viewing and forking permissions.
Commercial and other licensing requests: [email protected]
Full terms: LICENSE.
