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.
- package/CHANGELOG.md +57 -0
- package/README.md +183 -373
- package/dist/cjs/index.cjs +39 -12
- package/dist/cjs/live.cjs +457 -18
- package/docs/README.md +32 -66
- package/docs/api-reference.md +269 -144
- package/docs/backtest-engine.md +167 -321
- package/docs/data-reporting-cli.md +114 -156
- package/docs/examples.md +6 -6
- package/docs/live-trading.md +254 -134
- package/docs/mcp.md +244 -23
- package/docs/research.md +99 -45
- package/examples/mcpLiveTrading.js +77 -0
- package/package.json +11 -3
- package/src/engine/optimize.js +25 -1
- package/src/engine/portfolio.js +6 -2
- package/src/live/dashboard/server.js +67 -8
- package/src/live/engine/paperEngine.js +21 -11
- package/src/live/index.js +2 -0
- package/src/live/session.js +439 -0
- package/src/mcp/liveTools.js +202 -0
- package/src/mcp/schemas.js +119 -0
- package/src/mcp/server.js +5 -1
- package/src/mcp/tools.js +125 -2
- package/src/research/monteCarlo.js +6 -2
- package/templates/dashboard.html +595 -108
- package/types/index.d.ts +25 -0
- package/types/live.d.ts +102 -1
- package/types/mcp.d.ts +17 -0
- package/docs/superpowers/plans/2026-00-overview.md +0 -101
- package/docs/superpowers/plans/2026-01-metrics-correctness.md +0 -873
- package/docs/superpowers/plans/2026-02-indicator-library.md +0 -677
- package/docs/superpowers/plans/2026-03-overfitting-toolkit.md +0 -882
- package/docs/superpowers/plans/2026-04-async-signals-seeding.md +0 -981
- package/docs/superpowers/plans/2026-05-mcp-server.md +0 -758
- package/docs/superpowers/plans/2026-06-parallel-param-sweep.md +0 -508
- package/docs/superpowers/plans/2026-07-funding-carry-costs.md +0 -535
- package/docs/superpowers/plans/2026-08-live-dashboard.md +0 -547
- package/docs/superpowers/plans/HANDOFF.md +0 -88
package/docs/live-trading.md
CHANGED
|
@@ -1,54 +1,42 @@
|
|
|
1
|
-
# Live trading
|
|
1
|
+
# Live and paper trading
|
|
2
2
|
|
|
3
|
-
<small>[Back to
|
|
3
|
+
<small>[Back to docs](README.md)</small>
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Use `tradelab/live` when you want the same strategy contract from `backtest()` to run against a paper broker or a broker adapter.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The live module is intentionally small:
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
- persist state with `JsonFileStorage` for restart safety
|
|
15
|
-
|
|
16
|
-
Import path:
|
|
9
|
+
- a signal receives finalized candles and returns the same order intent used in backtests
|
|
10
|
+
- a broker adapter handles account, order, fill, and position operations
|
|
11
|
+
- a feed provides bars or ticks
|
|
12
|
+
- storage persists state so a process restart can recover cleanly
|
|
13
|
+
- risk controls can block new orders or halt a system
|
|
17
14
|
|
|
18
15
|
```js
|
|
19
|
-
import { LiveEngine,
|
|
16
|
+
import { LiveEngine, PaperEngine, JsonFileStorage } from "tradelab/live";
|
|
20
17
|
```
|
|
21
18
|
|
|
22
|
-
##
|
|
23
|
-
|
|
24
|
-
| Component | Purpose |
|
|
25
|
-
| -------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
|
|
26
|
-
| `LiveEngine` | Single-system live or paper execution loop |
|
|
27
|
-
| `LiveOrchestrator` | Multi-system live execution with shared broker and aggregated status |
|
|
28
|
-
| `PaperEngine` | In-process broker simulator implementing the broker adapter contract |
|
|
29
|
-
| `AlpacaBroker` / `BinanceBroker` / `CoinbaseBroker` / `InteractiveBrokersBroker` | Real broker adapters |
|
|
30
|
-
| `BrokerFeed` / `PollingFeed` | Feed adapters for streaming or polling operation |
|
|
31
|
-
| `RiskManager` | Session windows, daily loss gates, drawdown halts, position checks |
|
|
32
|
-
| `StateManager` / `JsonFileStorage` | Persisted state, trades, and equity curve |
|
|
33
|
-
| `EventBus` / `LiveLogger` | Event fanout and structured logging |
|
|
34
|
-
|
|
35
|
-
## `LiveEngine` quick start
|
|
19
|
+
## Start With Paper Mode
|
|
36
20
|
|
|
37
21
|
```js
|
|
38
22
|
import { LiveEngine, PaperEngine, JsonFileStorage } from "tradelab/live";
|
|
39
23
|
|
|
24
|
+
const broker = new PaperEngine({ equity: 25_000 });
|
|
25
|
+
|
|
40
26
|
const engine = new LiveEngine({
|
|
41
|
-
id: "aapl-
|
|
27
|
+
id: "aapl-paper",
|
|
42
28
|
symbol: "AAPL",
|
|
43
29
|
interval: "1m",
|
|
44
|
-
broker
|
|
30
|
+
broker,
|
|
45
31
|
storage: new JsonFileStorage({ baseDir: "./output/live-state" }),
|
|
32
|
+
mode: "polling",
|
|
46
33
|
riskPct: 1,
|
|
47
|
-
mode: "streaming",
|
|
48
34
|
signal({ bar, openPosition }) {
|
|
49
35
|
if (openPosition) return null;
|
|
36
|
+
|
|
50
37
|
return {
|
|
51
38
|
side: "long",
|
|
39
|
+
entry: bar.close,
|
|
52
40
|
stop: bar.close - 1,
|
|
53
41
|
rr: 2,
|
|
54
42
|
};
|
|
@@ -56,43 +44,116 @@ const engine = new LiveEngine({
|
|
|
56
44
|
});
|
|
57
45
|
|
|
58
46
|
await engine.start();
|
|
59
|
-
|
|
47
|
+
await engine.pollOnce();
|
|
48
|
+
console.log(engine.getStatus());
|
|
60
49
|
await engine.stop();
|
|
61
50
|
```
|
|
62
51
|
|
|
63
|
-
|
|
52
|
+
`PaperEngine` implements the broker interface in memory. Use it first for CLI runs, dashboard checks, and strategy wiring. Market orders need a price reference, so call `pushBar()`, `simulateBar()`, or the MCP `feed_price` tool before submitting one.
|
|
53
|
+
|
|
54
|
+
## Signal Contract
|
|
55
|
+
|
|
56
|
+
The signal function receives:
|
|
57
|
+
|
|
58
|
+
| Field | Meaning |
|
|
59
|
+
| -------------- | ---------------------------------------------- |
|
|
60
|
+
| `candles` | Finalized candle history available at this bar |
|
|
61
|
+
| `index` | Current candle index |
|
|
62
|
+
| `bar` | Current candle |
|
|
63
|
+
| `equity` | Current engine equity |
|
|
64
|
+
| `openPosition` | Current open position, or `null` |
|
|
65
|
+
| `pendingOrder` | Current pending entry order, or `null` |
|
|
66
|
+
|
|
67
|
+
Return `null` to do nothing. Return an order intent to open a trade:
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
return {
|
|
71
|
+
side: "long",
|
|
72
|
+
entry: bar.close,
|
|
73
|
+
stop: bar.close * 0.98,
|
|
74
|
+
rr: 2,
|
|
75
|
+
riskPct: 0.5,
|
|
76
|
+
};
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Useful fields:
|
|
80
|
+
|
|
81
|
+
| Field | Meaning |
|
|
82
|
+
| -------------------- | -------------------------------------------- |
|
|
83
|
+
| `side` | `"long"`, `"short"`, `"buy"`, or `"sell"` |
|
|
84
|
+
| `entry` | Planned entry price |
|
|
85
|
+
| `stop` | Stop loss price |
|
|
86
|
+
| `takeProfit` or `rr` | Explicit target, or reward/risk multiple |
|
|
87
|
+
| `qty` | Fixed quantity. If omitted, sizing uses risk |
|
|
88
|
+
| `riskPct` | Percent of equity to risk on this trade |
|
|
89
|
+
| `_maxBarsInTrade` | Force an exit after this many completed bars |
|
|
90
|
+
| `_maxHoldMin` | Force an exit after this many minutes |
|
|
91
|
+
|
|
92
|
+
Use `backtest()` or `backtestAsync()` with the same signal before connecting a real broker.
|
|
93
|
+
|
|
94
|
+
## Run From The CLI
|
|
95
|
+
|
|
96
|
+
The CLI has two entry points:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
tradelab paper --symbol AAPL --interval 1m --mode polling --once true
|
|
100
|
+
tradelab live --symbol AAPL --interval 1m --broker alpaca --paper
|
|
101
|
+
```
|
|
64
102
|
|
|
65
|
-
|
|
66
|
-
- `signal()` may be async; `LiveEngine` awaits the decision before normalizing it
|
|
67
|
-
- market and limit/stop order lifecycles are tracked through broker events
|
|
68
|
-
- state is persisted after fills, order updates, and equity updates
|
|
69
|
-
- `getStatus()` returns runtime and risk state for health checks
|
|
103
|
+
Common options:
|
|
70
104
|
|
|
71
|
-
|
|
105
|
+
| Option | Meaning |
|
|
106
|
+
| ----------------- | --------------------------------------------- |
|
|
107
|
+
| `--strategy` | Built-in strategy name or local strategy file |
|
|
108
|
+
| `--symbol` | Symbol passed to broker and feed |
|
|
109
|
+
| `--interval` | Candle interval, such as `1m`, `5m`, or `1d` |
|
|
110
|
+
| `--mode` | `streaming` or `polling` |
|
|
111
|
+
| `--once true` | Run one polling cycle and exit |
|
|
112
|
+
| `--stateDir` | Directory for persisted live state |
|
|
113
|
+
| `--dashboard` | Start the local dashboard |
|
|
114
|
+
| `--dashboardPort` | Dashboard port. Defaults to `4317` |
|
|
115
|
+
|
|
116
|
+
Strategy modules can export `default`, `createSignal(args)`, or `signal`:
|
|
72
117
|
|
|
73
118
|
```js
|
|
74
|
-
|
|
119
|
+
// ./strategies/ema-signal.js
|
|
120
|
+
import { ema } from "tradelab";
|
|
121
|
+
|
|
122
|
+
export function createSignal({ fast = 10, slow = 30, rr = 2 } = {}) {
|
|
123
|
+
return ({ candles, bar }) => {
|
|
124
|
+
if (candles.length < slow + 2) return null;
|
|
125
|
+
|
|
126
|
+
const closes = candles.map((candle) => candle.close);
|
|
127
|
+
const fastLine = ema(closes, Number(fast));
|
|
128
|
+
const slowLine = ema(closes, Number(slow));
|
|
129
|
+
const last = closes.length - 1;
|
|
130
|
+
|
|
131
|
+
if (fastLine[last - 1] <= slowLine[last - 1] && fastLine[last] > slowLine[last]) {
|
|
132
|
+
return {
|
|
133
|
+
side: "long",
|
|
134
|
+
entry: bar.close,
|
|
135
|
+
stop: Math.min(...candles.slice(-15).map((candle) => candle.low)),
|
|
136
|
+
rr: Number(rr),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
75
139
|
|
|
76
|
-
const llm = new LlmSignal({
|
|
77
|
-
budgetMs: 2000,
|
|
78
|
-
onError: "skip",
|
|
79
|
-
async resolve(context) {
|
|
80
|
-
// Call a model or agent here.
|
|
81
140
|
return null;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
```
|
|
84
144
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
145
|
+
```bash
|
|
146
|
+
tradelab paper \
|
|
147
|
+
--strategy ./strategies/ema-signal.js \
|
|
148
|
+
--symbol AAPL \
|
|
149
|
+
--interval 1m \
|
|
150
|
+
--mode polling \
|
|
151
|
+
--once true
|
|
91
152
|
```
|
|
92
153
|
|
|
93
|
-
|
|
154
|
+
## Run Multiple Systems
|
|
94
155
|
|
|
95
|
-
|
|
156
|
+
Use `LiveOrchestrator` when several systems share one account and broker.
|
|
96
157
|
|
|
97
158
|
```js
|
|
98
159
|
import { LiveOrchestrator, PaperEngine, JsonFileStorage } from "tradelab/live";
|
|
@@ -102,136 +163,195 @@ const orchestrator = new LiveOrchestrator({
|
|
|
102
163
|
storage: new JsonFileStorage({ baseDir: "./output/live-state" }),
|
|
103
164
|
allocation: "weight",
|
|
104
165
|
systems: [
|
|
105
|
-
{ id: "spy", symbol: "SPY", interval: "1m", weight: 2, signal:
|
|
106
|
-
{ id: "qqq", symbol: "QQQ", interval: "1m", weight: 1, signal:
|
|
166
|
+
{ id: "spy", symbol: "SPY", interval: "1m", weight: 2, signal: spySignal },
|
|
167
|
+
{ id: "qqq", symbol: "QQQ", interval: "1m", weight: 1, signal: qqqSignal },
|
|
107
168
|
],
|
|
108
169
|
});
|
|
109
170
|
|
|
110
171
|
await orchestrator.start();
|
|
111
|
-
|
|
172
|
+
console.log(orchestrator.getStatus());
|
|
112
173
|
await orchestrator.stop();
|
|
113
174
|
```
|
|
114
175
|
|
|
115
|
-
|
|
176
|
+
CLI config:
|
|
116
177
|
|
|
117
|
-
|
|
178
|
+
```json
|
|
179
|
+
{
|
|
180
|
+
"allocation": "weight",
|
|
181
|
+
"equity": 50000,
|
|
182
|
+
"systems": [
|
|
183
|
+
{
|
|
184
|
+
"id": "spy-system",
|
|
185
|
+
"symbol": "SPY",
|
|
186
|
+
"interval": "1m",
|
|
187
|
+
"strategy": "./strategies/spy.js",
|
|
188
|
+
"weight": 2
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"id": "qqq-system",
|
|
192
|
+
"symbol": "QQQ",
|
|
193
|
+
"interval": "1m",
|
|
194
|
+
"strategy": "./strategies/qqq.js",
|
|
195
|
+
"weight": 1
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
}
|
|
199
|
+
```
|
|
118
200
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
| `tradelab paper` | Shortcut for `live` with paper broker mode |
|
|
123
|
-
| `tradelab status` | Inspect persisted live state |
|
|
201
|
+
```bash
|
|
202
|
+
tradelab live --config ./live-portfolio.json --paper --mode polling --once true
|
|
203
|
+
```
|
|
124
204
|
|
|
125
|
-
##
|
|
205
|
+
## Dashboard
|
|
126
206
|
|
|
127
|
-
|
|
207
|
+
Start a local dashboard for an engine or orchestrator:
|
|
128
208
|
|
|
129
209
|
```js
|
|
130
210
|
import { createDashboardServer } from "tradelab/live";
|
|
131
211
|
|
|
132
212
|
const dashboard = createDashboardServer({ source: engine, port: 4317 });
|
|
133
213
|
const url = await dashboard.start();
|
|
134
|
-
console.log(`dashboard: ${url}`);
|
|
135
214
|
|
|
136
|
-
|
|
215
|
+
console.log(url);
|
|
216
|
+
|
|
217
|
+
// On shutdown:
|
|
137
218
|
await dashboard.close();
|
|
138
219
|
```
|
|
139
220
|
|
|
140
|
-
The
|
|
221
|
+
The dashboard is a zero-dependency dark trading cockpit served from a single HTML file. It includes:
|
|
141
222
|
|
|
142
|
-
|
|
223
|
+
- **KPI strip** - equity, day P&L (with percent), open position, last price, all in monospace tabular numerals
|
|
224
|
+
- **Equity curve** - canvas chart that grows in real time; green when above session start, red when below
|
|
225
|
+
- **Positions table** - symbol, side badge, qty, entry, mark, unrealized P&L
|
|
226
|
+
- **Open orders table** - type, side, qty, price, with inline cancel
|
|
227
|
+
- **Event feed** - color-coded by severity (fill, exit/warning, reject) with animated entry; capped at 120 rows
|
|
228
|
+
- **Risk-halt banner** - shown when `source.getStatus().risk.halted` is true
|
|
229
|
+
- **Controls** - Stop and Flatten All buttons in the header; cancel links in the orders table
|
|
143
230
|
|
|
144
|
-
|
|
145
|
-
tradelab paper --symbol AAPL --interval 1m --mode polling --dashboard --dashboardPort 4317
|
|
146
|
-
tradelab live --config ./live-portfolio.json --paper --dashboard --dashboardPort 4317
|
|
147
|
-
```
|
|
231
|
+
The dashboard exposes:
|
|
148
232
|
|
|
149
|
-
|
|
233
|
+
| Route | Method | Purpose |
|
|
234
|
+
| ---------- | ------ | ------------------------------------------------------------- |
|
|
235
|
+
| `/` | GET | Static dashboard page |
|
|
236
|
+
| `/state` | GET | Calls optional `source.refresh()`, then returns `getStatus()` |
|
|
237
|
+
| `/events` | GET | Server-Sent Events stream from `eventBus` |
|
|
238
|
+
| `/command` | POST | Dispatch a command to the source (whitelist enforced) |
|
|
150
239
|
|
|
151
|
-
###
|
|
240
|
+
### `/command` endpoint
|
|
152
241
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
242
|
+
Send a JSON body with a `type` field. Only the following types are accepted; anything else returns `400`:
|
|
243
|
+
|
|
244
|
+
| type | Source method called |
|
|
245
|
+
| --------------- | ---------------------------------- |
|
|
246
|
+
| `flatten` | `source.flatten()` |
|
|
247
|
+
| `stop` | `source.stop()` |
|
|
248
|
+
| `closePosition` | `source.closePosition(cmd.symbol)` |
|
|
249
|
+
| `cancelOrder` | `source.cancelOrder(cmd.orderId)` |
|
|
250
|
+
|
|
251
|
+
```js
|
|
252
|
+
// Example: flatten all positions from a browser
|
|
253
|
+
await fetch("/command", {
|
|
254
|
+
method: "POST",
|
|
255
|
+
headers: { "Content-Type": "application/json" },
|
|
256
|
+
body: JSON.stringify({ type: "flatten" }),
|
|
257
|
+
});
|
|
161
258
|
```
|
|
162
259
|
|
|
163
|
-
###
|
|
260
|
+
### `source.refresh()`
|
|
261
|
+
|
|
262
|
+
If the source object exposes a `refresh()` method, the dashboard awaits it before each `/state` response. Use this to pull fresh data from a broker before painting the UI - for example, a `TradingSession` from the MCP live tools can expose `refresh()` to sync account state before every poll.
|
|
263
|
+
|
|
264
|
+
CLI:
|
|
164
265
|
|
|
165
266
|
```bash
|
|
166
|
-
tradelab
|
|
167
|
-
|
|
168
|
-
--paper \
|
|
169
|
-
--mode polling \
|
|
170
|
-
--once true \
|
|
171
|
-
--stateDir ./output/live-state
|
|
267
|
+
tradelab paper --symbol AAPL --interval 1m --mode polling --dashboard --dashboardPort 4317
|
|
268
|
+
tradelab live --config ./live-portfolio.json --paper --dashboard --dashboardPort 4317
|
|
172
269
|
```
|
|
173
270
|
|
|
174
|
-
|
|
271
|
+
New browser clients receive a bounded replay of recent events. The equity curve grows from the first data point seen in the session; the chart updates on every `equity:update` SSE event and on each `/state` poll.
|
|
175
272
|
|
|
176
|
-
|
|
177
|
-
{
|
|
178
|
-
"allocation": "weight",
|
|
179
|
-
"equity": 50000,
|
|
180
|
-
"systems": [
|
|
181
|
-
{
|
|
182
|
-
"id": "spy-system",
|
|
183
|
-
"symbol": "SPY",
|
|
184
|
-
"interval": "1m",
|
|
185
|
-
"strategy": "./strategies/spySignal.js",
|
|
186
|
-
"weight": 2
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
"id": "qqq-system",
|
|
190
|
-
"symbol": "QQQ",
|
|
191
|
-
"interval": "1m",
|
|
192
|
-
"strategy": "./strategies/qqqSignal.js",
|
|
193
|
-
"weight": 1
|
|
194
|
-
}
|
|
195
|
-
]
|
|
196
|
-
}
|
|
197
|
-
```
|
|
273
|
+
## State And Recovery
|
|
198
274
|
|
|
199
|
-
|
|
275
|
+
`JsonFileStorage` stores one namespace per engine id:
|
|
276
|
+
|
|
277
|
+
| File | Contents |
|
|
278
|
+
| -------------- | ----------------------------------------- |
|
|
279
|
+
| `state.json` | Latest open position, pending order, risk |
|
|
280
|
+
| `trades.jsonl` | Append-only completed trade records |
|
|
281
|
+
| `equity.jsonl` | Append-only equity snapshots |
|
|
282
|
+
|
|
283
|
+
Inspect persisted state:
|
|
200
284
|
|
|
201
285
|
```bash
|
|
202
286
|
tradelab status --dir ./output/live-state
|
|
203
287
|
tradelab status --dir ./output/live-state --namespace spy-system
|
|
204
288
|
```
|
|
205
289
|
|
|
206
|
-
|
|
290
|
+
On restart, `StateManager` compares persisted state with broker positions and reports whether the state is clean, externally closed, adopted from broker state, or mismatched.
|
|
207
291
|
|
|
208
|
-
|
|
292
|
+
## Risk Controls
|
|
209
293
|
|
|
210
|
-
- `
|
|
211
|
-
- `trades.jsonl` (append-only)
|
|
212
|
-
- `equity.jsonl` (append-only)
|
|
294
|
+
Pass top-level risk options to `LiveEngine`, or group them under `risk`.
|
|
213
295
|
|
|
214
|
-
|
|
296
|
+
```js
|
|
297
|
+
const engine = new LiveEngine({
|
|
298
|
+
symbol: "AAPL",
|
|
299
|
+
interval: "1m",
|
|
300
|
+
broker,
|
|
301
|
+
signal,
|
|
302
|
+
riskPct: 0.5,
|
|
303
|
+
risk: {
|
|
304
|
+
maxDailyLossPct: 2,
|
|
305
|
+
maxDrawdownPct: 10,
|
|
306
|
+
maxPositions: 1,
|
|
307
|
+
maxDailyTrades: 4,
|
|
308
|
+
allowedWindows: "09:30-11:30,13:00-15:45",
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
```
|
|
215
312
|
|
|
216
|
-
|
|
313
|
+
The risk manager can block new positions and emit warning or halt events. It does not silently change your signal logic.
|
|
217
314
|
|
|
218
|
-
|
|
219
|
-
- Coinbase adapter is live API only; use `PaperEngine` for simulated Coinbase workflows.
|
|
220
|
-
- Interactive Brokers adapter requires `@stoqey/ib` to be installed.
|
|
315
|
+
## Broker Notes
|
|
221
316
|
|
|
222
|
-
|
|
317
|
+
| Broker | Notes |
|
|
318
|
+
| -------------------------- | -------------------------------------------------------- |
|
|
319
|
+
| `PaperEngine` | Local simulation. Best first step for any new strategy |
|
|
320
|
+
| `AlpacaBroker` | Supports native paper mode through broker config |
|
|
321
|
+
| `BinanceBroker` | Supports exchange-style crypto workflows |
|
|
322
|
+
| `CoinbaseBroker` | Live API adapter. Use `PaperEngine` for local simulation |
|
|
323
|
+
| `InteractiveBrokersBroker` | Requires `@stoqey/ib` in the consuming application |
|
|
223
324
|
|
|
224
|
-
|
|
325
|
+
Real broker adapters require credentials and broker-specific account permissions. Start with paper mode, then use the smallest possible order sizes when switching to live credentials.
|
|
225
326
|
|
|
226
|
-
|
|
327
|
+
## Events
|
|
227
328
|
|
|
228
|
-
|
|
329
|
+
`EventBus` emits lifecycle, order, position, equity, and risk events:
|
|
330
|
+
|
|
331
|
+
- `connected`
|
|
332
|
+
- `shutdown`
|
|
229
333
|
- `signal`
|
|
230
|
-
- `order:submitted
|
|
231
|
-
- `
|
|
334
|
+
- `order:submitted`
|
|
335
|
+
- `order:filled`
|
|
336
|
+
- `order:rejected`
|
|
337
|
+
- `order:canceled`
|
|
338
|
+
- `position:opened`
|
|
339
|
+
- `position:closed`
|
|
232
340
|
- `equity:update`
|
|
233
|
-
- `risk:warning
|
|
341
|
+
- `risk:warning`
|
|
342
|
+
- `risk:halt`
|
|
343
|
+
|
|
344
|
+
Attach `LiveLogger` to write structured JSON event logs.
|
|
345
|
+
|
|
346
|
+
```js
|
|
347
|
+
import { createEventBus, createLogger } from "tradelab/live";
|
|
348
|
+
|
|
349
|
+
const eventBus = createEventBus();
|
|
350
|
+
const logger = createLogger({ level: "info" });
|
|
351
|
+
|
|
352
|
+
logger.attach(eventBus);
|
|
353
|
+
```
|
|
234
354
|
|
|
235
|
-
|
|
355
|
+
See [api-reference.md](api-reference.md#live-module-tradelablive) for the full live export list.
|
|
236
356
|
|
|
237
|
-
<small>[Back to
|
|
357
|
+
<small>[Back to docs](README.md)</small>
|