tradelab 1.1.0 → 1.2.1
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 +57 -0
- package/README.md +183 -373
- package/dist/cjs/index.cjs +39 -12
- package/dist/cjs/live.cjs +457 -18
- 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 +6 -2
- package/src/live/dashboard/server.js +67 -8
- package/src/live/engine/paperEngine.js +21 -11
- package/src/live/index.js +2 -0
- package/src/live/session.js +439 -0
- package/src/mcp/liveTools.js +202 -0
- package/src/mcp/schemas.js +119 -0
- package/src/mcp/server.js +5 -1
- package/src/mcp/tools.js +125 -2
- package/src/research/monteCarlo.js +6 -2
- package/templates/dashboard.html +595 -108
- package/types/index.d.ts +25 -0
- package/types/live.d.ts +102 -1
- 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
|
@@ -13,305 +13,230 @@
|
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
A Node.js toolkit for testing, validating, and operating trading strategies.
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
tradelab gives you one `signal()` contract across research and execution:
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
- run candle or tick backtests
|
|
21
|
+
- model slippage, commissions, borrow, carry, and funding
|
|
22
|
+
- validate parameters with walk-forward tests and research statistics
|
|
23
|
+
- combine multiple systems into a shared-capital portfolio
|
|
24
|
+
- move the same strategy into paper or live execution
|
|
25
|
+
- export reports, metrics, and trade ledgers
|
|
26
|
+
- expose research tools through an MCP server
|
|
21
27
|
|
|
22
28
|
```bash
|
|
23
29
|
npm install tradelab
|
|
24
30
|
```
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
## Table of contents
|
|
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
|
|
32
|
+
Requires Node.js 18 or newer.
|
|
68
33
|
|
|
69
|
-
|
|
34
|
+
## Quick Start
|
|
70
35
|
|
|
71
36
|
```js
|
|
72
|
-
import { backtest, ema, exportBacktestArtifacts } from "tradelab";
|
|
37
|
+
import { backtest, getHistoricalCandles, ema, exportBacktestArtifacts } from "tradelab";
|
|
38
|
+
|
|
39
|
+
const candles = await getHistoricalCandles({
|
|
40
|
+
source: "yahoo",
|
|
41
|
+
symbol: "SPY",
|
|
42
|
+
interval: "1d",
|
|
43
|
+
period: "2y",
|
|
44
|
+
cache: true,
|
|
45
|
+
});
|
|
73
46
|
|
|
74
47
|
const result = backtest({
|
|
75
48
|
candles,
|
|
76
|
-
symbol: "
|
|
77
|
-
interval: "
|
|
78
|
-
range: "60d",
|
|
49
|
+
symbol: "SPY",
|
|
50
|
+
interval: "1d",
|
|
79
51
|
equity: 10_000,
|
|
80
52
|
riskPct: 1,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
53
|
+
warmupBars: 50,
|
|
54
|
+
costs: {
|
|
55
|
+
slippageBps: 1,
|
|
56
|
+
commissionBps: 0.5,
|
|
57
|
+
},
|
|
58
|
+
signal({ candles: history, bar }) {
|
|
59
|
+
const closes = history.map((c) => c.close);
|
|
85
60
|
const fast = ema(closes, 10);
|
|
86
61
|
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;
|
|
62
|
+
const i = closes.length - 1;
|
|
94
63
|
|
|
95
|
-
|
|
64
|
+
if (fast[i - 1] <= slow[i - 1] && fast[i] > slow[i]) {
|
|
65
|
+
return { side: "long", stop: bar.close * 0.97, rr: 2 };
|
|
96
66
|
}
|
|
97
67
|
|
|
98
68
|
return null;
|
|
99
69
|
},
|
|
100
70
|
});
|
|
101
71
|
|
|
72
|
+
console.log(result.metrics);
|
|
102
73
|
exportBacktestArtifacts({ result, outDir: "./output" });
|
|
103
74
|
```
|
|
104
75
|
|
|
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.
|
|
76
|
+
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
77
|
|
|
113
|
-
|
|
78
|
+
## What You Can Build
|
|
114
79
|
|
|
115
|
-
|
|
80
|
+
| Goal | API or command |
|
|
81
|
+
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|
82
|
+
| Backtest one strategy | `backtest({ candles, signal })` |
|
|
83
|
+
| Backtest an async strategy | `backtestAsync({ candles, signal })` |
|
|
84
|
+
| Replay tick or quote data | `backtestTicks({ ticks, signal })` |
|
|
85
|
+
| Run several systems together | `backtestPortfolio({ systems })` |
|
|
86
|
+
| Test parameter stability | `walkForwardOptimize(options)` |
|
|
87
|
+
| Run a parallel parameter sweep | `optimize({ signalModulePath, parameterSets })` |
|
|
88
|
+
| Use indicators | `import { rsi, macd, vwap } from "tradelab/ta"` |
|
|
89
|
+
| Check overfitting risk | `research.monteCarlo`, `research.deflatedSharpe` |
|
|
90
|
+
| Run in paper or live mode | `LiveEngine`, `LiveOrchestrator`, `tradelab paper` |
|
|
91
|
+
| Watch a live run locally | `createDashboardServer({ source })` — equity curve, KPI strip, controls |
|
|
92
|
+
| Let MCP clients run research tools | `tradelab-mcp` — `run_backtest`, `walk_forward`, `analyze_robustness`, `optimize_strategy`, `compare_strategies`, `candle_stats` |
|
|
93
|
+
| 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)) |
|
|
94
|
+
| Export reports and machine data | `exportBacktestArtifacts`, `exportMetricsJSON` |
|
|
116
95
|
|
|
117
|
-
##
|
|
96
|
+
## The Signal Contract
|
|
118
97
|
|
|
119
|
-
|
|
98
|
+
Your strategy is a function. Return `null` to do nothing, or return a trade signal.
|
|
120
99
|
|
|
121
100
|
```js
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const candles = await getHistoricalCandles({
|
|
125
|
-
source: "yahoo",
|
|
126
|
-
symbol: "SPY",
|
|
127
|
-
interval: "1d",
|
|
128
|
-
period: "2y",
|
|
129
|
-
cache: true, // reuses local copy on repeated runs
|
|
130
|
-
});
|
|
101
|
+
function signal({ candles, index, bar, equity, openPosition, pendingOrder }) {
|
|
102
|
+
if (openPosition || index < 50) return null;
|
|
131
103
|
|
|
132
|
-
|
|
104
|
+
return {
|
|
105
|
+
side: "long",
|
|
106
|
+
entry: bar.close, // optional; defaults to current close
|
|
107
|
+
stop: bar.close - 2,
|
|
108
|
+
rr: 2, // take profit at 2R
|
|
109
|
+
};
|
|
110
|
+
}
|
|
133
111
|
```
|
|
134
112
|
|
|
135
|
-
|
|
113
|
+
Common signal fields:
|
|
136
114
|
|
|
137
|
-
|
|
115
|
+
| Field | Meaning |
|
|
116
|
+
| --------------------------- | --------------------------------------------------- |
|
|
117
|
+
| `side` | `long`, `short`, `buy`, or `sell` |
|
|
118
|
+
| `entry` | Entry price. Defaults to the current close |
|
|
119
|
+
| `stop` | Required stop level for sizing and risk |
|
|
120
|
+
| `takeProfit` | Explicit target price |
|
|
121
|
+
| `rr` | Builds target from risk when `takeProfit` is absent |
|
|
122
|
+
| `qty` or `size` | Fixed size override |
|
|
123
|
+
| `riskPct` or `riskFraction` | Per-trade risk override |
|
|
138
124
|
|
|
139
|
-
|
|
125
|
+
## Data
|
|
140
126
|
|
|
141
|
-
|
|
127
|
+
Use `getHistoricalCandles()` for Yahoo Finance, CSV files, and cached datasets.
|
|
142
128
|
|
|
143
129
|
```js
|
|
144
|
-
const
|
|
145
|
-
source: "
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
// ... optional column mapping
|
|
151
|
-
},
|
|
130
|
+
const yahoo = await getHistoricalCandles({
|
|
131
|
+
source: "yahoo",
|
|
132
|
+
symbol: "QQQ",
|
|
133
|
+
interval: "1d",
|
|
134
|
+
period: "1y",
|
|
135
|
+
cache: true,
|
|
152
136
|
});
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
If your CSV already uses standard OHLCV column names, no mapping is needed at all.
|
|
156
|
-
|
|
157
|
-
---
|
|
158
137
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
Your signal function is called on every bar. Return `null` to skip, or a signal object to open a trade.
|
|
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
|
-
}
|
|
138
|
+
const csv = await getHistoricalCandles({
|
|
139
|
+
source: "csv",
|
|
140
|
+
csvPath: "./data/btc.csv",
|
|
141
|
+
});
|
|
176
142
|
```
|
|
177
143
|
|
|
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
|
|
144
|
+
Candles are normalized to:
|
|
194
145
|
|
|
195
146
|
```js
|
|
196
147
|
{
|
|
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
|
|
148
|
+
(time, open, high, low, close, volume);
|
|
203
149
|
}
|
|
204
150
|
```
|
|
205
151
|
|
|
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
|
-
---
|
|
214
|
-
|
|
215
|
-
## Portfolio mode
|
|
152
|
+
## Costs
|
|
216
153
|
|
|
217
|
-
|
|
154
|
+
Cost assumptions belong in the run, not in post-processing.
|
|
218
155
|
|
|
219
156
|
```js
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
157
|
+
const result = backtest({
|
|
158
|
+
candles,
|
|
159
|
+
signal,
|
|
160
|
+
costs: {
|
|
161
|
+
slippageBps: 2,
|
|
162
|
+
spreadBps: 1,
|
|
163
|
+
commissionBps: 1,
|
|
164
|
+
minCommission: 1,
|
|
165
|
+
carry: {
|
|
166
|
+
longAnnualBps: 500,
|
|
167
|
+
shortAnnualBps: 800,
|
|
168
|
+
},
|
|
169
|
+
funding: {
|
|
170
|
+
rateBps: 10,
|
|
171
|
+
intervalMs: 8 * 60 * 60 * 1000,
|
|
172
|
+
anchorMs: 0,
|
|
173
|
+
},
|
|
174
|
+
},
|
|
228
175
|
});
|
|
229
176
|
```
|
|
230
177
|
|
|
231
|
-
|
|
178
|
+
`exit.financing` is included on closed trades when carry or funding applies. It is already deducted from `exit.pnl` and aggregate metrics.
|
|
232
179
|
|
|
233
|
-
|
|
180
|
+
## Validation
|
|
234
181
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
Use `walkForwardOptimize()` when one in-sample backtest is not enough. It supports rolling and anchored train/test windows across the full candle history.
|
|
182
|
+
Use a normal backtest to build the strategy. Use validation tools before trusting it.
|
|
238
183
|
|
|
239
184
|
```js
|
|
240
|
-
import { walkForwardOptimize } from "tradelab";
|
|
185
|
+
import { walkForwardOptimize, grid } from "tradelab";
|
|
241
186
|
|
|
242
187
|
const wf = walkForwardOptimize({
|
|
243
188
|
candles,
|
|
244
|
-
mode: "anchored",
|
|
245
189
|
trainBars: 180,
|
|
246
190
|
testBars: 60,
|
|
247
|
-
|
|
191
|
+
mode: "anchored",
|
|
248
192
|
scoreBy: "profitFactor",
|
|
249
|
-
parameterSets:
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
193
|
+
parameterSets: grid({
|
|
194
|
+
fast: [8, 10, 12],
|
|
195
|
+
slow: [21, 30, 50],
|
|
196
|
+
rr: [1.5, 2, 3],
|
|
197
|
+
}),
|
|
253
198
|
signalFactory(params) {
|
|
254
|
-
return
|
|
199
|
+
return createEmaSignal(params);
|
|
255
200
|
},
|
|
256
201
|
});
|
|
257
|
-
```
|
|
258
202
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
## Tick backtests
|
|
203
|
+
console.log(wf.metrics);
|
|
204
|
+
console.log(wf.bestParamsSummary);
|
|
205
|
+
```
|
|
264
206
|
|
|
265
|
-
|
|
207
|
+
For larger sweeps, use `optimize()` with a strategy module:
|
|
266
208
|
|
|
267
209
|
```js
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
signal,
|
|
210
|
+
const out = await optimize({
|
|
211
|
+
candles,
|
|
212
|
+
interval: "1d",
|
|
213
|
+
signalModulePath: new URL("./strategy.js", import.meta.url).pathname,
|
|
214
|
+
parameterSets: grid({ fast: [8, 10], slow: [30, 50] }),
|
|
215
|
+
scoreBy: "sharpeAnnualized",
|
|
275
216
|
});
|
|
276
217
|
```
|
|
277
218
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
Use `seed` to make probabilistic limit fills reproducible across repeated runs with the same data and options.
|
|
219
|
+
## Portfolio Backtests
|
|
281
220
|
|
|
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.
|
|
221
|
+
`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
222
|
|
|
286
223
|
```js
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
224
|
+
const portfolio = backtestPortfolio({
|
|
225
|
+
equity: 100_000,
|
|
226
|
+
interval: "1d",
|
|
227
|
+
maxDailyLossPct: 3,
|
|
228
|
+
systems: [
|
|
229
|
+
{ symbol: "SPY", candles: spy, signal: spySignal, weight: 2 },
|
|
230
|
+
{ symbol: "QQQ", candles: qqq, signal: qqqSignal, weight: 1 },
|
|
231
|
+
],
|
|
295
232
|
});
|
|
296
|
-
|
|
297
|
-
const result = await backtestAsync({ candles, signal: llm.signal, signalBudgetMs: 3000 });
|
|
298
233
|
```
|
|
299
234
|
|
|
300
|
-
|
|
235
|
+
Portfolio equity points include `lockedCapital` and `availableCapital`.
|
|
301
236
|
|
|
302
|
-
|
|
237
|
+
## Live and Paper Runs
|
|
303
238
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
`tradelab/live` provides the live stack:
|
|
307
|
-
|
|
308
|
-
- `LiveEngine` for single-system live/paper execution
|
|
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:
|
|
239
|
+
The live package uses the same signal shape as backtests.
|
|
315
240
|
|
|
316
241
|
```js
|
|
317
242
|
import { LiveEngine, PaperEngine, JsonFileStorage } from "tradelab/live";
|
|
@@ -320,196 +245,81 @@ const engine = new LiveEngine({
|
|
|
320
245
|
id: "aapl-1m",
|
|
321
246
|
symbol: "AAPL",
|
|
322
247
|
interval: "1m",
|
|
248
|
+
mode: "polling",
|
|
323
249
|
broker: new PaperEngine({ equity: 25_000 }),
|
|
324
250
|
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
|
-
},
|
|
251
|
+
signal,
|
|
329
252
|
});
|
|
330
253
|
|
|
331
254
|
await engine.start();
|
|
332
255
|
```
|
|
333
256
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
---
|
|
337
|
-
|
|
338
|
-
## Execution and cost modeling
|
|
339
|
-
|
|
340
|
-
```js
|
|
341
|
-
const result = backtest({
|
|
342
|
-
candles,
|
|
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.
|
|
257
|
+
Run the same flow from the terminal:
|
|
378
258
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
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" });
|
|
259
|
+
```bash
|
|
260
|
+
tradelab paper --symbol AAPL --interval 1m --mode polling --once true
|
|
261
|
+
tradelab live --config ./live-portfolio.json --paper
|
|
388
262
|
```
|
|
389
263
|
|
|
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.
|
|
264
|
+
Add `--dashboard --dashboardPort 4317` to open a local Server-Sent Events dashboard.
|
|
400
265
|
|
|
401
|
-
|
|
266
|
+
## MCP Server
|
|
402
267
|
|
|
403
|
-
|
|
268
|
+
`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.
|
|
404
269
|
|
|
405
|
-
|
|
270
|
+
**Research tools:** `list_strategies`, `fetch_candles`, `run_backtest`, `walk_forward`, `analyze_robustness`, `optimize_strategy`, `compare_strategies`, `candle_stats`
|
|
406
271
|
|
|
407
|
-
|
|
408
|
-
# Backtest from Yahoo
|
|
409
|
-
npx tradelab backtest --source yahoo --symbol SPY --interval 1d --period 1y
|
|
272
|
+
**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`
|
|
410
273
|
|
|
411
|
-
|
|
412
|
-
npx tradelab backtest --source csv --csvPath ./data/btc.csv --strategy buy-hold --holdBars 3
|
|
274
|
+
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.
|
|
413
275
|
|
|
414
|
-
|
|
415
|
-
npx tradelab portfolio \
|
|
416
|
-
--csvPaths ./data/spy.csv,./data/qqq.csv \
|
|
417
|
-
--symbols SPY,QQQ \
|
|
418
|
-
--strategy buy-hold
|
|
276
|
+
Use it from any MCP client that can launch a stdio server:
|
|
419
277
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
npx tradelab live --config ./live-portfolio.json --paper --mode polling --once true
|
|
430
|
-
|
|
431
|
-
# Inspect persisted live state
|
|
432
|
-
npx tradelab status --dir ./output/live-state
|
|
433
|
-
|
|
434
|
-
# Prefetch and cache data
|
|
435
|
-
npx tradelab prefetch --symbol SPY --interval 1d --period 1y
|
|
436
|
-
npx tradelab import-csv --csvPath ./data/spy.csv --symbol SPY --interval 1d
|
|
278
|
+
```json
|
|
279
|
+
{
|
|
280
|
+
"mcpServers": {
|
|
281
|
+
"tradelab": {
|
|
282
|
+
"command": "npx",
|
|
283
|
+
"args": ["-y", "tradelab", "tradelab-mcp"]
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
437
287
|
```
|
|
438
288
|
|
|
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
|
|
289
|
+
## CLI
|
|
446
290
|
|
|
447
291
|
```bash
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
292
|
+
tradelab backtest --source yahoo --symbol SPY --interval 1d --period 1y
|
|
293
|
+
tradelab portfolio --csvPaths ./spy.csv,./qqq.csv --symbols SPY,QQQ
|
|
294
|
+
tradelab walk-forward --source yahoo --symbol QQQ --interval 1d --period 2y
|
|
295
|
+
tradelab status --dir ./output/live-state
|
|
451
296
|
```
|
|
452
297
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
---
|
|
298
|
+
## Documentation
|
|
456
299
|
|
|
457
|
-
|
|
300
|
+
- [Docs home](docs/README.md)
|
|
301
|
+
- [Backtesting](docs/backtest-engine.md)
|
|
302
|
+
- [Data, reporting, and CLI](docs/data-reporting-cli.md)
|
|
303
|
+
- [Live trading](docs/live-trading.md)
|
|
304
|
+
- [MCP server](docs/mcp.md)
|
|
305
|
+
- [Research tools](docs/research.md)
|
|
306
|
+
- [Strategy examples](docs/examples.md)
|
|
307
|
+
- [API reference](docs/api-reference.md)
|
|
458
308
|
|
|
459
|
-
|
|
309
|
+
## Module Entry Points
|
|
460
310
|
|
|
461
311
|
```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";
|
|
312
|
+
import { backtest, getHistoricalCandles } from "tradelab";
|
|
313
|
+
import { rsi, macd, vwap } from "tradelab/ta";
|
|
314
|
+
import { LiveEngine, PaperEngine, TradingSession, SessionManager } from "tradelab/live";
|
|
469
315
|
```
|
|
470
316
|
|
|
471
|
-
|
|
317
|
+
CommonJS is supported for the main, data, live, and TA entry points:
|
|
472
318
|
|
|
473
319
|
```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");
|
|
320
|
+
const { backtest } = require("tradelab");
|
|
480
321
|
```
|
|
481
322
|
|
|
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
|
|
323
|
+
## License
|
|
511
324
|
|
|
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
|
|
325
|
+
MIT
|