tradelab 1.0.1 → 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 (66) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/README.md +188 -328
  3. package/bin/tradelab-mcp.js +7 -0
  4. package/bin/tradelab.js +29 -0
  5. package/dist/cjs/data.cjs +149 -26
  6. package/dist/cjs/index.cjs +1917 -1005
  7. package/dist/cjs/live.cjs +536 -25
  8. package/dist/cjs/ta.cjs +339 -0
  9. package/docs/README.md +32 -66
  10. package/docs/api-reference.md +283 -112
  11. package/docs/backtest-engine.md +210 -252
  12. package/docs/data-reporting-cli.md +114 -156
  13. package/docs/examples.md +6 -6
  14. package/docs/live-trading.md +263 -92
  15. package/docs/mcp.md +285 -0
  16. package/docs/research.md +157 -0
  17. package/examples/liveDashboard.js +33 -0
  18. package/examples/llmSignal.js +33 -0
  19. package/examples/mcpLiveTrading.js +77 -0
  20. package/examples/optimize.js +25 -0
  21. package/package.json +26 -4
  22. package/src/engine/asyncSignal.js +28 -0
  23. package/src/engine/backtest.js +13 -1
  24. package/src/engine/backtestAsync.js +27 -0
  25. package/src/engine/backtestTicks.js +13 -2
  26. package/src/engine/barSystemRunner.js +96 -41
  27. package/src/engine/execution.js +39 -0
  28. package/src/engine/grid.js +15 -0
  29. package/src/engine/llmSignal.js +84 -0
  30. package/src/engine/optimize.js +110 -0
  31. package/src/engine/optimizeWorker.js +67 -0
  32. package/src/engine/portfolio.js +4 -1
  33. package/src/engine/walkForward.js +1 -0
  34. package/src/index.js +9 -0
  35. package/src/live/dashboard/server.js +179 -0
  36. package/src/live/engine/liveEngine.js +2 -2
  37. package/src/live/engine/paperEngine.js +5 -0
  38. package/src/live/index.js +3 -0
  39. package/src/live/session.js +402 -0
  40. package/src/mcp/liveTools.js +179 -0
  41. package/src/mcp/schemas.js +167 -0
  42. package/src/mcp/server.js +35 -0
  43. package/src/mcp/tools.js +265 -0
  44. package/src/metrics/annualize.js +32 -0
  45. package/src/metrics/benchmark.js +55 -0
  46. package/src/metrics/buildMetrics.js +34 -13
  47. package/src/metrics/finite.js +17 -0
  48. package/src/research/combinations.js +18 -0
  49. package/src/research/cpcv.js +47 -0
  50. package/src/research/deflatedSharpe.js +35 -0
  51. package/src/research/index.js +6 -0
  52. package/src/research/monteCarlo.js +88 -0
  53. package/src/research/pbo.js +69 -0
  54. package/src/research/stats.js +78 -0
  55. package/src/strategies/builtins.js +96 -0
  56. package/src/strategies/index.js +30 -0
  57. package/src/ta/channels.js +67 -0
  58. package/src/ta/index.js +16 -0
  59. package/src/ta/oscillators.js +70 -0
  60. package/src/ta/trend.js +78 -0
  61. package/src/utils/random.js +33 -0
  62. package/templates/dashboard.html +661 -0
  63. package/types/index.d.ts +179 -0
  64. package/types/live.d.ts +114 -0
  65. package/types/mcp.d.ts +17 -0
  66. package/types/ta.d.ts +45 -0
package/README.md CHANGED
@@ -1,278 +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.
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
19
14
 
20
15
  ```bash
21
16
  npm install tradelab
22
17
  ```
23
18
 
