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.
Files changed (38) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +185 -388
  3. package/dist/cjs/index.cjs +31 -9
  4. package/dist/cjs/live.cjs +409 -7
  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 +4 -1
  17. package/src/live/dashboard/server.js +67 -8
  18. package/src/live/engine/paperEngine.js +5 -0
  19. package/src/live/index.js +2 -0
  20. package/src/live/session.js +402 -0
  21. package/src/mcp/liveTools.js +179 -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/templates/dashboard.html +595 -108
  26. package/types/index.d.ts +25 -0
  27. package/types/live.d.ts +99 -0
  28. package/types/mcp.d.ts +17 -0
  29. package/docs/superpowers/plans/2026-00-overview.md +0 -101
  30. package/docs/superpowers/plans/2026-01-metrics-correctness.md +0 -873
  31. package/docs/superpowers/plans/2026-02-indicator-library.md +0 -677
  32. package/docs/superpowers/plans/2026-03-overfitting-toolkit.md +0 -882
  33. package/docs/superpowers/plans/2026-04-async-signals-seeding.md +0 -981
  34. package/docs/superpowers/plans/2026-05-mcp-server.md +0 -758
  35. package/docs/superpowers/plans/2026-06-parallel-param-sweep.md +0 -508
  36. package/docs/superpowers/plans/2026-07-funding-carry-costs.md +0 -535
  37. package/docs/superpowers/plans/2026-08-live-dashboard.md +0 -547
  38. package/docs/superpowers/plans/HANDOFF.md +0 -88
package/README.md CHANGED
@@ -1,317 +1,229 @@
1
- <div align="center">
2
- <img src="https://i.imgur.com/HGvvQbq.png" width="420" alt="tradelab logo" />
1
+ # tradelab
3
2
 
4
- <p><strong>A Node.js backtesting toolkit for serious trading strategy research.</strong></p>
3
+ A Node.js toolkit for testing, validating, and operating trading strategies.
5
4
 
