@tradejs/cli 3.1.29-beta.281 → 3.1.29-beta.283
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/dist/cli.js +2784 -2407
- package/dist/lib/mcpReplayProcess.js +15 -2
- package/dist/lib/runtimeDebugEvidence.js +45 -52
- package/dist/lib/runtimeFeedbackProcess.js +1700 -0
- package/dist/lib/runtimeRedis.js +45 -0
- package/dist/scripts/mcpWorker.js +65 -21
- package/dist/scripts/replay.js +173 -47
- package/dist/scripts/replayRunner.js +173 -47
- package/dist/scripts/replayRuntimeEvidence.js +154 -58
- package/dist/scripts/runtimeEvidence.js +45 -52
- package/dist/scripts/runtimeFeedbackProcess.js +1736 -0
- package/package.json +7 -7
|
@@ -59,8 +59,21 @@ const timer = setInterval(() => {
|
|
|
59
59
|
try {
|
|
60
60
|
const result = JSON.parse(fs.readFileSync(file + '.result', 'utf8'));
|
|
61
61
|
console.log(result.message);
|
|
62
|
+
if (result.exitCode !== 0) {
|
|
63
|
+
let fd;
|
|
64
|
+
try {
|
|
65
|
+
fd = fs.openSync(file + '.log', fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
66
|
+
const size = fs.fstatSync(fd).size;
|
|
67
|
+
const tail = Buffer.alloc(Math.min(size, 65536));
|
|
68
|
+
fs.readSync(fd, tail, 0, tail.length, Math.max(0, size - tail.length));
|
|
69
|
+
// The worker redacts each line before persisting or returning it through MCP.
|
|
70
|
+
for (const line of tail.toString('utf8').split(/[\\r\\n]+/).filter(Boolean).slice(-150)) console.error('Host replay: ' + line);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error('Host replay log unavailable: ' + error.code);
|
|
73
|
+
} finally { if (fd !== undefined) fs.closeSync(fd); }
|
|
74
|
+
}
|
|
62
75
|
clearInterval(timer);
|
|
63
|
-
process.
|
|
76
|
+
process.exitCode = result.exitCode === 0 ? 0 : 1;
|
|
64
77
|
} catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
65
78
|
}, 1000);
|
|
66
79
|
`;
|
|
@@ -83,7 +96,7 @@ var buildMcpReplayProcess = async ({
|
|
|
83
96
|
const heartbeat = JSON.parse(
|
|
84
97
|
await import_promises.default.readFile(import_node_path.default.join(root, "heartbeat.json"), "utf8")
|
|
85
98
|
);
|
|
86
|
-
if (!Number.isFinite(heartbeat.observedAt) || Date.now() - heartbeat.observedAt < 0 || Date.now() - heartbeat.observedAt > 12e4)
|
|
99
|
+
if (heartbeat.protocolVersion !== 2 || !Number.isFinite(heartbeat.observedAt) || Date.now() - heartbeat.observedAt < 0 || Date.now() - heartbeat.observedAt > 12e4)
|
|
87
100
|
throw new Error("Host replay runner heartbeat is stale");
|
|
88
101
|
const bytes = await import_promises.default.readFile(evidencePath);
|
|
89
102
|
const request = JSON.stringify({
|
|
@@ -42,39 +42,6 @@ var isRuntimeTradeRecord = (value) => {
|
|
|
42
42
|
const record = value;
|
|
43
43
|
return typeof record.orderId === "string" && typeof record.strategy === "string" && typeof record.symbol === "string" && typeof record.entryTimestamp === "number" && typeof record.entryPrice === "number" && typeof record.qty === "number" && (record.direction === "LONG" || record.direction === "SHORT");
|
|
44
44
|
};
|
|
45
|
-
var loadRuntimeTrades = async (userName, {
|
|
46
|
-
startTime,
|
|
47
|
-
endTime
|
|
48
|
-
} = {}) => {
|
|
49
|
-
const hasWindow = Number.isFinite(startTime) && Number.isFinite(endTime) && startTime != null && endTime != null;
|
|
50
|
-
const filterByWindow = (trade) => !hasWindow || trade.entryTimestamp >= startTime && trade.entryTimestamp <= endTime;
|
|
51
|
-
if (hasWindow) {
|
|
52
|
-
const dayKeys = (0, import_time.getRuntimeStorageDayKeys)(startTime, endTime);
|
|
53
|
-
const bucketTrades = (await Promise.all(
|
|
54
|
-
dayKeys.map(
|
|
55
|
-
(dayKey) => (0, import_redis.getHashJsonValues)(
|
|
56
|
-
import_redis.redisKeys.runtimeTradeBucket(userName, dayKey)
|
|
57
|
-
)
|
|
58
|
-
)
|
|
59
|
-
)).flat();
|
|
60
|
-
const dedupedBucketTrades = /* @__PURE__ */ new Map();
|
|
61
|
-
for (const trade of bucketTrades) {
|
|
62
|
-
if (!isRuntimeTradeRecord(trade)) {
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
dedupedBucketTrades.set(trade.orderId, trade);
|
|
66
|
-
}
|
|
67
|
-
const windowedTrades = [...dedupedBucketTrades.values()].filter(filterByWindow).sort((left, right) => left.entryTimestamp - right.entryTimestamp);
|
|
68
|
-
return windowedTrades;
|
|
69
|
-
}
|
|
70
|
-
const tradePrefix = import_redis.redisKeys.runtimeTrades(userName);
|
|
71
|
-
const bucketPrefix = import_redis.redisKeys.runtimeTradeBuckets(userName);
|
|
72
|
-
const keys = (await (0, import_redis.getKeys)(tradePrefix)).filter(
|
|
73
|
-
(key) => !key.startsWith(bucketPrefix)
|
|
74
|
-
);
|
|
75
|
-
const trades = await Promise.all(keys.map((key) => (0, import_redis.getData)(key, null)));
|
|
76
|
-
return trades.filter(isRuntimeTradeRecord).filter(filterByWindow).sort((left, right) => left.entryTimestamp - right.entryTimestamp);
|
|
77
|
-
};
|
|
78
45
|
var loadRuntimeClosedTrades = async (userName, {
|
|
79
46
|
startTime,
|
|
80
47
|
endTime
|
|
@@ -98,6 +65,49 @@ var loadRuntimeClosedTrades = async (userName, {
|
|
|
98
65
|
(left, right) => left.exitTimestamp - right.exitTimestamp
|
|
99
66
|
);
|
|
100
67
|
};
|
|
68
|
+
var loadRuntimeEvidenceTrades = async (userName, { startTime, endTime }) => {
|
|
69
|
+
const prefix = import_redis.redisKeys.runtimeTradeBuckets(userName);
|
|
70
|
+
const lastDay = (0, import_time.getRuntimeStorageDayKey)(endTime - 1);
|
|
71
|
+
const keys = (await (0, import_redis.getKeys)(prefix)).filter((key) => {
|
|
72
|
+
const day = key.slice(prefix.length);
|
|
73
|
+
return key.startsWith(prefix) && /^\d{4}-\d{2}-\d{2}$/.test(day) && day <= lastDay;
|
|
74
|
+
});
|
|
75
|
+
const retained = /* @__PURE__ */ new Map();
|
|
76
|
+
for (let offset = 0; offset < keys.length; offset += 16) {
|
|
77
|
+
const buckets = await Promise.all(
|
|
78
|
+
keys.slice(offset, offset + 16).map((key) => (0, import_redis.getHashJsonValues)(key))
|
|
79
|
+
);
|
|
80
|
+
for (const row of buckets.flat())
|
|
81
|
+
if (isRuntimeTradeRecord(row)) retained.set(row.orderId, row);
|
|
82
|
+
}
|
|
83
|
+
for (const row of await loadRuntimeClosedTrades(userName, {
|
|
84
|
+
startTime,
|
|
85
|
+
endTime
|
|
86
|
+
}))
|
|
87
|
+
retained.set(row.orderId, row);
|
|
88
|
+
return [...retained.values()].filter(
|
|
89
|
+
(row) => row.entryTimestamp < endTime && (row.status === "active" || Number.isFinite(row.exitTimestamp) && row.exitTimestamp >= startTime)
|
|
90
|
+
).map((row) => {
|
|
91
|
+
const closesAfterCutoff = row.status === "closed" && row.exitTimestamp >= endTime;
|
|
92
|
+
if (!closesAfterCutoff && !(row.status === "active" && row.lastSyncedAt >= endTime))
|
|
93
|
+
return row;
|
|
94
|
+
return {
|
|
95
|
+
...row,
|
|
96
|
+
status: "active",
|
|
97
|
+
currentPrice: null,
|
|
98
|
+
currentPnl: null,
|
|
99
|
+
closedPnl: null,
|
|
100
|
+
exitPrice: null,
|
|
101
|
+
actualExitPrice: null,
|
|
102
|
+
exitTimestamp: null,
|
|
103
|
+
exitType: null,
|
|
104
|
+
closeFee: null,
|
|
105
|
+
fundingFee: null,
|
|
106
|
+
totalFee: null,
|
|
107
|
+
lastSyncedAt: void 0
|
|
108
|
+
};
|
|
109
|
+
}).sort((a, b) => a.entryTimestamp - b.entryTimestamp);
|
|
110
|
+
};
|
|
101
111
|
|
|
102
112
|
// src/lib/runtimeSignalsLoader.ts
|
|
103
113
|
var import_redis2 = require("@tradejs/infra/redis");
|
|
@@ -318,30 +328,13 @@ var collectRuntimeDebugEvidence = async ({
|
|
|
318
328
|
}) => {
|
|
319
329
|
const dayKeys = (0, import_time2.getRuntimeStorageDayKeys)(startTime, endTime);
|
|
320
330
|
const dayKeySet = new Set(dayKeys);
|
|
321
|
-
const [
|
|
322
|
-
|
|
323
|
-
closedTrades,
|
|
324
|
-
signals,
|
|
325
|
-
evaluations,
|
|
326
|
-
evaluationStatsBuckets,
|
|
327
|
-
lineageScopes
|
|
328
|
-
] = await Promise.all([
|
|
329
|
-
loadRuntimeTrades(userName, { startTime, endTime }),
|
|
330
|
-
loadRuntimeClosedTrades(userName, { startTime, endTime }),
|
|
331
|
+
const [trades, signals, evaluations, evaluationStatsBuckets, lineageScopes] = await Promise.all([
|
|
332
|
+
loadRuntimeEvidenceTrades(userName, { startTime, endTime }),
|
|
331
333
|
loadRuntimeSignals(userName, { startTime, endTime }),
|
|
332
334
|
loadRuntimeSignalEvaluations(userName, { startTime, endTime }),
|
|
333
335
|
loadRuntimeSignalEvaluationStatsBuckets(userName),
|
|
334
336
|
loadRuntimeLineageScopes(userName, { startTime, endTime })
|
|
335
337
|
]);
|
|
336
|
-
const tradesByOrderId = new Map(
|
|
337
|
-
entryTrades.map((trade) => [trade.orderId, trade])
|
|
338
|
-
);
|
|
339
|
-
for (const trade of closedTrades) {
|
|
340
|
-
tradesByOrderId.set(trade.orderId, trade);
|
|
341
|
-
}
|
|
342
|
-
const trades = [...tradesByOrderId.values()].sort(
|
|
343
|
-
(left, right) => left.entryTimestamp - right.entryTimestamp
|
|
344
|
-
);
|
|
345
338
|
const filteredStats = evaluationStatsBuckets.filter(
|
|
346
339
|
(entry) => dayKeySet.has(entry.dayKey) && (!deploymentId || entry.deploymentId === deploymentId) && (!strategies?.length || strategies.includes(entry.strategy))
|
|
347
340
|
);
|