24
- ---
25
-
26
- ## Table of contents
27
-
28
- - [What it includes](#what-it-includes)
29
- - [Quick start](#quick-start)
30
- - [Loading historical data](#loading-historical-data)
31
- - [Core concepts](#core-concepts)
32
- - [Portfolio mode](#portfolio-mode)
33
- - [Walk-forward optimization](#walk-forward-optimization)
34
- - [Tick backtests](#tick-backtests)
35
- - [Live trading](#live-trading)
36
- - [Execution and cost modeling](#execution-and-cost-modeling)
37
- - [Exports and reporting](#exports-and-reporting)
38
- - [CLI](#cli)
39
- - [Examples](#examples)
40
- - [Documentation](#documentation)
41
-
42
- ---
43
-
44
- ## What it includes
45
-
46
- | Area | What you get |
47
- | ------------------ | ---------------------------------------------------------------------------------------- |
48
- | **Engine** | Candle and tick backtests with position sizing, exits, replay capture, and cost models |
49
- | **Portfolio** | Multi-system shared-capital simulation with live capital locking and daily loss halts |
50
- | **Walk-forward** | Rolling and anchored train/test validation with parameter search and stability summaries |
51
- | **Live execution** | Live and paper engines with broker adapters, state persistence, and orchestration |
52
- | **Data** | Yahoo Finance downloads, CSV import, and local cache helpers |
53
- | **Costs** | Slippage, spread, and commission modeling |
54
- | **Exports** | HTML reports, metrics JSON, and trade CSV |
55
- | **Dev experience** | TypeScript definitions, ESM/CJS support, CLI for quick runs |
56
-
57
- ---
19
+ Requires Node.js 18 or newer.
58
20
 
59
- ## Quick start
60
-
61
- If you already have candles, `backtest()` is the main entry point.
21
+ ## Quick Start
62
22
 
63
23
  ```js
64
- 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
+ });
65
33
 
66
34
  const result = backtest({
67
35
  candles,
68
- symbol: "BTC-USD",
69
- interval: "5m",
70
- range: "60d",
36
+ symbol: "SPY",
37
+ interval: "1d",
71
38
  equity: 10_000,
72
39
  riskPct: 1,
73
- signal({ candles: history }) {
74
- if (history.length < 50) return null;
75
-
76
- 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);
77
47
  const fast = ema(closes, 10);
78
48
  const slow = ema(closes, 30);
79
- const last = closes.length - 1;
80
-
81
- if (fast[last - 1] <= slow[last - 1] && fast[last] > slow[last]) {
82
- const entry = history[last].close;
83
- const stop = Math.min(...history.slice(-15).map((bar) => bar.low));
84
- const risk = entry - stop;
85
- if (risk <= 0) return null;
49
+ const i = closes.length - 1;
86
50
 
87
- 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 };
88
53
  }
89
54
 
90
55
  return null;
91
56
  },
92
57
  });
93
58
 
59
+ console.log(result.metrics);
94
60
  exportBacktestArtifacts({ result, outDir: "./output" });
95
61
  ```
96
62
 
97
- After the run, check `result.metrics` for the headline numbers and `result.positions` for the trade log.
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.
98
64
 
99
- ---
65
+ ## What You Can Build
100
66
 
101
- ## Loading historical data
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` |
102
82
 
103
- 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()`.
83
+ ## The Signal Contract
104
84
 
105
- ```js
106
- import { getHistoricalCandles, backtest } from "tradelab";
85
+ Your strategy is a function. Return `null` to do nothing, or return a trade signal.
107
86
 
108
- const candles = await getHistoricalCandles({
109
- source: "yahoo",
110
- symbol: "SPY",
111
- interval: "1d",
112
- period: "2y",
113
- cache: true, // reuses local copy on repeated runs
114
- });
87
+ ```js
88
+ function signal({ candles, index, bar, equity, openPosition, pendingOrder }) {
89
+ if (openPosition || index < 50) return null;
115
90
 
116
- 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
+ }
117
98
  ```
118
99
 
119
- **Supported sources:** `yahoo` · `csv` · `auto`
100
+ Common signal fields:
120
101
 
121
- **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 |
122
111
 
123
- Use `cache: true` for repeatable research runs. It eliminates network noise and makes failures easier to diagnose.
112
+ ## Data
124
113
 
125
- ### CSV import
114
+ Use `getHistoricalCandles()` for Yahoo Finance, CSV files, and cached datasets.
126
115
 
127
116
  ```js
128
- const candles = await getHistoricalCandles({
129
- source: "csv",
130
- csvPath: "./data/spy.csv",
131
- csv: {
132
- timeCol: "timestamp",
133
- openCol: "open",
134
- // ... optional column mapping
135
- },
117
+ const yahoo = await getHistoricalCandles({
118
+ source: "yahoo",
119
+ symbol: "QQQ",
120
+ interval: "1d",
121
+ period: "1y",
122
+ cache: true,
136
123
  });
137
- ```
138
-
139
- If your CSV already uses standard OHLCV column names, no mapping is needed at all.
140
-
141
- ---
142
-
143
- ## Core concepts
144
-
145
- ### The signal function
146
124
 
147
- Your signal function is called on every bar. Return `null` to skip, or a signal object to open a trade.
148
-
149
- ```js
150
- signal({ candles, index, bar, equity, openPosition, pendingOrder }) {
151
- // return null to skip
152
- // return a signal to enter
153
- return {
154
- side: "long", // "long" | "short" | "buy" | "sell"
155
- entry: bar.close, // defaults to current close if omitted
156
- stop: bar.close - 2,
157
- rr: 2, // target = entry + (entry - stop) * rr
158
- };
159
- }
125
+ const csv = await getHistoricalCandles({
126
+ source: "csv",
127
+ csvPath: "./data/btc.csv",
128
+ });
160
129
  ```
161
130
 
162
- The minimum viable signal is just `side`, `stop`, and `rr`. Start there and add fields only when the strategy actually needs them.
163
-
164
- ### Key backtest options
165
-
166
- | Option | Purpose |
167
- | ----------------- | -------------------------------------------- |
168
- | `equity` | Starting equity (default `10000`) |
169
- | `riskPct` | Percent of equity risked per trade |
170
- | `warmupBars` | Bars skipped before signal evaluation starts |
171
- | `flattenAtClose` | Forces end-of-day exit when enabled |
172
- | `costs` | Slippage, spread, and commission model |
173
- | `strict` | Throws on lookahead access |
174
- | `collectEqSeries` | Enables equity curve output |
175
- | `collectReplay` | Enables visualization payload |
176
-
177
- ### Result shape
131
+ Candles are normalized to:
178
132
 
179
133
  ```js
180
134
  {
181
- symbol, interval, range,
182
- trades, // every realized leg, including partial exits
183
- positions, // completed positions - start here for analysis
184
- metrics, // winRate, profitFactor, maxDrawdown, sharpe, ...
185
- eqSeries, // [{ time, timestamp, equity }] - equity curve
186
- replay, // visualization frames and events
135
+ (time, open, high, low, close, volume);
187
136
  }
188
137
  ```
189
138
 
190
- **First checks after any run:**
191
-
192
- - `metrics.trades` - enough sample size to trust the numbers?
193
- - `metrics.profitFactor` - do winners beat losers gross of costs?
194
- - `metrics.maxDrawdown` - is the equity path survivable?
195
- - `metrics.sideBreakdown` - does one side carry the whole result?
196
-
197
- ---
198
-
199
- ## Portfolio mode
139
+ ## Costs
200
140
 
201
- 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.
202
142
 
203
143
  ```js
204
- import { backtestPortfolio } from "tradelab";
205
-
206
- const result = backtestPortfolio({
207
- equity: 100_000,
208
- systems: [
209
- { symbol: "SPY", candles: spy, signal: signalA, weight: 2 },
210
- { symbol: "QQQ", candles: qqq, signal: signalB, weight: 1 },
211
- ],
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
+ },
212
162
  });
213
163
  ```
214
164
 
215
- 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.
216
-
217
- ---
165
+ `exit.financing` is included on closed trades when carry or funding applies. It is already deducted from `exit.pnl` and aggregate metrics.
218
166
 
219
- ## Walk-forward optimization
167
+ ## Validation
220
168
 
221
- 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.
222
170
 
223
171
  ```js
224
- import { walkForwardOptimize } from "tradelab";
172
+ import { walkForwardOptimize, grid } from "tradelab";
225
173
 
226
174
  const wf = walkForwardOptimize({
227
175
  candles,
228
- mode: "anchored",
229
176
  trainBars: 180,
230
177
  testBars: 60,
231
- stepBars: 60,
178
+ mode: "anchored",
232
179
  scoreBy: "profitFactor",
233
- parameterSets: [
234
- { fast: 8, slow: 21, rr: 2 },
235
- { fast: 10, slow: 30, rr: 2 },
236
- ],
180
+ parameterSets: grid({
181
+ fast: [8, 10, 12],
182
+ slow: [21, 30, 50],
183
+ rr: [1.5, 2, 3],
184
+ }),
237
185
  signalFactory(params) {
238
- return createSignalFromParams(params);
186
+ return createEmaSignal(params);
239
187
  },
240
188
  });
241
- ```
242
-
243
- 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.
244
-
245
- ---
246
189
 
247
- ## Tick backtests
190
+ console.log(wf.metrics);
191
+ console.log(wf.bestParamsSummary);
192
+ ```
248
193
 
249
- 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:
250
195
 
251
196
  ```js
252
- import { backtestTicks } from "tradelab";
253
-
254
- const result = backtestTicks({
255
- ticks,
256
- queueFillProbability: 0.35,
257
- 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",
258
203
  });
259
204
  ```
260
205
 
261
- 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`.
206
+ ## Portfolio Backtests
262
207
 
263
- ---
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.
264
209
 
265
- ## Live trading
210
+ ```js
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
+ ],
219
+ });
220
+ ```
266
221
 
267
- `tradelab/live` provides the live stack:
222
+ Portfolio equity points include `lockedCapital` and `availableCapital`.
268
223
 
269
- - `LiveEngine` for single-system live/paper execution
270
- - `LiveOrchestrator` for multi-system execution with shared broker state
271
- - `PaperEngine` implementing the broker interface for deterministic simulation
272
- - broker adapters for Alpaca, Binance, Coinbase, and Interactive Brokers
273
- - JSON state/trade/equity persistence via `JsonFileStorage`
224
+ ## Live and Paper Runs
274
225
 
275
- Use the same signal contract from backtesting in live mode:
226
+ The live package uses the same signal shape as backtests.
276
227
 
277
228
  ```js
278
229
  import { LiveEngine, PaperEngine, JsonFileStorage } from "tradelab/live";
@@ -281,172 +232,81 @@ const engine = new LiveEngine({
281
232
  id: "aapl-1m",
282
233
  symbol: "AAPL",
283
234
  interval: "1m",
235
+ mode: "polling",
284
236
  broker: new PaperEngine({ equity: 25_000 }),
285
237
  storage: new JsonFileStorage({ baseDir: "./output/live-state" }),
286
- signal({ bar, openPosition }) {
287
- if (openPosition) return null;
288
- return { side: "long", stop: bar.close - 1, rr: 2 };
289
- },
238
+ signal,
290
239
  });
291
240
 
292
241
  await engine.start();
293
242
  ```
294
243
 
295
- See [docs/live-trading.md](docs/live-trading.md) for API and CLI workflows.
296
-
297
- ---
298
-
299
- ## Execution and cost modeling
300
-
301
- ```js
302
- const result = backtest({
303
- candles,
304
- signal,
305
- costs: {
306
- slippageBps: 2,
307
- spreadBps: 1,
308
- slippageByKind: {
309
- market: 3,
310
- limit: 0.5,
311
- stop: 4,
312
- },
313
- commissionBps: 1,
314
- commissionPerUnit: 0,
315
- commissionPerOrder: 1,
316
- minCommission: 1,
317
- },
318
- });
319
- ```
320
-
321
- - Slippage is applied in the trade direction
322
- - Spread is modeled as half-spread paid on entry and exit
323
- - Commission can be percentage-based, per-unit, per-order, or mixed
324
- - `minCommission` floors the fee per fill
325
-
326
- > Leaving costs at zero is the most common cause of inflated backtests. Set them from the start.
327
-
328
- ---
329
-
330
- ## Exports and reporting
331
-
332
- ```js
333
- import { exportBacktestArtifacts } from "tradelab";
244
+ Run the same flow from the terminal:
334
245
 
335
- // Writes HTML report + trade CSV + metrics JSON in one call
336
- 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
337
249
  ```
338
250
 
339
- Or use the narrower helpers:
340
-
341
- | Helper | Output |
342
- | ---------------------------------- | ----------------------------------------------------- |
343
- | `exportHtmlReport(options)` | Interactive HTML report written to disk |
344
- | `renderHtmlReport(options)` | HTML report returned as a string |
345
- | `exportTradesCsv(trades, options)` | Flat trade ledger for spreadsheets or pandas |
346
- | `exportMetricsJSON(options)` | Machine-readable metrics for dashboards or automation |
347
-
348
- For programmatic pipelines, `exportMetricsJSON` is usually the most useful format to build on.
349
-
350
- ---
351
-
352
- ## CLI
353
-
354
- The package ships a `tradelab` binary. Best for quick iteration, smoke tests, and trying the package before wiring it into application code.
355
-
356
- ```bash
357
- # Backtest from Yahoo
358
- npx tradelab backtest --source yahoo --symbol SPY --interval 1d --period 1y
251
+ Add `--dashboard --dashboardPort 4317` to open a local Server-Sent Events dashboard.
359
252
 
360
- # Backtest from CSV with a built-in strategy
361
- npx tradelab backtest --source csv --csvPath ./data/btc.csv --strategy buy-hold --holdBars 3
253
+ ## MCP Server
362
254
 
363
- # Multi-symbol portfolio
364
- npx tradelab portfolio \
365
- --csvPaths ./data/spy.csv,./data/qqq.csv \
366
- --symbols SPY,QQQ \
367
- --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.
368
256
 
369
- # Walk-forward validation
370
- npx tradelab walk-forward \
371
- --source yahoo --symbol QQQ --interval 1d --period 2y \
372
- --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`
373
258
 
374
- # Live paper engine (single system)
375
- 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`
376
260
 
377
- # Live orchestrator from config
378
- 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.
379
262
 
380
- # Inspect persisted live state
381
- npx tradelab status --dir ./output/live-state
263
+ Use it from any MCP client that can launch a stdio server:
382
264
 
383
- # Prefetch and cache data
384
- npx tradelab prefetch --symbol SPY --interval 1d --period 1y
385
- 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
+ }
386
274
  ```
387
275
 
388
- **Built-in strategies:** `ema-cross` · `buy-hold`
389
-
390
- 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`.
391
-
392
- ---
393
-
394
- ## Examples
276
+ ## CLI
395
277
 
396
278
  ```bash
397
- node examples/emaCross.js
398
- node examples/yahooEmaCross.js SPY 1d 1y
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
399
283
  ```
400
284
 
401
- The examples are a good place to start if you want something runnable before wiring the package into your own strategy code.
402
-
403
- ---
285
+ ## Documentation
404
286
 
405
- ## 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)
406
295
 
407
- ### ESM
296
+ ## Module Entry Points
408
297
 
409
298
  ```js
410
- import { backtest, getHistoricalCandles, ema } from "tradelab";
411
- import { fetchHistorical } from "tradelab/data";
412
- import { LiveEngine, PaperEngine } from "tradelab/live";
299
+ import { backtest, getHistoricalCandles } from "tradelab";
300
+ import { rsi, macd, vwap } from "tradelab/ta";
301
+ import { LiveEngine, PaperEngine, TradingSession, SessionManager } from "tradelab/live";
413
302
  ```
414
303
 
415
- ### CommonJS
304
+ CommonJS is supported for the main, data, live, and TA entry points:
416
305
 
417
306
  ```js
418
- const { backtest, getHistoricalCandles, ema } = require("tradelab");
419
- const { fetchHistorical } = require("tradelab/data");
420
- const { LiveEngine, PaperEngine } = require("tradelab/live");
307
+ const { backtest } = require("tradelab");
421
308
  ```
422
309
 
423
- ---
424
-
425
- ## Documentation
426
-
427
- | Guide | What it covers |
428
- | ------------------------------------------------------ | ------------------------------------------------------------------------------ |
429
- | [Backtest engine](docs/backtest-engine.md) | Signal contract, all options, result shape, portfolio mode, walk-forward |
430
- | [Data, reporting, and CLI](docs/data-reporting-cli.md) | Data loading, cache behavior, exports, CLI reference |
431
- | [Live trading](docs/live-trading.md) | Live engine, broker adapters, paper mode, orchestration, and state persistence |
432
- | [Strategy examples](docs/examples.md) | Mean reversion, breakout, sentiment, LLM, and portfolio strategy patterns |
433
- | [API reference](docs/api-reference.md) | Compact index of every public export |
434
-
435
- ---
436
-
437
- ## Common mistakes
438
-
439
- - Using unsorted candles or mixed intervals in a single series
440
- - Reading `trades` as if they were always full positions - use `positions` for top-line analysis
441
- - Leaving costs at zero and overestimating edge
442
- - Trusting one backtest without out-of-sample validation
443
- - Debugging a strategy with `strict: false` when lookahead is possible
444
-
445
- ---
446
-
447
- ## Notes
310
+ ## License
448
311
 
449
- - Node `18+` is required
450
- - Yahoo downloads are cached under `output/data` by default
451
- - CommonJS and ESM are both supported
452
- - Live adapters support broker execution workflows, but this is still not an exchange microstructure simulator
312
+ MIT
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { startStdioServer } from "../src/mcp/server.js";
3
+
4
+ startStdioServer().catch((error) => {
5
+ console.error("tradelab-mcp failed to start:", error);
6
+ process.exit(1);
7
+ });