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
@@ -1,35 +1,16 @@
1
- # Data, reporting, and CLI
1
+ # Data, Reporting, and CLI
2
2
 
3
- <small>[Back to main page](README.md)</small>
3
+ This guide covers data loading, local caches, report exports, and the `tradelab` command.
4
4
 
5
- This page covers the parts of the package around the core engine:
5
+ [Back to docs](README.md)
6
6
 
7
- - historical data loading
8
- - local cache helpers
9
- - export helpers
10
- - command-line usage for backtest and live workflows
7
+ ## Data Loading
11
8
 
12
- ## Overview
13
-
14
- If you are not bringing your own candles yet, start here.
15
-
16
- ## Choose the right entry point
17
-
18
- | Use case | Function |
19
- | --------------------------------------------------------- | ------------------------ |
20
- | Load data without caring about the source-specific helper | `getHistoricalCandles()` |
21
- | Fetch directly from Yahoo | `fetchHistorical()` |
22
- | Load a local CSV file | `loadCandlesFromCSV()` |
23
- | Reuse saved normalized data | `loadCandlesFromCache()` |
24
- | Try the package from a terminal first | `tradelab` CLI |
25
-
26
- ## Historical data
27
-
28
- ### `getHistoricalCandles(options)`
29
-
30
- This is the main data-loading entry point.
9
+ Most workflows should start with `getHistoricalCandles()`.
31
10
 
32
11
  ```js
12
+ import { getHistoricalCandles } from "tradelab";
13
+
33
14
  const candles = await getHistoricalCandles({
34
15
  source: "yahoo",
35
16
  symbol: "SPY",
@@ -39,159 +20,139 @@ const candles = await getHistoricalCandles({
39
20
  });
40
21
  ```
41
22
 
42
- ### Sources
43
-
44
- - `yahoo`
45
- - `csv`
46
- - `auto`
47
-
48
- `auto` switches to CSV when `csvPath` or `csv.filePath` is present. Otherwise it uses Yahoo.
23
+ It returns normalized candles:
49
24
 
50
- If you are writing application code, prefer `getHistoricalCandles()` over calling source-specific helpers directly.
51
-
52
- ### Yahoo options
53
-
54
- | Option | Purpose |
55
- | ---------------- | ----------------------------------------------------- |
56
- | `symbol` | Ticker or Yahoo symbol |
57
- | `interval` | Candle interval such as `1d` or `5m` |
58
- | `period` | Lookback period such as `6mo` or `1y` |
59
- | `includePrePost` | Includes premarket and postmarket data when supported |
60
- | `cache` | Reuses saved normalized data |
61
- | `refresh` | Forces a fresh download even if cache exists |
62
- | `cacheDir` | Overrides the default cache directory |
25
+ ```js
26
+ {
27
+ (time, open, high, low, close, volume);
28
+ }
29
+ ```
63
30
 
64
- The Yahoo layer retries transient failures with exponential backoff. If the endpoint still fails, the error message points users toward CSV or cached data.
31
+ ## Sources
65
32
 
66
- Use caching for repeatable research runs. It reduces network noise and makes failures easier to diagnose.
33
+ | Source | Use it when... |
34
+ | ------- | --------------------------------------------------- |
35
+ | `yahoo` | You want quick market data by symbol |
36
+ | `csv` | You already have a file on disk |
37
+ | `auto` | You want CSV when `csvPath` exists, otherwise Yahoo |
67
38
 
68
- ### CSV options
39
+ ### Yahoo
69
40
 
70
41
  ```js
71
42
  const candles = await getHistoricalCandles({
72
- source: "csv",
73
- csvPath: "./data/spy.csv",
74
- csv: {
75
- timeCol: "timestamp",
76
- openCol: "open",
77
- highCol: "high",
78
- lowCol: "low",
79
- closeCol: "close",
80
- volumeCol: "volume",
81
- },
43
+ source: "yahoo",
44
+ symbol: "QQQ",
45
+ interval: "1d",
46
+ period: "1y",
47
+ cache: true,
48
+ refresh: false,
82
49
  });
83
50
  ```
84
51
 
85
- CSV parsing can be configured with:
86
-
87
- - delimiter
88
- - header presence
89
- - column names or indexes
90
- - start/end date filters
91
- - custom date parsing
92
-
93
- If your CSV already uses common OHLCV column names, you often do not need to pass any mapping at all.
52
+ Common options:
94
53
 
