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.
Files changed (39) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/README.md +183 -373
  3. package/dist/cjs/index.cjs +39 -12
  4. package/dist/cjs/live.cjs +457 -18
  5. package/docs/README.md +32 -66
  6. package/docs/api-reference.md +269 -144
  7. package/docs/backtest-engine.md +167 -321
  8. package/docs/data-reporting-cli.md +114 -156
  9. package/docs/examples.md +6 -6
  10. package/docs/live-trading.md +254 -134
  11. package/docs/mcp.md +244 -23
  12. package/docs/research.md +99 -45
  13. package/examples/mcpLiveTrading.js +77 -0
  14. package/package.json +11 -3
  15. package/src/engine/optimize.js +25 -1
  16. package/src/engine/portfolio.js +6 -2
  17. package/src/live/dashboard/server.js +67 -8
  18. package/src/live/engine/paperEngine.js +21 -11
  19. package/src/live/index.js +2 -0
  20. package/src/live/session.js +439 -0
  21. package/src/mcp/liveTools.js +202 -0
  22. package/src/mcp/schemas.js +119 -0
  23. package/src/mcp/server.js +5 -1
  24. package/src/mcp/tools.js +125 -2
  25. package/src/research/monteCarlo.js +6 -2
  26. package/templates/dashboard.html +595 -108
  27. package/types/index.d.ts +25 -0
  28. package/types/live.d.ts +102 -1
  29. package/types/mcp.d.ts +17 -0
  30. package/docs/superpowers/plans/2026-00-overview.md +0 -101
  31. package/docs/superpowers/plans/2026-01-metrics-correctness.md +0 -873
  32. package/docs/superpowers/plans/2026-02-indicator-library.md +0 -677
  33. package/docs/superpowers/plans/2026-03-overfitting-toolkit.md +0 -882
  34. package/docs/superpowers/plans/2026-04-async-signals-seeding.md +0 -981
  35. package/docs/superpowers/plans/2026-05-mcp-server.md +0 -758
  36. package/docs/superpowers/plans/2026-06-parallel-param-sweep.md +0 -508
  37. package/docs/superpowers/plans/2026-07-funding-carry-costs.md +0 -535
  38. package/docs/superpowers/plans/2026-08-live-dashboard.md +0 -547
  39. package/docs/superpowers/plans/HANDOFF.md +0 -88
package/README.md CHANGED
@@ -13,305 +13,230 @@
13
13
 
14
14
  ---
15
15
 
16
- **tradelab** handles strategy research and execution workflows in one package.
16
+ A Node.js toolkit for testing, validating, and operating trading strategies.
17
17
 
18
- Use it for backtests, portfolio and walk-forward validation, and live or paper execution through broker adapters while keeping the same `signal()` contract.
18
+ tradelab gives you one `signal()` contract across research and execution:
19
19
 
20
- AI-agent users: see [docs/mcp.md](docs/mcp.md) to run the research loop via MCP.
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
- If you already have candles, `backtest()` is the main entry point.
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: "BTC-USD",
77
- interval: "5m",
78
- range: "60d",
49
+ symbol: "SPY",
50
+ interval: "1d",
79
51
  equity: 10_000,
80
52
  riskPct: 1,