6
- [![npm version](https://img.shields.io/npm/v/tradelab?color=0f172a&label=npm&logo=npm)](https://www.npmjs.com/package/tradelab)
7
- [![GitHub](https://img.shields.io/badge/github-ishsharm0/tradelab-0f172a?logo=github)](https://github.com/ishsharm0/tradelab)
8
- [![License: MIT](https://img.shields.io/badge/license-MIT-0f172a)](https://github.com/ishsharm0/tradelab/blob/main/LICENSE)
9
- [![Node.js](https://img.shields.io/badge/node-%3E%3D18-0f172a?logo=node.js)](https://nodejs.org)
10
- [![TypeScript](https://img.shields.io/badge/TypeScript-ready-0f172a?logo=typescript)](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
- </div>
13
-
14
- ---
15
-
16
- **tradelab** handles strategy research and execution workflows in one package.
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.
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
- ## 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
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: "BTC-USD",
77
- interval: "5m",
78
- range: "60d",
36
+ symbol: "SPY",
37
+ interval: "1d",
79
38
  equity: 10_000,
80
39
  riskPct: 1,
81
- signal({ candles: history }) {
82
- if (history.length < 50) return null;
83
-
84
- const closes = history.map((bar) => bar.close);
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 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;
49
+ const i = closes.length - 1;
94
50
 
95
- return { side: "long", entry, stop, rr: 2 };
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
- 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.
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
- See [docs/mcp.md](docs/mcp.md) for setup and the Claude Desktop config.
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
- ## Loading historical data
83
+ ## The Signal Contract
118
84
 
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()`.
85
+ Your strategy is a function. Return `null` to do nothing, or return a trade signal.
120
86
 
121
87
  ```js
122
- import { getHistoricalCandles, backtest } from "tradelab";
88
+ function signal({ candles, index, bar, equity, openPosition, pendingOrder }) {
89
+ if (openPosition || index < 50) return null;
123
90
 
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
- });
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
- **Supported sources:** `yahoo` · `csv` · `auto`
100
+ Common signal fields:
136
101
 
137
- **Supported periods:** `5d` · `60d` · `6mo` · `1y` · `2y` · and more
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
- Use `cache: true` for repeatable research runs. It eliminates network noise and makes failures easier to diagnose.
112
+ ## Data
140
113
 
141
- ### CSV import
114
+ Use `getHistoricalCandles()` for Yahoo Finance, CSV files, and cached datasets.
142
115
 
143
116
  ```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
- },
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
- ### 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
- }
125
+ const csv = await getHistoricalCandles({
126
+ source: "csv",
127
+ csvPath: "./data/btc.csv",
128
+ });
176
129
  ```
177
130
 
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
131
+ Candles are normalized to:
194
132
 
195
133
  ```js
196
134
  {
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
135
+ (time, open, high, low, close, volume);
203
136
  }
204
137
  ```
205
138
 
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
- ---
139
+ ## Costs
214
140
 
215
- ## Portfolio mode
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
- 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
- ],
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
- 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.
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
- ## Walk-forward optimization
167
+ ## Validation
236
168
 
237
- Use `walkForwardOptimize()` when one in-sample backtest is not enough. It supports rolling and anchored train/test windows across the full candle history.
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
- stepBars: 60,
178
+ mode: "anchored",
248
179
  scoreBy: "profitFactor",
249
- parameterSets: [
250
- { fast: 8, slow: 21, rr: 2 },
251
- { fast: 10, slow: 30, rr: 2 },
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 createSignalFromParams(params);
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
- ## Tick backtests
190
+ console.log(wf.metrics);
191
+ console.log(wf.bestParamsSummary);
192
+ ```
264
193
 
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.
194
+ For larger sweeps, use `optimize()` with a strategy module:
266
195
 
267
196
  ```js
268
- import { backtestTicks } from "tradelab";
269
-
270
- const result = backtestTicks({
271
- ticks,
272
- queueFillProbability: 0.35,
273
- seed: "research-run-1",
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
- 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.
206
+ ## Portfolio Backtests
281
207
 
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.
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
- 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
- },
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
- `LiveEngine` awaits async signals too, so the same `llm.signal` can move from research into paper or live execution.
301
-
302
- ---
303
-
304
- ## Live trading
222
+ Portfolio equity points include `lockedCapital` and `availableCapital`.
305
223
 
306
- `tradelab/live` provides the live stack:
224
+ ## Live and Paper Runs
307
225
 
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:
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({ bar, openPosition }) {
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
- See [docs/live-trading.md](docs/live-trading.md) for API and CLI workflows.
335
-
336
- ---
337
-
338
- ## Execution and cost modeling
244
+ Run the same flow from the terminal:
339
245
 
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.
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
- 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.
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
- ```bash
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
- # Multi-symbol portfolio
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
- # Walk-forward validation
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
- # Live paper engine (single system)
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
- # Live orchestrator from config
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
- # Inspect persisted live state
432
- npx tradelab status --dir ./output/live-state
263
+ Use it from any MCP client that can launch a stdio server:
433
264
 
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
265
+ ```json
266
+ {
267
+ "mcpServers": {
268
+ "tradelab": {
269
+ "command": "npx",
270
+ "args": ["-y", "tradelab", "tradelab-mcp"]
271
+ }
272
+ }
273
+ }
437
274
  ```
438
275
 
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
276
+ ## CLI
446
277
 
447
278
  ```bash
448
- node examples/emaCross.js
449
- node examples/yahooEmaCross.js SPY 1d 1y
450
- node examples/llmSignal.js
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
- The examples are a good place to start if you want something runnable before wiring the package into your own strategy code.
454
-
455
- ---
285
+ ## Documentation
456
286
 
457
- ## Importing
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
- ### ESM
296
+ ## Module Entry Points
460
297
 
461
298
  ```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";
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
- ### CommonJS
304
+ CommonJS is supported for the main, data, live, and TA entry points:
472
305
 
473
306
  ```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");
307
+ const { backtest } = require("tradelab");
480
308
  ```
481
309
 
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
310
+ ## License
511
311
 
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
312
+ MIT