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/types/index.d.ts CHANGED
@@ -132,6 +132,14 @@ export interface SideBreakdownEntry {
132
132
  avgR: number;
133
133
  }
134
134
 
135
+ export interface BenchmarkStats {
136
+ alpha: number | null;
137
+ beta: number | null;
138
+ correlation: number | null;
139
+ informationRatio: number | null;
140
+ trackingError: number | null;
141
+ }
142
+
135
143
  /** Aggregate performance metrics returned by `backtest()`. */
136
144
  export interface BacktestMetrics {
137
145
  /** Count of completed positions included in the aggregate metrics. */
@@ -146,6 +154,12 @@ export interface BacktestMetrics {
146
154
  avgR: number;
147
155
  /** Daily Sharpe ratio alias for quick access. */
148
156
  sharpe: number;
157
+ /** Annualized Sharpe ratio derived from the configured interval or bar spacing. */
158
+ sharpeAnnualized: number;
159
+ /** Annualized Sortino ratio derived from the configured interval or bar spacing. */
160
+ sortinoAnnualized: number;
161
+ /** Number of periods per year used for annualized metrics. */
162
+ annualizationPeriods: number;
149
163
  sharpePerTrade: number;
150
164
  sortinoPerTrade: number;
151
165
  /** Maximum drawdown percent alias. */
@@ -169,6 +183,7 @@ export interface BacktestMetrics {
169
183
  /** Daily Sharpe ratio computed from realized equity changes. */
170
184
  sharpeDaily: number;
171
185
  sortinoDaily: number;
186
+ benchmark: BenchmarkStats;
172
187
  /** Long/short breakdown grouped by completed position side. */
173
188
  sideBreakdown: {
174
189
  long: SideBreakdownEntry;
@@ -659,6 +674,7 @@ export function optimize(options: {
659
674
  export function backtestPortfolio(options: {
660
675
  systems: PortfolioSystem[];
661
676
  equity?: number;
677
+ interval?: string;
662
678
  allocation?: "equal" | "weight";
663
679
  collectEqSeries?: boolean;
664
680
  collectReplay?: boolean;
@@ -684,7 +700,16 @@ export function buildMetrics(input: {
684
700
  candles: Candle[];
685
701
  estBarMs: number;
686
702
  eqSeries?: EquityPoint[];
703
+ interval?: string;
704
+ benchmarkReturns?: number[];
687
705
  }): BacktestMetrics;
706
+ export function benchmarkStats(
707
+ strategyReturns: number[],
708
+ benchmarkReturns: number[]
709
+ ): BenchmarkStats;
710
+ export function clampFinite(value: unknown, fallback?: number): number;
711
+ export const BIG_NUMBER: number;
712
+ export function periodsPerYear(interval?: string, estBarMs?: number): number;
688
713
 
689
714
  export class LlmSignal {
690
715
  constructor(options: LlmSignalOptions);
package/types/live.d.ts CHANGED
@@ -84,6 +84,8 @@ export interface StoredState {
84
84
  savedAt: number;
85
85
  }
86
86
 
87
+ export const LIVE_EVENTS: string[];
88
+
87
89
  export class EventBus extends import("node:events").EventEmitter {
88
90
  emitEvent(event: string, payload?: Record<string, unknown>): true;
89
91
  onAny(handler: (input: { event: string; payload: Record<string, unknown> }) => void): () => void;
@@ -339,7 +341,8 @@ export interface DashboardServer {
339
341
  export function createDashboardServer(options: {
340
342
  source: {
341
343
  eventBus: EventBus;
342
- getStatus?: () => Record<string, unknown>;
344
+ getStatus?: () => unknown;
345
+ refresh?: () => Promise<unknown>;
343
346
  };
344
347
  port?: number;
345
348
  maxBuffer?: number;
@@ -395,3 +398,101 @@ export function createLiveOrchestrator(options: {
395
398
  }): LiveOrchestrator;
396
399
 
397
400
  export type { SignalResult };
401
+
402
+ // ── TradingSession / SessionManager ──────────────────────────────────────────
403
+
404
+ export interface TradingSessionOptions {
405
+ id?: string;
406
+ symbol: string;
407
+ interval?: string;
408
+ broker: BrokerAdapter;
409
+ mode?: "paper" | "live";
410
+ equity?: number;
411
+ riskPct?: number;
412
+ maxDailyLossPct?: number;
413
+ maxPositionPct?: number;
414
+ qtyStep?: number;
415
+ minQty?: number;
416
+ maxLeverage?: number;
417
+ eventBus?: EventBus;
418
+ confirmLive?: boolean;
419
+ }
420
+
421
+ export interface SessionPlaceOrderOptions {
422
+ side: "long" | "short" | "buy" | "sell";
423
+ type?: "market" | "limit" | "stop" | "stop_limit";
424
+ qty?: number;
425
+ riskPct?: number;
426
+ stop?: number;
427
+ target?: number;
428
+ rr?: number;
429
+ limitPrice?: number;
430
+ }
431
+
432
+ export interface SessionStatus {
433
+ id: string;
434
+ symbol: string;
435
+ interval: string;
436
+ mode: "paper" | "live";
437
+ running: boolean;
438
+ equity: number;
439
+ dayPnl: number;
440
+ lastPrice: number | null;
441
+ positions: BrokerPosition[];
442
+ openOrders: OrderReceipt[];
443
+ risk: {
444
+ halted: boolean;
445
+ haltReason: string | null;
446
+ dayPnl: number;
447
+ dayTrades: number;
448
+ [key: string]: unknown;
449
+ };
450
+ }
451
+
452
+ export class TradingSession {
453
+ constructor(options: TradingSessionOptions);
454
+ readonly id: string;
455
+ readonly symbol: string;
456
+ readonly interval: string;
457
+ readonly mode: "paper" | "live";
458
+ readonly eventBus: EventBus;
459
+ equity: number;
460
+ lastPrice: number | null;
461
+ running: boolean;
462
+ candleBuffer: import("./index.d.ts").Candle[];
463
+ static liveAllowed(): boolean;
464
+ start(): Promise<void>;
465
+ stop(options?: { flatten?: boolean }): Promise<void>;
466
+ pushBar(bar: import("./index.d.ts").Candle): Promise<void>;
467
+ placeOrder(options: SessionPlaceOrderOptions): Promise<OrderReceipt>;
468
+ closePosition(symbol?: string): Promise<OrderReceipt | null>;
469
+ flatten(): Promise<void>;
470
+ cancelOrder(orderId: string): Promise<void>;
471
+ getAccount(): Promise<AccountInfo>;
472
+ getPositions(): Promise<BrokerPosition[]>;
473
+ recentEvents(limit?: number): Array<{ event: string; payload: unknown; t: number }>;
474
+ getStatus(): SessionStatus;
475
+ refresh(): Promise<SessionStatus>;
476
+ }
477
+
478
+ export interface SessionManagerOptions {
479
+ brokerFactory?: (options: Record<string, unknown>) => BrokerAdapter;
480
+ }
481
+
482
+ export interface CreateSessionOptions extends Partial<TradingSessionOptions> {
483
+ id: string;
484
+ symbol: string;
485
+ confirmLive?: boolean;
486
+ broker?: BrokerAdapter;
487
+ }
488
+
489
+ export class SessionManager {
490
+ constructor(options?: SessionManagerOptions);
491
+ create(options: CreateSessionOptions): Promise<TradingSession>;
492
+ get(id: string): TradingSession | null;
493
+ list(): TradingSession[];
494
+ remove(id: string, options?: { flatten?: boolean }): Promise<void>;
495
+ haltAll(): Promise<void>;
496
+ }
497
+
498
+ export function createSessionManager(options?: SessionManagerOptions): SessionManager;
package/types/mcp.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { SessionManager } from "./live.d.ts";
3
+
4
+ export function createServer(): McpServer;
5
+ export function startStdioServer(): Promise<McpServer>;
6
+
7
+ export interface McpToolHandler {
8
+ description: string;
9
+ handler(args: Record<string, unknown>): Promise<unknown>;
10
+ }
11
+
12
+ export const mcpTools: Record<string, McpToolHandler>;
13
+ export const researchTools: Record<string, McpToolHandler>;
14
+ export const liveTools: Record<string, McpToolHandler>;
15
+
16
+ /** The shared SessionManager instance used by the MCP server process. */
17
+ export const sessionManager: SessionManager;
@@ -1,101 +0,0 @@
1
- # tradelab 2026 Roadmap — Overview & Sequencing
2
-
3
- > **For agentic workers:** Each subsystem below has its own plan file. Use
4
- > `superpowers:subagent-driven-development` (recommended) or
5
- > `superpowers:executing-plans` to implement one plan at a time, task-by-task.
6
- > All step lists use checkbox (`- [ ]`) syntax for tracking.
7
-
8
- **Goal:** Turn tradelab from a strong single-run backtester into an AI-native,
9
- statistically-defensible research + execution platform for quants, simple
10
- traders, and autonomous agents.
11
-
12
- ---
13
-
14
- ## The 8 subsystems
15
-
16
- | # | Plan file | What it delivers | Depends on |
17
- | --- | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ----------- |
18
- | 1 | [2026-01-metrics-correctness.md](2026-01-metrics-correctness.md) | Annualized Sharpe/Sortino, finite-clamped metrics JSON, benchmark alpha/beta/IR | — |
19
- | 2 | [2026-02-indicator-library.md](2026-02-indicator-library.md) | `tradelab/ta` namespace: RSI, MACD, Bollinger, VWAP, Supertrend, Donchian, Keltner, stochastics | — |
20
- | 3 | [2026-03-overfitting-toolkit.md](2026-03-overfitting-toolkit.md) | CPCV, PBO, Deflated Sharpe, Monte Carlo bands, sweep haircut | 1 |
21
- | 4 | [2026-04-async-signals-seeding.md](2026-04-async-signals-seeding.md) | `async signal()` with per-bar budget + cache + no-lookahead guard, `LlmSignal`, configurable RNG seed | — |
22
- | 5 | [2026-05-mcp-server.md](2026-05-mcp-server.md) | `tradelab/mcp` server exposing data/backtest/walk-forward/metrics as agent tools | 1, 4 (soft) |
23
- | 6 | [2026-06-parallel-param-sweep.md](2026-06-parallel-param-sweep.md) | Worker-pool param sweep + `optimize()` API | — |
24
- | 7 | [2026-07-funding-carry-costs.md](2026-07-funding-carry-costs.md) | Funding/borrow/overnight carry in the cost model | — |
25
- | 8 | [2026-08-live-dashboard.md](2026-08-live-dashboard.md) | Local realtime dashboard for `LiveEngine`/`LiveOrchestrator` | — |
26
-
27
- ### Dependency graph
28
-
29
- ```
30
- 1 metrics ──► 3 overfitting
31
- 1 metrics ──► 5 mcp (soft: nicer tool output)
32
- 4 async ────► 5 mcp (soft: agent-driven backtests)
33
- 2, 6, 7, 8 are independent
34
- ```
35
-
36
- ### Recommended execution order
37
-
38
- 1. **Plan 1 (metrics)** — small, corrects existing bugs, unblocks 3 and 5.
39
- 2. **Plan 2 (indicators)** — independent, high user value, unblocks NL strategies later.
40
- 3. **Plan 4 (async signals + seed)** — engine change; do before MCP so agents can drive live.
41
- 4. **Plan 5 (MCP)** — the 2026 headline; sits on top of 1 + 4.
42
- 5. **Plan 3 (overfitting)** — the quant moat; needs clean metrics.
43
- 6. **Plans 6, 7, 8** — parallelizable, any order.
44
-
45
- ---
46
-
47
- ## Shared conventions (all plans assume these)
48
-
49
- **Runtime:** Node `>=18`, ESM (`"type": "module"`). No transpile step for `src/`.
50
- The CJS build is generated by `npm run build` (esbuild) from `src/`.
51
-
52
- **Tests:** `node:test` + `node:assert/strict`. Run a single file with:
53
-
54
- ```bash
55
- node --test test/<name>.test.js
56
- ```
57
-
58
- Run everything with `npm test` (`node --test`). New test files live under `test/`
59
- mirroring `src/` layout (e.g. `src/metrics/finite.js` → `test/metrics/finite.test.js`).
60
- There is no test runner config — discovery is by filename.
61
-
62
- **Lint/format before commit:**
63
-
64
- ```bash
65
- npm run lint
66
- npm run format:check
67
- ```
68
-
69
- **Commit style:** match existing history — `feat:`, `fix:`, `docs:`, `perf:`,
70
- `test:`. Every commit message MUST end with the trailer:
71
-
72
- ```
73
- Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
74
- ```
75
-
76
- **Public exports:** add new top-level exports in [src/index.js](../../../src/index.js).
77
- New subpath entrypoints (`tradelab/ta`, `tradelab/mcp`) require an entry in the
78
- `exports` map of [package.json](../../../package.json) AND a matching CJS bundle
79
- in [scripts/build-cjs.mjs](../../../scripts/build-cjs.mjs).
80
-
81
- **Canonical result shape (do not break it):** every engine returns
82
- `{ symbol, interval, range, trades, positions, openPositions, metrics, eqSeries, replay }`.
83
- `buildMetrics` is the single source of truth for `metrics`. Plans that add metrics
84
- fields ADD keys; they never rename or remove existing ones (dashboards depend on them).
85
-
86
- **The signal contract (do not break it):** `signal(context)` receives
87
- `{ candles, index, bar, equity, openPosition, pendingOrder }` and returns `null`
88
- or `{ side, entry?, stop, rr|takeProfit, ... }`. Two engines call it independently:
89
- the standalone loop in [src/engine/backtest.js](../../../src/engine/backtest.js) and
90
- the shared [src/engine/barSystemRunner.js](../../../src/engine/barSystemRunner.js)
91
- (used by portfolio). The live path uses
92
- [src/live/engine/liveEngine.js](../../../src/live/engine/liveEngine.js). Plan 4
93
- touches all three call sites.
94
-
95
- ---
96
-
97
- ## Out of scope for this roadmap
98
-
99
- - Natural-language → signal compiler (separate spec; depends on Plan 2 + a strategy schema).
100
- - New broker adapters / options / fundamentals data sources.
101
- - L2 microstructure simulator.