95
- ## Cache helpers
54
+ | Option | Meaning |
55
+ | ---------------- | --------------------------------------------------------------- |
56
+ | `symbol` | Yahoo symbol |
57
+ | `interval` | `1m`, `5m`, `1d`, `1wk`, and other Yahoo intervals |
58
+ | `period` | `5d`, `60d`, `6mo`, `1y`, `2y`, and similar |
59
+ | `includePrePost` | Include premarket and postmarket candles if Yahoo provides them |
60
+ | `cache` | Reuse a saved normalized file |
61
+ | `refresh` | Download again even if a cache file exists |
62
+ | `cacheDir` | Change where cache files are stored |
96
63
 
97
- Available helpers:
64
+ The Yahoo helper retries transient failures. If Yahoo is unavailable, use a cached run or switch to CSV for repeatable tests.
98
65
 
99
- - `saveCandlesToCache(candles, meta)`
100
- - `loadCandlesFromCache(symbol, interval, period, outDir)`
101
- - `cachedCandlesPath(symbol, interval, period, outDir)`
102
-
103
- The cache is just normalized candle JSON on disk. It is meant for research convenience, not as a durable database layer.
104
-
105
- ## Common workflows
106
-
107
- ### Yahoo to backtest
66
+ ### CSV
108
67
 
109
68
  ```js
110
69
  const candles = await getHistoricalCandles({
111
- source: "yahoo",
112
- symbol: "SPY",
113
- interval: "1d",
114
- period: "1y",
115
- cache: true,
70
+ source: "csv",
71
+ csvPath: "./data/spy.csv",
116
72
  });
117
73
  ```
118
74
 
119
- ### CSV to backtest
75
+ If your headers use common OHLCV names, no mapping is needed. For custom files, pass column names or indexes:
120
76
 
121
77
  ```js
122
78
  const candles = await getHistoricalCandles({
123
79
  source: "csv",
124
80
  csvPath: "./data/spy.csv",
81
+ csv: {
82
+ timeCol: "timestamp",
83
+ openCol: "open_price",
84
+ highCol: "high_price",
85
+ lowCol: "low_price",
86
+ closeCol: "close_price",
87
+ volumeCol: "volume",
88
+ delimiter: ",",
89
+ },
125
90
  });
126
91
  ```
127
92
 
128
- ### Cached repeat run
93
+ ## Cache Helpers
94
+
95
+ The cache is normalized candle JSON on disk. It is useful for repeatable research runs and CI fixtures. It is not a database.
129
96
 
130
97
  ```js
131
- const candles = await getHistoricalCandles({
132
- source: "yahoo",
98
+ import { saveCandlesToCache, loadCandlesFromCache, cachedCandlesPath } from "tradelab";
99
+
100
+ const path = saveCandlesToCache(candles, {
133
101
  symbol: "SPY",
134
102
  interval: "1d",
135
103
  period: "1y",
136
- cache: true,
137
- refresh: false,
138
104
  });
139
- ```
140
105
 
141
- ## Reporting and exports
142
-
143
- ### `exportBacktestArtifacts({ result, outDir })`
144
-
145
- The main bundle export. By default it writes:
106
+ const cached = loadCandlesFromCache("SPY", "1d", "1y");
107
+ ```
146
108
 
147
- - HTML report
148
- - trade CSV
149
- - metrics JSON
109
+ ## Reporting
150
110
 
151
- Return value:
111
+ ### Write All Artifacts
152
112
 
153
- <!-- prettier-ignore -->
154
113
  ```js
155
- { csv, html, metrics }
156
- ```
114
+ import { exportBacktestArtifacts } from "tradelab";
157
115
 
158
- If you only need one output type, call the narrower helper directly.
159
-
160
- ### `exportMetricsJSON({ result, outDir })`
161
-
162
- Use this for dashboards, notebooks, or any machine-readable downstream pipeline.
116
+ const files = exportBacktestArtifacts({
117
+ result,
118
+ outDir: "./output",
119
+ });
163
120
 
164
- For automation, this is usually the best export format to build on.
121
+ console.log(files);
122
+ ```
165
123
 
166
- ### `exportTradesCsv(trades, options)`
124
+ Return shape:
167
125
 
168
- Use this when you want a flat trade ledger for spreadsheets or pandas-style workflows.
126
+ ```js
127
+ {
128
+ (html, csv, metrics);
129
+ }
130
+ ```
169
131
 
170
- ### `renderHtmlReport(options)` and `exportHtmlReport(options)`
132
+ ### Export Only What You Need
171
133
 