81
- signal({ candles: history }) {
82
- if (history.length < 50) return null;
83
-
84
- const closes = history.map((bar) => bar.close);
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 last = closes.length - 1;
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
- return { side: "long", entry, stop, rr: 2 };
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
- After the run, check `result.metrics` for the headline numbers and `result.positions` for the trade log.
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
- See [docs/mcp.md](docs/mcp.md) for setup and the Claude Desktop config.
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
- ## Loading historical data
96
+ ## The Signal Contract
118
97
 
119
- Most users can start with `getHistoricalCandles()`. It abstracts over Yahoo Finance and CSV, handles caching, and normalizes the output so it feeds straight into `backtest()`.
98
+ Your strategy is a function. Return `null` to do nothing, or return a trade signal.
120
99
 
121
100
  ```js
122
- import { getHistoricalCandles, backtest } from "tradelab";
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
- const result = backtest({ candles, symbol: "SPY", interval: "1d", range: "2y", signal });
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
- **Supported sources:** `yahoo` · `csv` · `auto`
113
+ Common signal fields:
136
114
 
137
- **Supported periods:** `5d` · `60d` · `6mo` · `1y` · `2y` · and more
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
- Use `cache: true` for repeatable research runs. It eliminates network noise and makes failures easier to diagnose.
125
+ ## Data
140
126
 
141
- ### CSV import
127
+ Use `getHistoricalCandles()` for Yahoo Finance, CSV files, and cached datasets.
142
128
 
143
129
  ```js
144
- const candles = await getHistoricalCandles({
145
- source: "csv",
146
- csvPath: "./data/spy.csv",
147
- csv: {
148
- timeCol: "timestamp",
149
- openCol: "open",
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
- ## Core concepts
160
-
161
- ### The signal function
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
- The minimum viable signal is just `side`, `stop`, and `rr`. Start there and add fields only when the strategy actually needs them.
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
- symbol, interval, range,
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
- **First checks after any run:**
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
- Use `backtestPortfolio()` when you have one candle array per symbol and want a single combined result.
154
+ Cost assumptions belong in the run, not in post-processing.
218
155
 
219
156
  ```js
220
- import { backtestPortfolio } from "tradelab";
221
-
222
- const result = backtestPortfolio({
223
- equity: 100_000,
224
- systems: [
225
- { symbol: "SPY", candles: spy, signal: signalA, weight: 2 },
226
- { symbol: "QQQ", candles: qqq, signal: signalB, weight: 1 },
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
- Weights now act as default per-system allocation caps rather than pre-funded sleeves. Capital is locked only when a fill happens, `eqSeries` includes `lockedCapital` and `availableCapital`, later systems size against remaining live capital, and `maxDailyLossPct` on `backtestPortfolio()` can halt the whole book for the rest of the day.
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
- ## Walk-forward optimization
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
- stepBars: 60,
191
+ mode: "anchored",
248
192
  scoreBy: "profitFactor",
249
- parameterSets: [
250
- { fast: 8, slow: 21, rr: 2 },
251
- { fast: 10, slow: 30, rr: 2 },
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 createSignalFromParams(params);
199
+ return createEmaSignal(params);
255
200
  },
256
201
  });
257
- ```
258
202
 
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
-
263
- ## Tick backtests
203
+ console.log(wf.metrics);
204
+ console.log(wf.bestParamsSummary);
205
+ ```
264
206
 
265
- Use `backtestTicks()` when you want event-driven fills on tick or quote data without changing the result shape used by metrics, exports, or replay.
207
+ For larger sweeps, use `optimize()` with a strategy module:
266
208
 
267
209
  ```js
268
- import { backtestTicks } from "tradelab";
269
-
270
- const result = backtestTicks({
271
- ticks,
272
- queueFillProbability: 0.35,
273
- seed: "research-run-1",
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
- Market entries fill on the next tick, limit orders can fill at the touch with configurable queue probability, and stop exits use the existing cost model with stop-specific slippage if you provide it in `costs.slippageByKind.stop`.
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
- ## Async and LLM signals
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
- import { backtestAsync, LlmSignal } from "tradelab";
288
-
289
- const llm = new LlmSignal({
290
- budgetMs: 2000,
291
- async resolve({ candles, bar }) {
292
- const closes = candles.map((c) => c.close);
293
- return closes.at(-1) > closes.at(-5) ? { side: "long", stop: bar.close * 0.98, rr: 2 } : null;
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
- `LiveEngine` awaits async signals too, so the same `llm.signal` can move from research into paper or live execution.
235
+ Portfolio equity points include `lockedCapital` and `availableCapital`.
301
236
 
302
- ---
237
+ ## Live and Paper Runs
303
238
 
304
- ## Live trading
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({ bar, openPosition }) {
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
- See [docs/live-trading.md](docs/live-trading.md) for API and CLI workflows.
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
- ## 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" });
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
- Or use the narrower helpers:
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
- ## CLI
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
- The package ships a `tradelab` binary. Best for quick iteration, smoke tests, and trying the package before wiring it into application code.
270
+ **Research tools:** `list_strategies`, `fetch_candles`, `run_backtest`, `walk_forward`, `analyze_robustness`, `optimize_strategy`, `compare_strategies`, `candle_stats`
406
271
 
407
- ```bash
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
- # Backtest from CSV with a built-in strategy
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
- # Multi-symbol portfolio
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
- # Walk-forward validation
421
- npx tradelab walk-forward \
422
- --source yahoo --symbol QQQ --interval 1d --period 2y \
423
- --trainBars 180 --testBars 60 --mode anchored
424
-
425
- # Live paper engine (single system)
426
- npx tradelab paper --symbol AAPL --interval 1m --mode polling --once true
427
-
428
- # Live orchestrator from config
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
- **Built-in strategies:** `ema-cross` · `buy-hold`
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
- node examples/emaCross.js
449
- node examples/yahooEmaCross.js SPY 1d 1y
450
- node examples/llmSignal.js
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
- The examples are a good place to start if you want something runnable before wiring the package into your own strategy code.
454
-
455
- ---
298
+ ## Documentation
456
299
 
457
- ## Importing
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
- ### ESM
309
+ ## Module Entry Points
460
310
 
461
311
  ```js
462
- import { backtest, getHistoricalCandles, ema } from "tradelab";
463
- import { backtestAsync, LlmSignal, optimize, grid } from "tradelab";
464
- import { research } from "tradelab"; // monteCarlo, deflatedSharpe, probabilityOfBacktestOverfitting, ...
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
- ### CommonJS
317
+ CommonJS is supported for the main, data, live, and TA entry points:
472
318
 
473
319
  ```js
474
- const { backtest, getHistoricalCandles, ema } = require("tradelab");
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
- > `tradelab/mcp` is ESM-only (the MCP SDK is ESM-only). Use the `tradelab-mcp` binary or import it from an ESM context.
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
- - Node `18+` is required
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