openbroker 1.3.2 → 1.4.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.
- package/CHANGELOG.md +12 -0
- package/dist/auto/audit.d.ts +57 -0
- package/dist/auto/audit.d.ts.map +1 -0
- package/dist/auto/audit.js +407 -0
- package/dist/auto/cli.d.ts +2 -0
- package/dist/auto/cli.d.ts.map +1 -0
- package/dist/auto/cli.js +423 -0
- package/dist/auto/events.d.ts +11 -0
- package/dist/auto/events.d.ts.map +1 -0
- package/dist/auto/events.js +36 -0
- package/dist/auto/examples/dca.d.ts +4 -0
- package/dist/auto/examples/dca.d.ts.map +1 -0
- package/dist/auto/examples/dca.js +60 -0
- package/dist/auto/examples/funding-arb.d.ts +4 -0
- package/dist/auto/examples/funding-arb.d.ts.map +1 -0
- package/dist/auto/examples/funding-arb.js +81 -0
- package/dist/auto/examples/grid.d.ts +4 -0
- package/dist/auto/examples/grid.d.ts.map +1 -0
- package/dist/auto/examples/grid.js +114 -0
- package/dist/auto/examples/mm-maker.d.ts +4 -0
- package/dist/auto/examples/mm-maker.d.ts.map +1 -0
- package/dist/auto/examples/mm-maker.js +131 -0
- package/dist/auto/examples/mm-spread.d.ts +4 -0
- package/dist/auto/examples/mm-spread.d.ts.map +1 -0
- package/dist/auto/examples/mm-spread.js +119 -0
- package/dist/auto/examples/price-alert.d.ts +4 -0
- package/dist/auto/examples/price-alert.d.ts.map +1 -0
- package/dist/auto/examples/price-alert.js +85 -0
- package/dist/auto/keep-awake.d.ts +11 -0
- package/dist/auto/keep-awake.d.ts.map +1 -0
- package/dist/auto/keep-awake.js +70 -0
- package/dist/auto/loader.d.ts +22 -0
- package/dist/auto/loader.d.ts.map +1 -0
- package/dist/auto/loader.js +127 -0
- package/dist/auto/prune.d.ts +40 -0
- package/dist/auto/prune.d.ts.map +1 -0
- package/dist/auto/prune.js +204 -0
- package/dist/auto/registry.d.ts +24 -0
- package/dist/auto/registry.d.ts.map +1 -0
- package/dist/auto/registry.js +93 -0
- package/dist/auto/report.d.ts +3 -0
- package/dist/auto/report.d.ts.map +1 -0
- package/dist/auto/report.js +385 -0
- package/dist/auto/runtime.d.ts +33 -0
- package/dist/auto/runtime.d.ts.map +1 -0
- package/dist/auto/runtime.js +844 -0
- package/dist/auto/types.d.ts +236 -0
- package/dist/auto/types.d.ts.map +1 -0
- package/dist/auto/types.js +3 -0
- package/dist/core/client.d.ts +684 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +2040 -0
- package/dist/core/config.d.ts +22 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +143 -0
- package/dist/core/types.d.ts +221 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/utils.d.ts +61 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/core/utils.js +142 -0
- package/dist/core/ws.d.ts +121 -0
- package/dist/core/ws.d.ts.map +1 -0
- package/dist/core/ws.js +222 -0
- package/dist/info/account.d.ts +3 -0
- package/dist/info/account.d.ts.map +1 -0
- package/dist/info/account.js +198 -0
- package/dist/info/all-markets.d.ts +3 -0
- package/dist/info/all-markets.d.ts.map +1 -0
- package/dist/info/all-markets.js +272 -0
- package/dist/info/candles.d.ts +3 -0
- package/dist/info/candles.d.ts.map +1 -0
- package/dist/info/candles.js +120 -0
- package/dist/info/fees.d.ts +3 -0
- package/dist/info/fees.d.ts.map +1 -0
- package/dist/info/fees.js +87 -0
- package/dist/info/fills.d.ts +3 -0
- package/dist/info/fills.d.ts.map +1 -0
- package/dist/info/fills.js +105 -0
- package/dist/info/funding-history.d.ts +3 -0
- package/dist/info/funding-history.d.ts.map +1 -0
- package/dist/info/funding-history.js +98 -0
- package/dist/info/funding-scan.d.ts +3 -0
- package/dist/info/funding-scan.d.ts.map +1 -0
- package/dist/info/funding-scan.js +178 -0
- package/dist/info/funding.d.ts +3 -0
- package/dist/info/funding.d.ts.map +1 -0
- package/dist/info/funding.js +158 -0
- package/dist/info/markets.d.ts +3 -0
- package/dist/info/markets.d.ts.map +1 -0
- package/dist/info/markets.js +178 -0
- package/dist/info/order-status.d.ts +3 -0
- package/dist/info/order-status.d.ts.map +1 -0
- package/dist/info/order-status.js +85 -0
- package/dist/info/orders.d.ts +3 -0
- package/dist/info/orders.d.ts.map +1 -0
- package/dist/info/orders.js +162 -0
- package/dist/info/outcomes.d.ts +3 -0
- package/dist/info/outcomes.d.ts.map +1 -0
- package/dist/info/outcomes.js +175 -0
- package/dist/info/positions.d.ts +3 -0
- package/dist/info/positions.d.ts.map +1 -0
- package/dist/info/positions.js +127 -0
- package/dist/info/rate-limit.d.ts +3 -0
- package/dist/info/rate-limit.d.ts.map +1 -0
- package/dist/info/rate-limit.js +58 -0
- package/dist/info/search-markets.d.ts +3 -0
- package/dist/info/search-markets.d.ts.map +1 -0
- package/dist/info/search-markets.js +296 -0
- package/dist/info/spot.d.ts +3 -0
- package/dist/info/spot.d.ts.map +1 -0
- package/dist/info/spot.js +192 -0
- package/dist/info/trades.d.ts +3 -0
- package/dist/info/trades.d.ts.map +1 -0
- package/dist/info/trades.js +97 -0
- package/dist/lib.d.ts +14 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +17 -0
- package/dist/operations/bracket.d.ts +28 -0
- package/dist/operations/bracket.d.ts.map +1 -0
- package/dist/operations/bracket.js +266 -0
- package/dist/operations/cancel.d.ts +3 -0
- package/dist/operations/cancel.d.ts.map +1 -0
- package/dist/operations/cancel.js +107 -0
- package/dist/operations/chase.d.ts +25 -0
- package/dist/operations/chase.d.ts.map +1 -0
- package/dist/operations/chase.js +215 -0
- package/dist/operations/limit-order.d.ts +3 -0
- package/dist/operations/limit-order.d.ts.map +1 -0
- package/dist/operations/limit-order.js +144 -0
- package/dist/operations/market-order.d.ts +3 -0
- package/dist/operations/market-order.d.ts.map +1 -0
- package/dist/operations/market-order.js +153 -0
- package/dist/operations/outcome-order.d.ts +3 -0
- package/dist/operations/outcome-order.d.ts.map +1 -0
- package/dist/operations/outcome-order.js +171 -0
- package/dist/operations/scale.d.ts +3 -0
- package/dist/operations/scale.d.ts.map +1 -0
- package/dist/operations/scale.js +212 -0
- package/dist/operations/set-tpsl.d.ts +3 -0
- package/dist/operations/set-tpsl.d.ts.map +1 -0
- package/dist/operations/set-tpsl.js +277 -0
- package/dist/operations/spot-order.d.ts +3 -0
- package/dist/operations/spot-order.d.ts.map +1 -0
- package/dist/operations/spot-order.js +173 -0
- package/dist/operations/trigger-order.d.ts +3 -0
- package/dist/operations/trigger-order.d.ts.map +1 -0
- package/dist/operations/trigger-order.js +177 -0
- package/dist/operations/twap-cancel.d.ts +3 -0
- package/dist/operations/twap-cancel.d.ts.map +1 -0
- package/dist/operations/twap-cancel.js +57 -0
- package/dist/operations/twap-status.d.ts +3 -0
- package/dist/operations/twap-status.d.ts.map +1 -0
- package/dist/operations/twap-status.js +81 -0
- package/dist/operations/twap.d.ts +3 -0
- package/dist/operations/twap.d.ts.map +1 -0
- package/dist/operations/twap.js +124 -0
- package/dist/setup/approve-builder.d.ts +3 -0
- package/dist/setup/approve-builder.d.ts.map +1 -0
- package/dist/setup/approve-builder.js +155 -0
- package/dist/setup/env.d.ts +4 -0
- package/dist/setup/env.d.ts.map +1 -0
- package/dist/setup/env.js +8 -0
- package/dist/setup/onboard.d.ts +10 -0
- package/dist/setup/onboard.d.ts.map +1 -0
- package/dist/setup/onboard.js +462 -0
- package/package.json +10 -4
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
3
|
+
import { AUDIT_DB_PATH } from './audit.js';
|
|
4
|
+
import { formatUsd, parseArgs } from '../core/utils.js';
|
|
5
|
+
const DEFAULT_WATCH_INTERVAL_MS = 2000;
|
|
6
|
+
function printUsage() {
|
|
7
|
+
console.log(`
|
|
8
|
+
Usage: openbroker auto report <id> [options]
|
|
9
|
+
|
|
10
|
+
Options:
|
|
11
|
+
--run <run-id|latest> Specific run ID to inspect (default: latest)
|
|
12
|
+
--limit <n> Number of recent rows per section (default: 10)
|
|
13
|
+
--watch Refresh the report continuously
|
|
14
|
+
--watch-interval <ms> Refresh interval for --watch (default: 2000)
|
|
15
|
+
--json Output JSON
|
|
16
|
+
--help, -h Show this help
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
openbroker auto report hype-mm-v2-live-r4
|
|
20
|
+
openbroker auto report hype-mm-v2-live-r4 --limit 20
|
|
21
|
+
openbroker auto report hype-mm-v2-live-r4 --watch
|
|
22
|
+
openbroker auto report hype-mm-v2-live-r4 --run 123e4567... --json
|
|
23
|
+
`);
|
|
24
|
+
}
|
|
25
|
+
function parseJson(value) {
|
|
26
|
+
if (!value)
|
|
27
|
+
return null;
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(value);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function parseNumber(raw, fallback) {
|
|
36
|
+
const parsed = Number(raw);
|
|
37
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
38
|
+
}
|
|
39
|
+
function formatTimestamp(timestamp) {
|
|
40
|
+
return timestamp ? new Date(timestamp).toLocaleString() : '-';
|
|
41
|
+
}
|
|
42
|
+
function formatDurationMs(startedAt, stoppedAt) {
|
|
43
|
+
const end = stoppedAt ?? Date.now();
|
|
44
|
+
const totalSeconds = Math.max(0, Math.round((end - startedAt) / 1000));
|
|
45
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
46
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
47
|
+
const seconds = totalSeconds % 60;
|
|
48
|
+
if (hours > 0)
|
|
49
|
+
return `${hours}h ${minutes}m ${seconds}s`;
|
|
50
|
+
if (minutes > 0)
|
|
51
|
+
return `${minutes}m ${seconds}s`;
|
|
52
|
+
return `${seconds}s`;
|
|
53
|
+
}
|
|
54
|
+
function getPositionalArgs(rawArgs) {
|
|
55
|
+
return rawArgs.filter((arg, index) => {
|
|
56
|
+
if (arg.startsWith('--'))
|
|
57
|
+
return false;
|
|
58
|
+
if (index > 0 && rawArgs[index - 1]?.startsWith('--'))
|
|
59
|
+
return false;
|
|
60
|
+
return true;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function loadReport(db, automationId, runSelector, limit) {
|
|
64
|
+
const run = runSelector !== 'latest'
|
|
65
|
+
? db.prepare(`
|
|
66
|
+
SELECT *
|
|
67
|
+
FROM automation_runs
|
|
68
|
+
WHERE automation_id = ? AND run_id = ?
|
|
69
|
+
LIMIT 1
|
|
70
|
+
`).get(automationId, runSelector)
|
|
71
|
+
: db.prepare(`
|
|
72
|
+
SELECT *
|
|
73
|
+
FROM automation_runs
|
|
74
|
+
WHERE automation_id = ?
|
|
75
|
+
ORDER BY started_at DESC
|
|
76
|
+
LIMIT 1
|
|
77
|
+
`).get(automationId);
|
|
78
|
+
if (!run) {
|
|
79
|
+
throw new Error(`No audit run found for automation "${automationId}"${runSelector !== 'latest' ? ` and run "${runSelector}"` : ''}`);
|
|
80
|
+
}
|
|
81
|
+
const countTables = {
|
|
82
|
+
logs: 'automation_logs',
|
|
83
|
+
events: 'automation_events',
|
|
84
|
+
actions: 'automation_actions',
|
|
85
|
+
snapshots: 'automation_snapshots',
|
|
86
|
+
orderUpdates: 'automation_order_updates',
|
|
87
|
+
fills: 'automation_fills',
|
|
88
|
+
userEvents: 'automation_user_events',
|
|
89
|
+
stateChanges: 'automation_state_changes',
|
|
90
|
+
publishes: 'automation_publishes',
|
|
91
|
+
errors: 'automation_errors',
|
|
92
|
+
notes: 'automation_notes',
|
|
93
|
+
metrics: 'automation_metrics',
|
|
94
|
+
};
|
|
95
|
+
const counts = Object.fromEntries(Object.entries(countTables).map(([key, table]) => {
|
|
96
|
+
const row = db.prepare(`SELECT count(*) AS c FROM ${table} WHERE run_id = ?`).get(run.run_id);
|
|
97
|
+
return [key, row.c];
|
|
98
|
+
}));
|
|
99
|
+
const fillSummary = db.prepare(`
|
|
100
|
+
SELECT
|
|
101
|
+
count(*) AS count,
|
|
102
|
+
COALESCE(sum(fee), 0) AS total_fee,
|
|
103
|
+
COALESCE(sum(closed_pnl), 0) AS total_closed_pnl,
|
|
104
|
+
COALESCE(sum(size * price), 0) AS total_volume
|
|
105
|
+
FROM automation_fills
|
|
106
|
+
WHERE run_id = ?
|
|
107
|
+
`).get(run.run_id);
|
|
108
|
+
const firstSnapshot = db.prepare(`
|
|
109
|
+
SELECT timestamp, poll_count, equity, margin_used, margin_used_pct, positions_json
|
|
110
|
+
FROM automation_snapshots
|
|
111
|
+
WHERE run_id = ?
|
|
112
|
+
ORDER BY timestamp ASC
|
|
113
|
+
LIMIT 1
|
|
114
|
+
`).get(run.run_id);
|
|
115
|
+
const latestSnapshot = db.prepare(`
|
|
116
|
+
SELECT timestamp, poll_count, equity, margin_used, margin_used_pct, positions_json
|
|
117
|
+
FROM automation_snapshots
|
|
118
|
+
WHERE run_id = ?
|
|
119
|
+
ORDER BY timestamp DESC
|
|
120
|
+
LIMIT 1
|
|
121
|
+
`).get(run.run_id);
|
|
122
|
+
const actionBreakdown = db.prepare(`
|
|
123
|
+
SELECT
|
|
124
|
+
method,
|
|
125
|
+
sum(CASE WHEN phase = 'request' THEN 1 ELSE 0 END) AS requests,
|
|
126
|
+
sum(CASE WHEN phase = 'response' THEN 1 ELSE 0 END) AS responses,
|
|
127
|
+
sum(CASE WHEN phase = 'error' THEN 1 ELSE 0 END) AS errors
|
|
128
|
+
FROM automation_actions
|
|
129
|
+
WHERE run_id = ?
|
|
130
|
+
GROUP BY method
|
|
131
|
+
ORDER BY requests DESC, responses DESC, errors DESC, method ASC
|
|
132
|
+
`).all(run.run_id);
|
|
133
|
+
const recentLogs = db.prepare(`
|
|
134
|
+
SELECT timestamp, level, message
|
|
135
|
+
FROM automation_logs
|
|
136
|
+
WHERE run_id = ?
|
|
137
|
+
ORDER BY timestamp DESC
|
|
138
|
+
LIMIT ?
|
|
139
|
+
`).all(run.run_id, limit);
|
|
140
|
+
const recentErrors = db.prepare(`
|
|
141
|
+
SELECT timestamp, stage, error_json
|
|
142
|
+
FROM automation_errors
|
|
143
|
+
WHERE run_id = ?
|
|
144
|
+
ORDER BY timestamp DESC
|
|
145
|
+
LIMIT ?
|
|
146
|
+
`).all(run.run_id, limit);
|
|
147
|
+
const recentFills = db.prepare(`
|
|
148
|
+
SELECT timestamp, coin, side, size, price, fee, closed_pnl
|
|
149
|
+
FROM automation_fills
|
|
150
|
+
WHERE run_id = ?
|
|
151
|
+
ORDER BY timestamp DESC
|
|
152
|
+
LIMIT ?
|
|
153
|
+
`).all(run.run_id, limit);
|
|
154
|
+
const recentOrderUpdates = db.prepare(`
|
|
155
|
+
SELECT timestamp, coin, side, size, price, status, oid
|
|
156
|
+
FROM automation_order_updates
|
|
157
|
+
WHERE run_id = ?
|
|
158
|
+
ORDER BY timestamp DESC
|
|
159
|
+
LIMIT ?
|
|
160
|
+
`).all(run.run_id, limit);
|
|
161
|
+
const recentNotes = db.prepare(`
|
|
162
|
+
SELECT timestamp, kind, payload_json
|
|
163
|
+
FROM automation_notes
|
|
164
|
+
WHERE run_id = ?
|
|
165
|
+
ORDER BY timestamp DESC
|
|
166
|
+
LIMIT ?
|
|
167
|
+
`).all(run.run_id, limit);
|
|
168
|
+
const recentMetrics = db.prepare(`
|
|
169
|
+
SELECT timestamp, name, value, tags_json
|
|
170
|
+
FROM automation_metrics
|
|
171
|
+
WHERE run_id = ?
|
|
172
|
+
ORDER BY timestamp DESC
|
|
173
|
+
LIMIT ?
|
|
174
|
+
`).all(run.run_id, limit);
|
|
175
|
+
const report = {
|
|
176
|
+
automationId: run.automation_id,
|
|
177
|
+
runId: run.run_id,
|
|
178
|
+
status: run.status,
|
|
179
|
+
stopReason: run.stop_reason,
|
|
180
|
+
scriptPath: run.script_path,
|
|
181
|
+
startedAt: new Date(run.started_at).toISOString(),
|
|
182
|
+
stoppedAt: run.stopped_at ? new Date(run.stopped_at).toISOString() : null,
|
|
183
|
+
durationSec: Math.max(0, Math.round(((run.stopped_at ?? Date.now()) - run.started_at) / 1000)),
|
|
184
|
+
accountAddress: run.account_address,
|
|
185
|
+
walletAddress: run.wallet_address,
|
|
186
|
+
dryRun: run.dry_run === 1,
|
|
187
|
+
verbose: run.verbose === 1,
|
|
188
|
+
useWebSocket: run.use_websocket === 1,
|
|
189
|
+
pollIntervalMs: run.poll_interval_ms,
|
|
190
|
+
pid: run.pid,
|
|
191
|
+
initialState: parseJson(run.initial_state_json),
|
|
192
|
+
persistedState: parseJson(run.persisted_state_json),
|
|
193
|
+
runtimeStats: {
|
|
194
|
+
pollCount: run.poll_count,
|
|
195
|
+
eventsEmitted: run.events_emitted,
|
|
196
|
+
},
|
|
197
|
+
counts,
|
|
198
|
+
fills: {
|
|
199
|
+
count: fillSummary.count,
|
|
200
|
+
totalFees: fillSummary.total_fee,
|
|
201
|
+
totalClosedPnl: fillSummary.total_closed_pnl,
|
|
202
|
+
netAfterFees: fillSummary.total_closed_pnl - fillSummary.total_fee,
|
|
203
|
+
totalVolume: fillSummary.total_volume,
|
|
204
|
+
},
|
|
205
|
+
equity: {
|
|
206
|
+
first: firstSnapshot ? {
|
|
207
|
+
timestamp: firstSnapshot.timestamp,
|
|
208
|
+
pollCount: firstSnapshot.poll_count,
|
|
209
|
+
equity: firstSnapshot.equity,
|
|
210
|
+
marginUsed: firstSnapshot.margin_used,
|
|
211
|
+
marginUsedPct: firstSnapshot.margin_used_pct,
|
|
212
|
+
positions: parseJson(firstSnapshot.positions_json),
|
|
213
|
+
} : null,
|
|
214
|
+
latest: latestSnapshot ? {
|
|
215
|
+
timestamp: latestSnapshot.timestamp,
|
|
216
|
+
pollCount: latestSnapshot.poll_count,
|
|
217
|
+
equity: latestSnapshot.equity,
|
|
218
|
+
marginUsed: latestSnapshot.margin_used,
|
|
219
|
+
marginUsedPct: latestSnapshot.margin_used_pct,
|
|
220
|
+
positions: parseJson(latestSnapshot.positions_json),
|
|
221
|
+
} : null,
|
|
222
|
+
delta: firstSnapshot && latestSnapshot
|
|
223
|
+
? Number(latestSnapshot.equity) - Number(firstSnapshot.equity)
|
|
224
|
+
: null,
|
|
225
|
+
},
|
|
226
|
+
actionBreakdown,
|
|
227
|
+
recent: {
|
|
228
|
+
logs: recentLogs,
|
|
229
|
+
errors: recentErrors.map((row) => ({
|
|
230
|
+
...row,
|
|
231
|
+
error: parseJson(row.error_json),
|
|
232
|
+
})),
|
|
233
|
+
fills: recentFills,
|
|
234
|
+
orderUpdates: recentOrderUpdates,
|
|
235
|
+
notes: recentNotes.map((row) => ({
|
|
236
|
+
...row,
|
|
237
|
+
payload: parseJson(row.payload_json),
|
|
238
|
+
})),
|
|
239
|
+
metrics: recentMetrics.map((row) => ({
|
|
240
|
+
...row,
|
|
241
|
+
tags: parseJson(row.tags_json),
|
|
242
|
+
})),
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
return { run, report, counts, actionBreakdown, recentErrors, recentFills, recentLogs };
|
|
246
|
+
}
|
|
247
|
+
function renderTextReport(data, watchMode = false, watchIntervalMs = DEFAULT_WATCH_INTERVAL_MS) {
|
|
248
|
+
const { run, report, counts, actionBreakdown, recentErrors, recentFills, recentLogs } = data;
|
|
249
|
+
if (watchMode && process.stdout.isTTY) {
|
|
250
|
+
process.stdout.write('\x1Bc');
|
|
251
|
+
}
|
|
252
|
+
console.log('Open Broker - Automation Report');
|
|
253
|
+
console.log('===============================\n');
|
|
254
|
+
console.log(`Automation: ${report.automationId}`);
|
|
255
|
+
console.log(`Run ID: ${report.runId}`);
|
|
256
|
+
console.log(`Status: ${report.status}${report.stopReason ? ` (${report.stopReason})` : ''}`);
|
|
257
|
+
console.log(`Started: ${formatTimestamp(run.started_at)}`);
|
|
258
|
+
console.log(`Stopped: ${formatTimestamp(run.stopped_at)}`);
|
|
259
|
+
console.log(`Duration: ${formatDurationMs(run.started_at, run.stopped_at)}`);
|
|
260
|
+
console.log(`Script: ${run.script_path}`);
|
|
261
|
+
console.log(`Account: ${run.account_address ?? '-'}`);
|
|
262
|
+
console.log(`Mode: ${report.dryRun ? 'dry' : 'live'}${report.useWebSocket ? ', ws' : ', polling only'}`);
|
|
263
|
+
console.log(`Poll interval: ${run.poll_interval_ms ?? '-'} ms`);
|
|
264
|
+
if (watchMode) {
|
|
265
|
+
console.log(`Refresh: every ${watchIntervalMs} ms (Ctrl-C to stop)`);
|
|
266
|
+
}
|
|
267
|
+
console.log('\nCounts');
|
|
268
|
+
console.log('------');
|
|
269
|
+
for (const [key, value] of Object.entries(counts)) {
|
|
270
|
+
console.log(`${key.padEnd(14)} ${value}`);
|
|
271
|
+
}
|
|
272
|
+
console.log('\nEconomics');
|
|
273
|
+
console.log('---------');
|
|
274
|
+
console.log(`Fills: ${report.fills.count}`);
|
|
275
|
+
console.log(`Volume: ${formatUsd(report.fills.totalVolume)}`);
|
|
276
|
+
console.log(`Closed PnL: ${formatUsd(report.fills.totalClosedPnl)}`);
|
|
277
|
+
console.log(`Fees: ${formatUsd(report.fills.totalFees)}`);
|
|
278
|
+
console.log(`Net after fees: ${formatUsd(report.fills.netAfterFees)}`);
|
|
279
|
+
console.log('\nEquity');
|
|
280
|
+
console.log('------');
|
|
281
|
+
if (report.equity.first) {
|
|
282
|
+
console.log(`First snapshot: ${formatUsd(Number(report.equity.first.equity))} @ ${formatTimestamp(Number(report.equity.first.timestamp))}`);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
console.log('First snapshot: -');
|
|
286
|
+
}
|
|
287
|
+
if (report.equity.latest) {
|
|
288
|
+
console.log(`Latest snapshot:${formatUsd(Number(report.equity.latest.equity))} @ ${formatTimestamp(Number(report.equity.latest.timestamp))}`);
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
console.log('Latest snapshot:-');
|
|
292
|
+
}
|
|
293
|
+
console.log(`Delta: ${report.equity.delta === null ? '-' : formatUsd(report.equity.delta)}`);
|
|
294
|
+
if (Array.isArray(actionBreakdown) && actionBreakdown.length > 0) {
|
|
295
|
+
console.log('\nActions');
|
|
296
|
+
console.log('-------');
|
|
297
|
+
for (const row of actionBreakdown) {
|
|
298
|
+
console.log(`${String(row.method).padEnd(20)} req=${String(row.requests).padStart(3)} resp=${String(row.responses).padStart(3)} err=${String(row.errors).padStart(3)}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (recentErrors.length > 0) {
|
|
302
|
+
console.log('\nRecent Errors');
|
|
303
|
+
console.log('-------------');
|
|
304
|
+
for (const row of recentErrors) {
|
|
305
|
+
const parsed = parseJson(row.error_json);
|
|
306
|
+
console.log(`${formatTimestamp(Number(row.timestamp))} ${String(row.stage)} ${parsed?.message || String(row.error_json)}`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (recentFills.length > 0) {
|
|
310
|
+
console.log('\nRecent Fills');
|
|
311
|
+
console.log('------------');
|
|
312
|
+
for (const row of recentFills) {
|
|
313
|
+
console.log(`${formatTimestamp(Number(row.timestamp))} ${String(row.side).toUpperCase()} ${String(row.coin)} ${row.size} @ ${row.price} pnl=${row.closed_pnl} fee=${row.fee}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (recentLogs.length > 0) {
|
|
317
|
+
console.log('\nRecent Logs');
|
|
318
|
+
console.log('-----------');
|
|
319
|
+
for (const row of recentLogs) {
|
|
320
|
+
console.log(`${formatTimestamp(Number(row.timestamp))} ${String(row.level).toUpperCase()} ${String(row.message)}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
async function main() {
|
|
325
|
+
const rawArgs = process.argv.slice(2);
|
|
326
|
+
const args = parseArgs(rawArgs);
|
|
327
|
+
if (args.help || args.h) {
|
|
328
|
+
printUsage();
|
|
329
|
+
process.exit(0);
|
|
330
|
+
}
|
|
331
|
+
const positional = getPositionalArgs(rawArgs);
|
|
332
|
+
const automationId = positional[0];
|
|
333
|
+
if (!automationId) {
|
|
334
|
+
console.error('Error: automation ID is required');
|
|
335
|
+
printUsage();
|
|
336
|
+
process.exit(1);
|
|
337
|
+
}
|
|
338
|
+
const runSelector = String(args.run || 'latest');
|
|
339
|
+
const limit = parseNumber(args.limit, 10);
|
|
340
|
+
const jsonOutput = args.json === true;
|
|
341
|
+
const watchMode = args.watch === true;
|
|
342
|
+
const watchIntervalMs = parseNumber(args['watch-interval'], DEFAULT_WATCH_INTERVAL_MS);
|
|
343
|
+
if (watchMode && jsonOutput) {
|
|
344
|
+
console.error('Error: --watch cannot be combined with --json');
|
|
345
|
+
process.exit(1);
|
|
346
|
+
}
|
|
347
|
+
const db = new DatabaseSync(AUDIT_DB_PATH);
|
|
348
|
+
let stopRequested = false;
|
|
349
|
+
const cleanup = () => {
|
|
350
|
+
try {
|
|
351
|
+
db.close();
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
// ignore close failures during shutdown
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
const requestStop = () => {
|
|
358
|
+
stopRequested = true;
|
|
359
|
+
};
|
|
360
|
+
process.once('SIGINT', requestStop);
|
|
361
|
+
process.once('SIGTERM', requestStop);
|
|
362
|
+
try {
|
|
363
|
+
if (!watchMode) {
|
|
364
|
+
const data = loadReport(db, automationId, runSelector, limit);
|
|
365
|
+
if (jsonOutput) {
|
|
366
|
+
console.log(JSON.stringify(data.report, null, 2));
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
renderTextReport(data);
|
|
370
|
+
}
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
while (!stopRequested) {
|
|
374
|
+
const data = loadReport(db, automationId, runSelector, limit);
|
|
375
|
+
renderTextReport(data, true, watchIntervalMs);
|
|
376
|
+
await new Promise((resolve) => setTimeout(resolve, watchIntervalMs));
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
finally {
|
|
380
|
+
process.off('SIGINT', requestStop);
|
|
381
|
+
process.off('SIGTERM', requestStop);
|
|
382
|
+
cleanup();
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
await main();
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getRegisteredAutomations as getRegisteredFromFile } from './registry.js';
|
|
2
|
+
import type { RunningAutomation } from './types.js';
|
|
3
|
+
export interface RuntimeOptions {
|
|
4
|
+
scriptPath: string;
|
|
5
|
+
id?: string;
|
|
6
|
+
dryRun?: boolean;
|
|
7
|
+
verbose?: boolean;
|
|
8
|
+
pollIntervalMs?: number;
|
|
9
|
+
/** Gateway port for webhook delivery. Falls back to OPENCLAW_GATEWAY_PORT or 18789 */
|
|
10
|
+
gatewayPort?: number;
|
|
11
|
+
/** Hooks token for webhook auth. Falls back to OPENCLAW_HOOKS_TOKEN */
|
|
12
|
+
hooksToken?: string;
|
|
13
|
+
/** Pre-seed state before the factory function runs (e.g. from --set key=value) */
|
|
14
|
+
initialState?: Record<string, unknown>;
|
|
15
|
+
/**
|
|
16
|
+
* Enable WebSocket for real-time events (allMids, orderUpdates, userFills, userEvents).
|
|
17
|
+
* When enabled, REST polling interval is relaxed to a heartbeat (default 60s).
|
|
18
|
+
* Falls back gracefully to polling if WebSocket connection fails.
|
|
19
|
+
* @default true
|
|
20
|
+
*/
|
|
21
|
+
useWebSocket?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Best-effort host idle-sleep inhibition for the lifetime of the automation.
|
|
24
|
+
* Enabled by default for live runs and disabled by default for dry runs.
|
|
25
|
+
*/
|
|
26
|
+
keepAwake?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export declare function getRunningAutomations(): RunningAutomation[];
|
|
29
|
+
export declare function getAutomation(id: string): RunningAutomation | undefined;
|
|
30
|
+
/** Get all automations from file-based registry (cross-process visibility) */
|
|
31
|
+
export { getRegisteredFromFile as getRegisteredAutomations };
|
|
32
|
+
export declare function startAutomation(options: RuntimeOptions): Promise<RunningAutomation>;
|
|
33
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../scripts/auto/runtime.ts"],"names":[],"mappings":"AAeA,OAAO,EAA4C,wBAAwB,IAAI,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAG5H,OAAO,KAAK,EAYV,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAoZpB,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sFAAsF;IACtF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kFAAkF;IAClF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAKD,wBAAgB,qBAAqB,IAAI,iBAAiB,EAAE,CAE3D;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAEvE;AAED,8EAA8E;AAC9E,OAAO,EAAE,qBAAqB,IAAI,wBAAwB,EAAE,CAAC;AAE7D,wBAAsB,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAohBzF"}
|