172
- - `renderHtmlReport()` returns an HTML string
173
- - `exportHtmlReport()` writes the file and returns its path
134
+ | Helper | Output |
135
+ | ---------------------------------- | ----------------- |
136
+ | `exportMetricsJSON(options)` | Metrics JSON |
137
+ | `exportTradesCsv(trades, options)` | Flat trade ledger |
138
+ | `renderHtmlReport(options)` | HTML string |
139
+ | `exportHtmlReport(options)` | HTML file path |
174
140
 
175
- The report system uses the assets under `templates/`. The renderer injects the payload and keeps markup, CSS, and client script separate from the JS entrypoint.
141
+ Use metrics JSON for notebooks, dashboards, or downstream jobs. Use trade CSV for spreadsheet review. Use HTML when a human needs to inspect the run.
176
142
 
177
143
  ## CLI
178
144
 
179
- The package ships with a `tradelab` binary.
145
+ The package installs two binaries:
180
146
 
181
- The CLI is best for quick iteration, smoke tests, and trying the package before building a JS workflow around it.
147
+ - `tradelab`
148
+ - `tradelab-mcp`
182
149
 
183
- ## Commands
150
+ Use `tradelab` when you want a quick command-line run before writing application code.
184
151
 
185
- | Command | Purpose |
186
- | ----------------------- | ------------------------------------------------------------------------- |
187
- | `tradelab backtest` | Run a single backtest from Yahoo or CSV |
188
- | `tradelab portfolio` | Run a simple multi-file portfolio backtest |
189
- | `tradelab walk-forward` | Run rolling or anchored validation with built-in or local strategy search |
190
- | `tradelab live` | Run live engine or orchestrator mode |
191
- | `tradelab paper` | Run live engine in paper broker mode |
192
- | `tradelab status` | Inspect persisted live namespace state |
193
- | `tradelab prefetch` | Download and cache Yahoo data |
194
- | `tradelab import-csv` | Normalize and cache a CSV file |
152
+ ```bash
153
+ tradelab --version
154
+ tradelab help
155
+ ```
195
156
 
196
157
  ### Backtest
197
158
 
@@ -200,19 +161,17 @@ tradelab backtest --source yahoo --symbol SPY --interval 1d --period 1y
200
161
  tradelab backtest --source csv --csvPath ./data/btc.csv --strategy buy-hold --holdBars 3
201
162
  ```
202
163
 
203
- Built-in strategies:
164
+ Built-in CLI strategies:
204
165
 
205
166
  - `ema-cross`
206
167
  - `buy-hold`
207
168
 
208
- You can also point `--strategy` at a local module. The module should export one of:
169
+ Local strategy modules can export one of:
209
170
 
210
171
  - `default(args)`
211
172
  - `createSignal(args)`
212
173
  - `signal`
213
174
 
214
- That makes it easy to prototype a strategy file before wiring it into a larger application.
215
-
216
175
  ### Portfolio
217
176
 
218
177
  ```bash
@@ -222,9 +181,9 @@ tradelab portfolio \
222
181
  --strategy buy-hold
223
182
  ```
224
183
 
225
- This command is intentionally simple. Use it for quick combined runs, not for custom portfolio logic.
184
+ The CLI portfolio command is intentionally compact. Use the JavaScript API when you need per-system options or custom signal wiring.
226
185
 
227
- ### Walk-forward
186
+ ### Walk-Forward
228
187
 
229
188
  ```bash
230
189
  tradelab walk-forward \
@@ -237,9 +196,9 @@ tradelab walk-forward \
237
196
  --mode anchored
238
197
  ```
239
198
 
240
- The CLI walk-forward command defaults to the built-in `ema-cross` search, but `--strategy ./path/to/module.mjs` can now load a local module that exports `signalFactory(params, args)` and either `parameterSets` or `createParameterSets(args)`. Inline JSON grids are also accepted through `--parameterSets`.
199
+ You can pass `--strategy ./strategy.mjs` for local modules that export `signalFactory(params, args)` and either `parameterSets` or `createParameterSets(args)`.
241
200
 
242
- ### Live and paper
201
+ ### Live and Paper
243
202
 
244
203
  ```bash
245
204
  tradelab paper --symbol AAPL --interval 1m --mode polling --once true
@@ -249,36 +208,35 @@ tradelab live \
249
208
  --symbol AAPL \
250
209
  --interval 1m \
251
210
  --broker alpaca \
252
- --apiKey $APCA_KEY \
253
- --apiSecret $APCA_SECRET
254
-
255
- tradelab live --config ./live-portfolio.json --paper --mode polling --once true
211
+ --apiKey "$APCA_KEY" \
212
+ --apiSecret "$APCA_SECRET"
256
213
  ```
257
214
 
258
- For full runtime details, see [live-trading.md](live-trading.md).
215
+ Use a config file for multi-system live runs:
216
+
217
+ ```bash
218
+ tradelab live --config ./live-portfolio.json --paper --mode polling
219
+ ```
259
220
 
260
- ### Status
221
+ Add a dashboard:
261
222
 
262
223
  ```bash
