tradelab 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/README.md +185 -388
- package/dist/cjs/index.cjs +31 -9
- package/dist/cjs/live.cjs +409 -7
- package/docs/README.md +32 -66
- package/docs/api-reference.md +269 -144
- package/docs/backtest-engine.md +167 -321
- package/docs/data-reporting-cli.md +114 -156
- package/docs/examples.md +6 -6
- package/docs/live-trading.md +254 -134
- package/docs/mcp.md +244 -23
- package/docs/research.md +99 -45
- package/examples/mcpLiveTrading.js +77 -0
- package/package.json +11 -3
- package/src/engine/optimize.js +25 -1
- package/src/engine/portfolio.js +4 -1
- package/src/live/dashboard/server.js +67 -8
- package/src/live/engine/paperEngine.js +5 -0
- package/src/live/index.js +2 -0
- package/src/live/session.js +402 -0
- package/src/mcp/liveTools.js +179 -0
- package/src/mcp/schemas.js +119 -0
- package/src/mcp/server.js +5 -1
- package/src/mcp/tools.js +125 -2
- package/templates/dashboard.html +595 -108
- package/types/index.d.ts +25 -0
- package/types/live.d.ts +99 -0
- package/types/mcp.d.ts +17 -0
- package/docs/superpowers/plans/2026-00-overview.md +0 -101
- package/docs/superpowers/plans/2026-01-metrics-correctness.md +0 -873
- package/docs/superpowers/plans/2026-02-indicator-library.md +0 -677
- package/docs/superpowers/plans/2026-03-overfitting-toolkit.md +0 -882
- package/docs/superpowers/plans/2026-04-async-signals-seeding.md +0 -981
- package/docs/superpowers/plans/2026-05-mcp-server.md +0 -758
- package/docs/superpowers/plans/2026-06-parallel-param-sweep.md +0 -508
- package/docs/superpowers/plans/2026-07-funding-carry-costs.md +0 -535
- package/docs/superpowers/plans/2026-08-live-dashboard.md +0 -547
- package/docs/superpowers/plans/HANDOFF.md +0 -88
package/README.md
CHANGED
|
@@ -1,317 +1,229 @@
|
|
|
1
|
-
|
|
2
|
-
<img src="https://i.imgur.com/HGvvQbq.png" width="420" alt="tradelab logo" />
|
|
1
|
+
# tradelab
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
A Node.js toolkit for testing, validating, and operating trading strategies.
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
[](https://github.com/ishsharm0/tradelab)
|
|
8
|
-
[](https://github.com/ishsharm0/tradelab/blob/main/LICENSE)
|
|
9
|
-
[](https://nodejs.org)
|
|
10
|
-
[](https://github.com/ishsharm0/tradelab/blob/main/types/index.d.ts)
|
|
5
|
+
tradelab gives you one `signal()` contract across research and execution:
|
|
11
6
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
AI-agent users: see [docs/mcp.md](docs/mcp.md) to run the research loop via MCP.
|
|
7
|
+
- run candle or tick backtests
|
|
8
|
+
- model slippage, commissions, borrow, carry, and funding
|
|
9
|
+
- validate parameters with walk-forward tests and research statistics
|
|
10
|
+
- combine multiple systems into a shared-capital portfolio
|
|
11
|
+
- move the same strategy into paper or live execution
|
|
12
|
+
- export reports, metrics, and trade ledgers
|
|
13
|
+
- expose research tools through an MCP server
|
|
21
14
|
|
|
22
15
|
```bash
|
|
23
16
|
npm install tradelab
|
|
24
17
|
```
|
|
25
18
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
##
|
|
29
|
-
|
|
30
|
-
- [What it includes](#what-it-includes)
|
|
31
|
-
- [Quick start](#quick-start)
|
|
32
|
-
- [Loading historical data](#loading-historical-data)
|
|
33
|
-
- [Core concepts](#core-concepts)
|
|
34
|
-
- [AI agents / MCP](#ai-agents--mcp)
|
|
35
|
-
- [Portfolio mode](#portfolio-mode)
|
|
36
|
-
- [Walk-forward optimization](#walk-forward-optimization)
|
|
37
|
-
- [Tick backtests](#tick-backtests)
|
|
38
|
-
- [Live trading](#live-trading)
|
|
39
|
-
- [Execution and cost modeling](#execution-and-cost-modeling)
|
|
40
|
-
- [Exports and reporting](#exports-and-reporting)
|
|
41
|
-
- [CLI](#cli)
|
|
42
|
-
- [Examples](#examples)
|
|
43
|
-
- [Documentation](#documentation)
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## What it includes
|
|
48
|
-
|
|
49
|
-
| Area | What you get |
|
|
50
|
-
| -------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
51
|
-
| **Engine** | Candle and tick backtests with position sizing, exits, replay capture, and cost models |
|
|
52
|
-
| **Async / AI signals** | Promise-returning signals, `LlmSignal` caching/budgets, and live async signal support |
|
|
53
|
-
| **Indicators (`ta`)** | RSI, MACD, stochastic, Bollinger, Donchian, Keltner, Supertrend, VWAP, EMA, ATR, swing/FVG helpers |
|
|
54
|
-
| **Optimization** | `optimize()` worker-pool parameter sweep and `grid()` spec helper |
|
|
55
|
-
| **Portfolio** | Multi-system shared-capital simulation with live capital locking and daily loss halts |
|
|
56
|
-
| **Walk-forward** | Rolling and anchored train/test validation with parameter search and stability summaries |
|
|
57
|
-
| **Research / overfitting** | Monte Carlo, deflated Sharpe, sweep haircut, PBO (CSCV), and CPCV combinatorial purging |
|
|
58
|
-
| **AI / MCP server** | `tradelab-mcp` stdio server — run the research loop from Claude Desktop, Cursor, or any MCP agent |
|
|
59
|
-
| **Live execution** | Live and paper engines with broker adapters, state persistence, orchestration, and SSE dashboard |
|
|
60
|
-
| **Data** | Yahoo Finance downloads, CSV import, and local cache helpers |
|
|
61
|
-
| **Costs** | Slippage, spread, commission, annualized carry/borrow, and perpetual futures funding |
|
|
62
|
-
| **Exports** | HTML reports, metrics JSON, and trade CSV |
|
|
63
|
-
| **Dev experience** | TypeScript definitions, ESM/CJS support, CLI for quick runs |
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
## Quick start
|
|
68
|
-
|
|
69
|
-
If you already have candles, `backtest()` is the main entry point.
|
|
19
|
+
Requires Node.js 18 or newer.
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
70
22
|
|
|
71
23
|
```js
|
|
72
|
-
import { backtest, ema, exportBacktestArtifacts } from "tradelab";
|
|
24
|
+
import { backtest, getHistoricalCandles, ema, exportBacktestArtifacts } from "tradelab";
|
|
25
|
+
|
|
26
|
+
const candles = await getHistoricalCandles({
|
|
27
|
+
source: "yahoo",
|
|
28
|
+
symbol: "SPY",
|
|
29
|
+
interval: "1d",
|
|
30
|
+
period: "2y",
|
|
31
|
+
cache: true,
|
|
32
|
+
});
|
|
73
33
|
|
|
74
34
|
const result = backtest({
|
|
75
35
|
candles,
|
|
76
|
-
symbol: "
|
|
77
|
-
interval: "
|
|
78
|
-
range: "60d",
|
|
36
|
+
symbol: "SPY",
|
|
37
|
+
interval: "1d",
|
|
79
38
|
equity: 10_000,
|
|
80
39
|
riskPct: 1,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
40
|
+
warmupBars: 50,
|
|
41
|
+
costs: {
|
|
42
|
+
slippageBps: 1,
|
|
43
|
+
commissionBps: 0.5,
|
|
44
|
+
},
|
|
45
|
+
signal({ candles: history, bar }) {
|
|
46
|
+
const closes = history.map((c) => c.close);
|
|
85
47
|
const fast = ema(closes, 10);
|
|
86
48
|
const slow = ema(closes, 30);
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
if (fast[last - 1] <= slow[last - 1] && fast[last] > slow[last]) {
|
|
90
|
-
const entry = history[last].close;
|
|
91
|
-
const stop = Math.min(...history.slice(-15).map((bar) => bar.low));
|
|
92
|
-
const risk = entry - stop;
|
|
93
|
-
if (risk <= 0) return null;
|
|
49
|
+
const i = closes.length - 1;
|
|
94
50
|
|
|
95
|
-
|
|
51
|
+
if (fast[i - 1] <= slow[i - 1] && fast[i] > slow[i]) {
|
|
52
|
+
return { side: "long", stop: bar.close * 0.97, rr: 2 };
|
|
96
53
|
}
|
|
97
54
|
|
|
98
55
|
return null;
|
|
99
56
|
},
|
|
100
57
|
});
|
|
101
58
|
|
|
59
|
+
console.log(result.metrics);
|
|
102
60
|
exportBacktestArtifacts({ result, outDir: "./output" });
|
|
103
61
|
```
|
|
104
62
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
## AI agents / MCP
|
|
110
|
-
|
|
111
|
-
`tradelab-mcp` lets MCP-capable agents run the research loop through tools: list strategies, fetch candles, run backtests, and walk-forward validate parameter grids.
|
|
63
|
+
Start with `result.metrics` for the summary and `result.positions` for completed trades. Use `trades` when you need every realized leg, including partial exits.
|
|
112
64
|
|
|
113
|
-
|
|
65
|
+
## What You Can Build
|
|
114
66
|
|
|
115
|
-
|
|
67
|
+
| Goal | API or command |
|
|
68
|
+
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|
69
|
+
| Backtest one strategy | `backtest({ candles, signal })` |
|
|
70
|
+
| Backtest an async strategy | `backtestAsync({ candles, signal })` |
|
|
71
|
+
| Replay tick or quote data | `backtestTicks({ ticks, signal })` |
|
|
72
|
+
| Run several systems together | `backtestPortfolio({ systems })` |
|
|
73
|
+
| Test parameter stability | `walkForwardOptimize(options)` |
|
|
74
|
+
| Run a parallel parameter sweep | `optimize({ signalModulePath, parameterSets })` |
|
|
75
|
+
| Use indicators | `import { rsi, macd, vwap } from "tradelab/ta"` |
|
|
76
|
+
| Check overfitting risk | `research.monteCarlo`, `research.deflatedSharpe` |
|
|
77
|
+
| Run in paper or live mode | `LiveEngine`, `LiveOrchestrator`, `tradelab paper` |
|
|
78
|
+
| Watch a live run locally | `createDashboardServer({ source })` — equity curve, KPI strip, controls |
|
|
79
|
+
| Let MCP clients run research tools | `tradelab-mcp` — `run_backtest`, `walk_forward`, `analyze_robustness`, `optimize_strategy`, `compare_strategies`, `candle_stats` |
|
|
80
|
+
| Let MCP agents trade (paper/live) | `tradelab-mcp` — `create_session`, `feed_price`, `place_order`, bracket orders, `halt_all` kill-switch (see [docs/mcp.md](docs/mcp.md)) |
|
|
81
|
+
| Export reports and machine data | `exportBacktestArtifacts`, `exportMetricsJSON` |
|
|
116
82
|
|
|
117
|
-
##
|
|
83
|
+
## The Signal Contract
|
|
118
84
|
|
|
119
|
-
|
|
85
|
+
Your strategy is a function. Return `null` to do nothing, or return a trade signal.
|
|
120
86
|
|
|
121
87
|
```js
|
|
122
|
-
|
|
88
|
+
function signal({ candles, index, bar, equity, openPosition, pendingOrder }) {
|
|
89
|
+
if (openPosition || index < 50) return null;
|
|
123
90
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const result = backtest({ candles, symbol: "SPY", interval: "1d", range: "2y", signal });
|
|
91
|
+
return {
|
|
92
|
+
side: "long",
|
|
93
|
+
entry: bar.close, // optional; defaults to current close
|
|
94
|
+
stop: bar.close - 2,
|
|
95
|
+
rr: 2, // take profit at 2R
|
|
96
|
+
};
|
|
97
|
+
}
|
|
133
98
|
```
|
|
134
99
|
|
|
135
|
-
|
|
100
|
+
Common signal fields:
|
|
136
101
|
|
|
137
|
-
|
|
102
|
+
| Field | Meaning |
|
|
103
|
+
| --------------------------- | --------------------------------------------------- |
|
|
104
|
+
| `side` | `long`, `short`, `buy`, or `sell` |
|
|
105
|
+
| `entry` | Entry price. Defaults to the current close |
|
|
106
|
+
| `stop` | Required stop level for sizing and risk |
|
|
107
|
+
| `takeProfit` | Explicit target price |
|
|
108
|
+
| `rr` | Builds target from risk when `takeProfit` is absent |
|
|
109
|
+
| `qty` or `size` | Fixed size override |
|
|
110
|
+
| `riskPct` or `riskFraction` | Per-trade risk override |
|
|
138
111
|
|
|
139
|
-
|
|
112
|
+
## Data
|
|
140
113
|
|
|
141
|
-
|
|
114
|
+
Use `getHistoricalCandles()` for Yahoo Finance, CSV files, and cached datasets.
|
|
142
115
|
|
|
143
116
|
```js
|
|
144
|
-
const
|
|
145
|
-
source: "
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
// ... optional column mapping
|
|
151
|
-
},
|
|
117
|
+
const yahoo = await getHistoricalCandles({
|
|
118
|
+
source: "yahoo",
|
|
119
|
+
symbol: "QQQ",
|
|
120
|
+
interval: "1d",
|
|
121
|
+
period: "1y",
|
|
122
|
+
cache: true,
|
|
152
123
|
});
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
If your CSV already uses standard OHLCV column names, no mapping is needed at all.
|
|
156
|
-
|
|
157
|
-
---
|
|
158
|
-
|
|
159
|
-
## Core concepts
|
|
160
124
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
```js
|
|
166
|
-
signal({ candles, index, bar, equity, openPosition, pendingOrder }) {
|
|
167
|
-
// return null to skip
|
|
168
|
-
// return a signal to enter
|
|
169
|
-
return {
|
|
170
|
-
side: "long", // "long" | "short" | "buy" | "sell"
|
|
171
|
-
entry: bar.close, // defaults to current close if omitted
|
|
172
|
-
stop: bar.close - 2,
|
|
173
|
-
rr: 2, // target = entry + (entry - stop) * rr
|
|
174
|
-
};
|
|
175
|
-
}
|
|
125
|
+
const csv = await getHistoricalCandles({
|
|
126
|
+
source: "csv",
|
|
127
|
+
csvPath: "./data/btc.csv",
|
|
128
|
+
});
|
|
176
129
|
```
|
|
177
130
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
### Key backtest options
|
|
181
|
-
|
|
182
|
-
| Option | Purpose |
|
|
183
|
-
| ----------------- | -------------------------------------------- |
|
|
184
|
-
| `equity` | Starting equity (default `10000`) |
|
|
185
|
-
| `riskPct` | Percent of equity risked per trade |
|
|
186
|
-
| `warmupBars` | Bars skipped before signal evaluation starts |
|
|
187
|
-
| `flattenAtClose` | Forces end-of-day exit when enabled |
|
|
188
|
-
| `costs` | Slippage, spread, and commission model |
|
|
189
|
-
| `strict` | Throws on lookahead access |
|
|
190
|
-
| `collectEqSeries` | Enables equity curve output |
|
|
191
|
-
| `collectReplay` | Enables visualization payload |
|
|
192
|
-
|
|
193
|
-
### Result shape
|
|
131
|
+
Candles are normalized to:
|
|
194
132
|
|
|
195
133
|
```js
|
|
196
134
|
{
|
|
197
|
-
|
|
198
|
-
trades, // every realized leg, including partial exits
|
|
199
|
-
positions, // completed positions - start here for analysis
|
|
200
|
-
metrics, // winRate, profitFactor, maxDrawdown, sharpe, ...
|
|
201
|
-
eqSeries, // [{ time, timestamp, equity }] - equity curve
|
|
202
|
-
replay, // visualization frames and events
|
|
135
|
+
(time, open, high, low, close, volume);
|
|
203
136
|
}
|
|
204
137
|
```
|
|
205
138
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
- `metrics.trades` - enough sample size to trust the numbers?
|
|
209
|
-
- `metrics.profitFactor` - do winners beat losers gross of costs?
|
|
210
|
-
- `metrics.maxDrawdown` - is the equity path survivable?
|
|
211
|
-
- `metrics.sideBreakdown` - does one side carry the whole result?
|
|
212
|
-
|
|
213
|
-
---
|
|
139
|
+
## Costs
|
|
214
140
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
Use `backtestPortfolio()` when you have one candle array per symbol and want a single combined result.
|
|
141
|
+
Cost assumptions belong in the run, not in post-processing.
|
|
218
142
|
|
|
219
143
|
```js
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
144
|
+
const result = backtest({
|
|
145
|
+
candles,
|
|
146
|
+
signal,
|
|
147
|
+
costs: {
|
|
148
|
+
slippageBps: 2,
|
|
149
|
+
spreadBps: 1,
|
|
150
|
+
commissionBps: 1,
|
|
151
|
+
minCommission: 1,
|
|
152
|
+
carry: {
|
|
153
|
+
longAnnualBps: 500,
|
|
154
|
+
shortAnnualBps: 800,
|
|
155
|
+
},
|
|
156
|
+
funding: {
|
|
157
|
+
rateBps: 10,
|
|
158
|
+
intervalMs: 8 * 60 * 60 * 1000,
|
|
159
|
+
anchorMs: 0,
|
|
160
|
+
},
|
|
161
|
+
},
|
|
228
162
|
});
|
|
229
163
|
```
|
|
230
164
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
---
|
|
165
|
+
`exit.financing` is included on closed trades when carry or funding applies. It is already deducted from `exit.pnl` and aggregate metrics.
|
|
234
166
|
|
|
235
|
-
##
|
|
167
|
+
## Validation
|
|
236
168
|
|
|
237
|
-
Use
|
|
169
|
+
Use a normal backtest to build the strategy. Use validation tools before trusting it.
|
|
238
170
|
|
|
239
171
|
```js
|
|
240
|
-
import { walkForwardOptimize } from "tradelab";
|
|
172
|
+
import { walkForwardOptimize, grid } from "tradelab";
|
|
241
173
|
|
|
242
174
|
const wf = walkForwardOptimize({
|
|
243
175
|
candles,
|
|
244
|
-
mode: "anchored",
|
|
245
176
|
trainBars: 180,
|
|
246
177
|
testBars: 60,
|
|
247
|
-
|
|
178
|
+
mode: "anchored",
|
|
248
179
|
scoreBy: "profitFactor",
|
|
249
|
-
parameterSets:
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
180
|
+
parameterSets: grid({
|
|
181
|
+
fast: [8, 10, 12],
|
|
182
|
+
slow: [21, 30, 50],
|
|
183
|
+
rr: [1.5, 2, 3],
|
|
184
|
+
}),
|
|
253
185
|
signalFactory(params) {
|
|
254
|
-
return
|
|
186
|
+
return createEmaSignal(params);
|
|
255
187
|
},
|
|
256
188
|
});
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
Each window picks the best parameter set in training, then runs it blind on the test slice. The `windows` array now includes out-of-sample trade count, profitability, and a per-window stability score. `bestParamsSummary` reports how stable the winners were across the full run.
|
|
260
|
-
|
|
261
|
-
---
|
|
262
189
|
|
|
263
|
-
|
|
190
|
+
console.log(wf.metrics);
|
|
191
|
+
console.log(wf.bestParamsSummary);
|
|
192
|
+
```
|
|
264
193
|
|
|
265
|
-
|
|
194
|
+
For larger sweeps, use `optimize()` with a strategy module:
|
|
266
195
|
|
|
267
196
|
```js
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
signal,
|
|
197
|
+
const out = await optimize({
|
|
198
|
+
candles,
|
|
199
|
+
interval: "1d",
|
|
200
|
+
signalModulePath: new URL("./strategy.js", import.meta.url).pathname,
|
|
201
|
+
parameterSets: grid({ fast: [8, 10], slow: [30, 50] }),
|
|
202
|
+
scoreBy: "sharpeAnnualized",
|
|
275
203
|
});
|
|
276
204
|
```
|
|
277
205
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
Use `seed` to make probabilistic limit fills reproducible across repeated runs with the same data and options.
|
|
206
|
+
## Portfolio Backtests
|
|
281
207
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
Use `backtestAsync()` when your signal returns a promise. `LlmSignal` wraps async model or agent calls with a per-bar budget, one-decision-per-bar cache, no-lookahead candle view, and a decision log.
|
|
208
|
+
`backtestPortfolio()` runs multiple systems against shared capital. Capital is locked only when an order fills, so later systems size against what is still available.
|
|
285
209
|
|
|
286
210
|
```js
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
211
|
+
const portfolio = backtestPortfolio({
|
|
212
|
+
equity: 100_000,
|
|
213
|
+
interval: "1d",
|
|
214
|
+
maxDailyLossPct: 3,
|
|
215
|
+
systems: [
|
|
216
|
+
{ symbol: "SPY", candles: spy, signal: spySignal, weight: 2 },
|
|
217
|
+
{ symbol: "QQQ", candles: qqq, signal: qqqSignal, weight: 1 },
|
|
218
|
+
],
|
|
295
219
|
});
|
|
296
|
-
|
|
297
|
-
const result = await backtestAsync({ candles, signal: llm.signal, signalBudgetMs: 3000 });
|
|
298
220
|
```
|
|
299
221
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
---
|
|
303
|
-
|
|
304
|
-
## Live trading
|
|
222
|
+
Portfolio equity points include `lockedCapital` and `availableCapital`.
|
|
305
223
|
|
|
306
|
-
|
|
224
|
+
## Live and Paper Runs
|
|
307
225
|
|
|
308
|
-
|
|
309
|
-
- `LiveOrchestrator` for multi-system execution with shared broker state
|
|
310
|
-
- `PaperEngine` implementing the broker interface for deterministic simulation
|
|
311
|
-
- broker adapters for Alpaca, Binance, Coinbase, and Interactive Brokers
|
|
312
|
-
- JSON state/trade/equity persistence via `JsonFileStorage`
|
|
313
|
-
|
|
314
|
-
Use the same signal contract from backtesting in live mode:
|
|
226
|
+
The live package uses the same signal shape as backtests.
|
|
315
227
|
|
|
316
228
|
```js
|
|
317
229
|
import { LiveEngine, PaperEngine, JsonFileStorage } from "tradelab/live";
|
|
@@ -320,196 +232,81 @@ const engine = new LiveEngine({
|
|
|
320
232
|
id: "aapl-1m",
|
|
321
233
|
symbol: "AAPL",
|
|
322
234
|
interval: "1m",
|
|
235
|
+
mode: "polling",
|
|
323
236
|
broker: new PaperEngine({ equity: 25_000 }),
|
|
324
237
|
storage: new JsonFileStorage({ baseDir: "./output/live-state" }),
|
|
325
|
-
signal
|
|
326
|
-
if (openPosition) return null;
|
|
327
|
-
return { side: "long", stop: bar.close - 1, rr: 2 };
|
|
328
|
-
},
|
|
238
|
+
signal,
|
|
329
239
|
});
|
|
330
240
|
|
|
331
241
|
await engine.start();
|
|
332
242
|
```
|
|
333
243
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
---
|
|
337
|
-
|
|
338
|
-
## Execution and cost modeling
|
|
244
|
+
Run the same flow from the terminal:
|
|
339
245
|
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
signal,
|
|
344
|
-
costs: {
|
|
345
|
-
slippageBps: 2,
|
|
346
|
-
spreadBps: 1,
|
|
347
|
-
slippageByKind: {
|
|
348
|
-
market: 3,
|
|
349
|
-
limit: 0.5,
|
|
350
|
-
stop: 4,
|
|
351
|
-
},
|
|
352
|
-
commissionBps: 1,
|
|
353
|
-
commissionPerUnit: 0,
|
|
354
|
-
commissionPerOrder: 1,
|
|
355
|
-
minCommission: 1,
|
|
356
|
-
carry: {
|
|
357
|
-
longAnnualBps: 500,
|
|
358
|
-
shortAnnualBps: 800,
|
|
359
|
-
},
|
|
360
|
-
funding: {
|
|
361
|
-
rateBps: 10,
|
|
362
|
-
intervalMs: 8 * 60 * 60 * 1000,
|
|
363
|
-
anchorMs: 0,
|
|
364
|
-
},
|
|
365
|
-
},
|
|
366
|
-
});
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
- Slippage is applied in the trade direction
|
|
370
|
-
- Spread is modeled as half-spread paid on entry and exit
|
|
371
|
-
- Commission can be percentage-based, per-unit, per-order, or mixed
|
|
372
|
-
- `minCommission` floors the fee per fill
|
|
373
|
-
- `carry` models annualized overnight financing or borrow costs
|
|
374
|
-
- `funding` models per-interval perpetual futures funding; positive rates charge longs and credit shorts
|
|
375
|
-
- Closed trades include `exit.financing`, already deducted from `exit.pnl`
|
|
376
|
-
|
|
377
|
-
> Leaving costs at zero is the most common cause of inflated backtests. Set them from the start.
|
|
378
|
-
|
|
379
|
-
---
|
|
380
|
-
|
|
381
|
-
## Exports and reporting
|
|
382
|
-
|
|
383
|
-
```js
|
|
384
|
-
import { exportBacktestArtifacts } from "tradelab";
|
|
385
|
-
|
|
386
|
-
// Writes HTML report + trade CSV + metrics JSON in one call
|
|
387
|
-
exportBacktestArtifacts({ result, outDir: "./output" });
|
|
246
|
+
```bash
|
|
247
|
+
tradelab paper --symbol AAPL --interval 1m --mode polling --once true
|
|
248
|
+
tradelab live --config ./live-portfolio.json --paper
|
|
388
249
|
```
|
|
389
250
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
| Helper | Output |
|
|
393
|
-
| ---------------------------------- | ----------------------------------------------------- |
|
|
394
|
-
| `exportHtmlReport(options)` | Interactive HTML report written to disk |
|
|
395
|
-
| `renderHtmlReport(options)` | HTML report returned as a string |
|
|
396
|
-
| `exportTradesCsv(trades, options)` | Flat trade ledger for spreadsheets or pandas |
|
|
397
|
-
| `exportMetricsJSON(options)` | Machine-readable metrics for dashboards or automation |
|
|
398
|
-
|
|
399
|
-
For programmatic pipelines, `exportMetricsJSON` is usually the most useful format to build on.
|
|
400
|
-
|
|
401
|
-
---
|
|
402
|
-
|
|
403
|
-
## CLI
|
|
404
|
-
|
|
405
|
-
The package ships a `tradelab` binary. Best for quick iteration, smoke tests, and trying the package before wiring it into application code.
|
|
251
|
+
Add `--dashboard --dashboardPort 4317` to open a local Server-Sent Events dashboard.
|
|
406
252
|
|
|
407
|
-
|
|
408
|
-
# Backtest from Yahoo
|
|
409
|
-
npx tradelab backtest --source yahoo --symbol SPY --interval 1d --period 1y
|
|
410
|
-
|
|
411
|
-
# Backtest from CSV with a built-in strategy
|
|
412
|
-
npx tradelab backtest --source csv --csvPath ./data/btc.csv --strategy buy-hold --holdBars 3
|
|
253
|
+
## MCP Server
|
|
413
254
|
|
|
414
|
-
|
|
415
|
-
npx tradelab portfolio \
|
|
416
|
-
--csvPaths ./data/spy.csv,./data/qqq.csv \
|
|
417
|
-
--symbols SPY,QQQ \
|
|
418
|
-
--strategy buy-hold
|
|
255
|
+
`tradelab-mcp` exposes research and live-trading tools over stdio to any MCP-capable agent (Claude Desktop, Cursor, etc.). See [docs/mcp.md](docs/mcp.md) for the full tool reference and agent trading guide.
|
|
419
256
|
|
|
420
|
-
|
|
421
|
-
npx tradelab walk-forward \
|
|
422
|
-
--source yahoo --symbol QQQ --interval 1d --period 2y \
|
|
423
|
-
--trainBars 180 --testBars 60 --mode anchored
|
|
257
|
+
**Research tools:** `list_strategies`, `fetch_candles`, `run_backtest`, `walk_forward`, `analyze_robustness`, `optimize_strategy`, `compare_strategies`, `candle_stats`
|
|
424
258
|
|
|
425
|
-
|
|
426
|
-
npx tradelab paper --symbol AAPL --interval 1m --mode polling --once true
|
|
259
|
+
**Agent trading tools (paper by default; live gated):** `create_session`, `list_sessions`, `session_status`, `feed_price`, `place_order`, `close_position`, `flatten`, `cancel_order`, `account`, `positions`, `recent_events`, `attach_strategy`, `halt_all`
|
|
427
260
|
|
|
428
|
-
|
|
429
|
-
npx tradelab live --config ./live-portfolio.json --paper --mode polling --once true
|
|
261
|
+
Paper trading needs no credentials. Live trading requires `TRADELAB_ALLOW_LIVE=true` and `confirmLive: true` plus a credentialed broker. `halt_all` is an emergency kill-switch that flattens all positions and stops every session.
|
|
430
262
|
|
|
431
|
-
|
|
432
|
-
npx tradelab status --dir ./output/live-state
|
|
263
|
+
Use it from any MCP client that can launch a stdio server:
|
|
433
264
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
265
|
+
```json
|
|
266
|
+
{
|
|
267
|
+
"mcpServers": {
|
|
268
|
+
"tradelab": {
|
|
269
|
+
"command": "npx",
|
|
270
|
+
"args": ["-y", "tradelab", "tradelab-mcp"]
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
437
274
|
```
|
|
438
275
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
You can also point `--strategy` at a local module that exports `default(args)`, `createSignal(args)`, or `signal` for `backtest`, or `signalFactory(params, args)` plus `parameterSets`/`createParameterSets(args)` for `walk-forward`.
|
|
442
|
-
|
|
443
|
-
---
|
|
444
|
-
|
|
445
|
-
## Examples
|
|
276
|
+
## CLI
|
|
446
277
|
|
|
447
278
|
```bash
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
279
|
+
tradelab backtest --source yahoo --symbol SPY --interval 1d --period 1y
|
|
280
|
+
tradelab portfolio --csvPaths ./spy.csv,./qqq.csv --symbols SPY,QQQ
|
|
281
|
+
tradelab walk-forward --source yahoo --symbol QQQ --interval 1d --period 2y
|
|
282
|
+
tradelab status --dir ./output/live-state
|
|
451
283
|
```
|
|
452
284
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
---
|
|
285
|
+
## Documentation
|
|
456
286
|
|
|
457
|
-
|
|
287
|
+
- [Docs home](docs/README.md)
|
|
288
|
+
- [Backtesting](docs/backtest-engine.md)
|
|
289
|
+
- [Data, reporting, and CLI](docs/data-reporting-cli.md)
|
|
290
|
+
- [Live trading](docs/live-trading.md)
|
|
291
|
+
- [MCP server](docs/mcp.md)
|
|
292
|
+
- [Research tools](docs/research.md)
|
|
293
|
+
- [Strategy examples](docs/examples.md)
|
|
294
|
+
- [API reference](docs/api-reference.md)
|
|
458
295
|
|
|
459
|
-
|
|
296
|
+
## Module Entry Points
|
|
460
297
|
|
|
461
298
|
```js
|
|
462
|
-
import { backtest, getHistoricalCandles
|
|
463
|
-
import {
|
|
464
|
-
import {
|
|
465
|
-
import { fetchHistorical } from "tradelab/data";
|
|
466
|
-
import { LiveEngine, PaperEngine, createDashboardServer } from "tradelab/live";
|
|
467
|
-
import { rsi, macd, bollinger, vwap, supertrend } from "tradelab/ta";
|
|
468
|
-
import { createServer, startStdioServer } from "tradelab/mcp";
|
|
299
|
+
import { backtest, getHistoricalCandles } from "tradelab";
|
|
300
|
+
import { rsi, macd, vwap } from "tradelab/ta";
|
|
301
|
+
import { LiveEngine, PaperEngine, TradingSession, SessionManager } from "tradelab/live";
|
|
469
302
|
```
|
|
470
303
|
|
|
471
|
-
|
|
304
|
+
CommonJS is supported for the main, data, live, and TA entry points:
|
|
472
305
|
|
|
473
306
|
```js
|
|
474
|
-
const { backtest
|
|
475
|
-
const { backtestAsync, LlmSignal, optimize, grid } = require("tradelab");
|
|
476
|
-
const { research } = require("tradelab");
|
|
477
|
-
const { fetchHistorical } = require("tradelab/data");
|
|
478
|
-
const { LiveEngine, PaperEngine, createDashboardServer } = require("tradelab/live");
|
|
479
|
-
const { rsi, macd, bollinger, vwap, supertrend } = require("tradelab/ta");
|
|
307
|
+
const { backtest } = require("tradelab");
|
|
480
308
|
```
|
|
481
309
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
---
|
|
485
|
-
|
|
486
|
-
## Documentation
|
|
487
|
-
|
|
488
|
-
| Guide | What it covers |
|
|
489
|
-
| ------------------------------------------------------ | ------------------------------------------------------------------------------ |
|
|
490
|
-
| [Backtest engine](docs/backtest-engine.md) | Signal contract, all options, result shape, portfolio mode, walk-forward |
|
|
491
|
-
| [Data, reporting, and CLI](docs/data-reporting-cli.md) | Data loading, cache behavior, exports, CLI reference |
|
|
492
|
-
| [Live trading](docs/live-trading.md) | Live engine, broker adapters, paper mode, orchestration, and state persistence |
|
|
493
|
-
| [MCP server](docs/mcp.md) | Run the research loop from any MCP-capable agent |
|
|
494
|
-
| [Research & overfitting](docs/research.md) | Monte Carlo, deflated Sharpe, PBO, CPCV, sweep haircut |
|
|
495
|
-
| [Strategy examples](docs/examples.md) | Mean reversion, breakout, sentiment, LLM, and portfolio strategy patterns |
|
|
496
|
-
| [API reference](docs/api-reference.md) | Compact index of every public export |
|
|
497
|
-
|
|
498
|
-
---
|
|
499
|
-
|
|
500
|
-
## Common mistakes
|
|
501
|
-
|
|
502
|
-
- Using unsorted candles or mixed intervals in a single series
|
|
503
|
-
- Reading `trades` as if they were always full positions - use `positions` for top-line analysis
|
|
504
|
-
- Leaving costs at zero and overestimating edge
|
|
505
|
-
- Trusting one backtest without out-of-sample validation
|
|
506
|
-
- Debugging a strategy with `strict: false` when lookahead is possible
|
|
507
|
-
|
|
508
|
-
---
|
|
509
|
-
|
|
510
|
-
## Notes
|
|
310
|
+
## License
|
|
511
311
|
|
|
512
|
-
|
|
513
|
-
- Yahoo downloads are cached under `output/data` by default
|
|
514
|
-
- CommonJS and ESM are both supported
|
|
515
|
-
- Live adapters support broker execution workflows, but this is still not an exchange microstructure simulator
|
|
312
|
+
MIT
|