263
- tradelab status --dir ./output/live-state
264
- tradelab status --dir ./output/live-state --namespace my-system
224
+ tradelab paper --symbol AAPL --interval 1m --dashboard --dashboardPort 4317
265
225
  ```
266
226
 
267
- ### Cache utilities
227
+ ### State
268
228
 
269
229
  ```bash
270
- tradelab prefetch --symbol SPY --interval 1d --period 1y
271
- tradelab import-csv --csvPath ./data/spy.csv --symbol SPY --interval 1d
230
+ tradelab status --dir ./output/live-state
231
+ tradelab status --dir ./output/live-state --namespace aapl-1m
272
232
  ```
273
233
 
274
- ## Troubleshooting
234
+ State commands read persisted JSON from `JsonFileStorage`; they do not connect to a broker.
235
+
236
+ ## MCP Binary
237
+
238
+ `tradelab-mcp` starts the stdio MCP server. Most users run it through an MCP client config rather than typing it directly.
275
239
 
276
- | Problem | Check first |
277
- | ---------------------- | ---------------------------------------------------------------------- |
278
- | Yahoo request errors | enable cache, retry later, or fall back to CSV |
279
- | Unexpected trade count | `warmupBars`, `flattenAtClose`, and signal frequency |
280
- | Empty result | candle order, signal logic, and stop/target validity |
281
- | Confusing CSV import | inspect normalized bars from `loadCandlesFromCSV()` before backtesting |
282
- | Export confusion | use metrics JSON first if you need programmatic output |
240
+ See [MCP server](mcp.md).
283
241
 
284
- <small>[Back to main page](README.md)</small>
242
+ [Back to docs](README.md)
package/docs/examples.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Strategy examples
2
2
 
3
- <small>[Back to main page](README.md)</small>
3
+ <small>[Back to docs](README.md)</small>
4
4
 
5
5
  These are research templates. They show how to wire different kinds of data and execution assumptions into the engine without changing the output pipeline.
6
6
 
@@ -9,7 +9,7 @@ The five examples cover:
9
9
  - single-symbol price research
10
10
  - tick-level fills
11
11
  - external feature overlays
12
- - model-derived regime filters with walk-forward validation
12
+ - precomputed regime filters with walk-forward validation
13
13
  - portfolio research with shared capital
14
14
 
15
15
  ---
@@ -157,7 +157,7 @@ The same pattern works for any precomputed field - regime labels, macro scores,
157
157
 
158
158
  ## 4. Precomputed regime filter with anchored walk-forward
159
159
 
160
- LLM or model outputs work best as precomputed fields, not as live callers inside the signal function. Call the model once per bar outside the engine, store the result on the candle, then run a normal walk-forward on top of it.
160
+ Regime labels work best as precomputed fields, not as slow callers inside the signal function. Build the label once per bar outside the engine, store the result on the candle, then run walk-forward validation on top of it.
161
161
 
162
162
  ```js
163
163
  import { walkForwardOptimize, getHistoricalCandles, ema } from "tradelab";
@@ -169,7 +169,7 @@ const candles = await getHistoricalCandles({
169
169
  period: "3y",
170
170
  });
171
171
 
172
- // call model outside the engine - keep signal() synchronous
172
+ // build labels outside the engine - keep signal() synchronous
173
173
  const labeled = await Promise.all(
174
174
  candles.map(async (bar, index) => ({
175
175
  ...bar,
@@ -220,7 +220,7 @@ const wf = walkForwardOptimize({
220
220
  });
221
221
  ```
222
222
 
223
- Check `wf.bestParamsSummary` for parameter stability across windows. If the winning regime or EMA pair changes every window, the model output probably is not adding signal.
223
+ Check `wf.bestParamsSummary` for parameter stability across windows. If the winning regime or EMA pair changes every window, the label probably is not adding durable signal.
224
224
 
225
225
  ---
226
226
 
@@ -272,4 +272,4 @@ const result = backtestPortfolio({
272
272
 
273
273
  `result.eqSeries` includes `lockedCapital` and `availableCapital` at each realized equity point. Use those to see how often the portfolio was fully deployed versus sitting partially idle.
274
274
 
275
- <small>[Back to main page](README.md)</small>
275
+ <small>[Back to docs](README.md)</small>