@tradejs/cli 3.1.15-beta.228 → 3.1.15
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 +289 -29
- package/dist/lib/runtimeEvidenceDeployment.js +68 -0
- package/dist/lib/runtimeEvidenceSync.js +116 -8
- package/dist/lib/runtimeScorecard.js +156 -10
- package/dist/scripts/replay.js +74 -2
- package/dist/scripts/replayRunner.js +74 -2
- package/dist/scripts/runtimeEvidence.js +76 -5
- package/dist/scripts/runtimeEvidenceSync.js +110 -9
- package/dist/scripts/runtimeScorecard.js +161 -10
- package/package.json +7 -7
|
@@ -639,7 +639,74 @@ var runtimeLineageKey = (lineage) => lineage.schemaVersion === 3 ? [
|
|
|
639
639
|
|
|
640
640
|
// src/lib/runtimeEvidenceDeployment.ts
|
|
641
641
|
var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
|
|
642
|
+
var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
643
|
+
var samePackageVersions = (left, right) => {
|
|
644
|
+
if (!left || !right) return false;
|
|
645
|
+
const leftEntries = Object.entries(left).sort(
|
|
646
|
+
([a], [b]) => a.localeCompare(b)
|
|
647
|
+
);
|
|
648
|
+
const rightEntries = Object.entries(right).sort(
|
|
649
|
+
([a], [b]) => a.localeCompare(b)
|
|
650
|
+
);
|
|
651
|
+
return JSON.stringify(leftEntries) === JSON.stringify(rightEntries);
|
|
652
|
+
};
|
|
653
|
+
var lineageMatchesStrategySnapshot = ({
|
|
654
|
+
lineage,
|
|
655
|
+
deployment,
|
|
656
|
+
strategy
|
|
657
|
+
}) => lineage?.schemaVersion === 3 && lineage.strategyRevision === strategy.strategyRevision && lineage.deploymentCompositionId === deployment.deploymentCompositionId && lineage.strategyPackageVersion === strategy.strategyPackageVersion && lineage.runtimePackageVersion === strategy.runtimePackageVersion && samePackageVersions(
|
|
658
|
+
lineage.strategyDependencyVersions,
|
|
659
|
+
strategy.strategyDependencyVersions
|
|
660
|
+
);
|
|
642
661
|
var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
|
|
662
|
+
var resolveRuntimeEvidenceTickerUniverse = ({
|
|
663
|
+
deployment,
|
|
664
|
+
lineageScopes
|
|
665
|
+
}) => {
|
|
666
|
+
const declaredTickers = deployment.tickers?.filter(isNonEmptyString) ?? [];
|
|
667
|
+
if (declaredTickers.length > 0) {
|
|
668
|
+
return {
|
|
669
|
+
...deployment,
|
|
670
|
+
tickers: [
|
|
671
|
+
...new Set(declaredTickers.map((ticker) => ticker.trim()))
|
|
672
|
+
].sort()
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
const activeStrategies = activeRuntimeEvidenceStrategies(deployment);
|
|
676
|
+
if (activeStrategies.length > 0 && activeStrategies.every((strategy) => strategy.selection?.tickers?.length)) {
|
|
677
|
+
return {
|
|
678
|
+
...deployment,
|
|
679
|
+
tickers: [
|
|
680
|
+
...new Set(
|
|
681
|
+
activeStrategies.flatMap(
|
|
682
|
+
(strategy) => strategy.selection?.tickers ?? []
|
|
683
|
+
)
|
|
684
|
+
)
|
|
685
|
+
].sort()
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
const strategiesByName = new Map(
|
|
689
|
+
activeStrategies.map((strategy) => [strategy.strategyName, strategy])
|
|
690
|
+
);
|
|
691
|
+
const tickers = /* @__PURE__ */ new Set();
|
|
692
|
+
for (const scope of lineageScopes) {
|
|
693
|
+
const strategy = strategiesByName.get(scope.strategy);
|
|
694
|
+
if (!strategy || scope.deploymentId !== deployment.id || scope.accountId !== deployment.accountId || !isNonEmptyString(scope.symbol) || !lineageMatchesStrategySnapshot({
|
|
695
|
+
lineage: scope.lineage,
|
|
696
|
+
deployment,
|
|
697
|
+
strategy
|
|
698
|
+
})) {
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
tickers.add(scope.symbol.trim());
|
|
702
|
+
}
|
|
703
|
+
if (tickers.size === 0) {
|
|
704
|
+
throw new Error(
|
|
705
|
+
"Runtime evidence has no immutable ticker universe for the embedded deployment composition"
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
return { ...deployment, tickers: [...tickers].sort() };
|
|
709
|
+
};
|
|
643
710
|
var resolveRuntimeEvidenceDeploymentSnapshot = async ({
|
|
644
711
|
userName,
|
|
645
712
|
projectRoot: projectRoot2,
|
|
@@ -777,18 +844,18 @@ var parseStrategyFilter = (value) => String(value ?? "").split(",").map((item) =
|
|
|
777
844
|
var runtimeEvidence = async () => {
|
|
778
845
|
const { startTime, endTime, source } = resolveWindow();
|
|
779
846
|
const deploymentId = String(flags.deployment);
|
|
780
|
-
const
|
|
847
|
+
const deploymentSnapshot = await resolveRuntimeEvidenceDeploymentSnapshot({
|
|
781
848
|
userName: String(flags.user),
|
|
782
849
|
projectRoot,
|
|
783
850
|
deploymentId
|
|
784
851
|
});
|
|
785
|
-
const activeStrategies = activeRuntimeEvidenceStrategies(
|
|
786
|
-
|
|
787
|
-
);
|
|
852
|
+
const activeStrategies = activeRuntimeEvidenceStrategies(
|
|
853
|
+
deploymentSnapshot
|
|
854
|
+
).map(({ strategyName }) => strategyName);
|
|
788
855
|
const requestedStrategies = parseStrategyFilter(flags.strategy);
|
|
789
856
|
const strategies = requestedStrategies.length ? requestedStrategies : activeStrategies;
|
|
790
857
|
const declaredStrategies = new Set(
|
|
791
|
-
|
|
858
|
+
deploymentSnapshot.strategies.map(({ strategyName }) => strategyName)
|
|
792
859
|
);
|
|
793
860
|
const unknownStrategies = strategies.filter(
|
|
794
861
|
(strategyName) => !declaredStrategies.has(strategyName)
|
|
@@ -816,6 +883,10 @@ var runtimeEvidence = async () => {
|
|
|
816
883
|
evaluationStatsBuckets: evidence.evaluationStatsBuckets,
|
|
817
884
|
lineageScopes: evidence.lineageScopes
|
|
818
885
|
});
|
|
886
|
+
const deployment = resolveRuntimeEvidenceTickerUniverse({
|
|
887
|
+
deployment: deploymentSnapshot,
|
|
888
|
+
lineageScopes: evidence.lineageScopes
|
|
889
|
+
});
|
|
819
890
|
const artifact = {
|
|
820
891
|
reportType: "runtime-evidence",
|
|
821
892
|
generatedAt: Date.now(),
|
|
@@ -151,6 +151,70 @@ var discoverRuntimeEvidenceBundles = async (rootDir) => {
|
|
|
151
151
|
return bundles.sort();
|
|
152
152
|
};
|
|
153
153
|
|
|
154
|
+
// src/lib/runtimeEvidenceDeployment.ts
|
|
155
|
+
var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
|
|
156
|
+
var isRecord = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
157
|
+
var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
158
|
+
var isPackageVersionMap = (value) => isRecord(value) && Object.keys(value).length > 0 && Object.entries(value).every(
|
|
159
|
+
([name, version]) => name.startsWith("@tradejs/") && isNonEmptyString(version)
|
|
160
|
+
);
|
|
161
|
+
var INTERVALS = /* @__PURE__ */ new Set([
|
|
162
|
+
"1",
|
|
163
|
+
"3",
|
|
164
|
+
"5",
|
|
165
|
+
"15",
|
|
166
|
+
"30",
|
|
167
|
+
"60",
|
|
168
|
+
"120",
|
|
169
|
+
"240",
|
|
170
|
+
"360",
|
|
171
|
+
"720",
|
|
172
|
+
"D",
|
|
173
|
+
"W",
|
|
174
|
+
"M"
|
|
175
|
+
]);
|
|
176
|
+
var UNIVERSES = /* @__PURE__ */ new Set(["crypto", "tradfi"]);
|
|
177
|
+
var isRuntimeStrategySelection = (value) => value === void 0 || isRecord(value) && Object.keys(value).length === 1 && Object.keys(value).every((key) => key === "tickers") && Array.isArray(value.tickers) && value.tickers.length > 0 && value.tickers.every((ticker) => isNonEmptyString(ticker));
|
|
178
|
+
var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
|
|
179
|
+
if (!isRecord(value) || value.schemaVersion !== 2 || !isNonEmptyString(value.id) || !isNonEmptyString(value.deploymentCompositionId) || !/^dc1:[a-f0-9]{16}$/.test(value.deploymentCompositionId) || !isNonEmptyString(value.label) || !isNonEmptyString(value.connectorName) || !isNonEmptyString(value.provider) || !isNonEmptyString(value.accountId) || typeof value.enabled !== "boolean" || !Array.isArray(value.strategies)) {
|
|
180
|
+
throw new Error(
|
|
181
|
+
"Runtime evidence deployment snapshot is missing or invalid"
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
const strategies = value.strategies.map((candidate) => {
|
|
185
|
+
if (!isRecord(candidate) || !isNonEmptyString(candidate.strategyName) || !isNonEmptyString(candidate.strategyRevision) || !/^sr1:[a-f0-9]{16}$/.test(candidate.strategyRevision) || typeof candidate.enabled !== "boolean" || !["active", "entries_paused"].includes(String(candidate.controlState)) || !INTERVALS.has(String(candidate.interval)) || !UNIVERSES.has(String(candidate.universe)) || !isNonEmptyString(candidate.strategyPackage) || !isNonEmptyString(candidate.strategyPackageVersion) || !isPackageVersionMap(candidate.strategyDependencyVersions) || !isNonEmptyString(candidate.runtimePackageVersion) || !isRecord(candidate.strategyConfig) || !isRuntimeStrategySelection(candidate.selection)) {
|
|
186
|
+
throw new Error(
|
|
187
|
+
"Runtime evidence deployment strategy snapshot is invalid"
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
if (String(candidate.strategyConfig.INTERVAL) !== String(candidate.interval) || String(candidate.strategyConfig.UNIVERSE) !== String(candidate.universe)) {
|
|
191
|
+
throw new Error(
|
|
192
|
+
`Runtime evidence strategy config does not match its scope: ${candidate.strategyName}`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
if (candidate.accountId != null && (!isNonEmptyString(candidate.accountId) || candidate.accountId !== value.accountId)) {
|
|
196
|
+
throw new Error(
|
|
197
|
+
`Runtime evidence strategy account does not match deployment: ${candidate.strategyName}`
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
return candidate;
|
|
201
|
+
});
|
|
202
|
+
const identities = /* @__PURE__ */ new Set();
|
|
203
|
+
for (const strategy of strategies) {
|
|
204
|
+
if (identities.has(strategy.strategyName)) {
|
|
205
|
+
throw new Error(
|
|
206
|
+
`Duplicate runtime evidence strategy: ${strategy.strategyName}`
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
identities.add(strategy.strategyName);
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
...value,
|
|
213
|
+
strategies
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
|
|
217
|
+
|
|
154
218
|
// src/lib/runtimeEvidenceSync.ts
|
|
155
219
|
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
156
220
|
var isExistingDestinationError = (error) => {
|
|
@@ -183,7 +247,26 @@ var buildRuntimeEvidenceRsyncArgs = ({
|
|
|
183
247
|
withTrailingSlash(destination)
|
|
184
248
|
];
|
|
185
249
|
var receiptPath = (receiptsRoot, artifactId) => import_node_path2.default.join(receiptsRoot, `${safeSegment(artifactId, "artifact")}.json`);
|
|
186
|
-
var
|
|
250
|
+
var compareBundles = (left, right) => left.manifest.window.endTime - right.manifest.window.endTime || left.manifest.createdAt - right.manifest.createdAt;
|
|
251
|
+
var inspectRuntimeEvidenceBundleSupport = (bundle) => {
|
|
252
|
+
try {
|
|
253
|
+
const deployment = parseRuntimeEvidenceDeploymentSnapshot(
|
|
254
|
+
bundle.artifact.deployment
|
|
255
|
+
);
|
|
256
|
+
if (activeRuntimeEvidenceStrategies(deployment).length === 0) {
|
|
257
|
+
throw new Error(
|
|
258
|
+
"Runtime evidence deployment has no enabled active strategies"
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
return { supported: true };
|
|
262
|
+
} catch (error) {
|
|
263
|
+
return {
|
|
264
|
+
supported: false,
|
|
265
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
var listRuntimeEvidenceBundleStatuses = async ({
|
|
187
270
|
evidenceRoot,
|
|
188
271
|
deploymentId
|
|
189
272
|
}) => {
|
|
@@ -192,19 +275,29 @@ var listPendingRuntimeEvidenceBundles = async ({
|
|
|
192
275
|
const receiptsRoot = import_node_path2.default.join(evidenceRoot, "receipts", safeDeploymentId);
|
|
193
276
|
const bundles = await discoverRuntimeEvidenceBundles(artifactsRoot);
|
|
194
277
|
const pending = [];
|
|
278
|
+
const unsupported = [];
|
|
195
279
|
for (const bundleDir of bundles) {
|
|
196
280
|
const verified = await verifyRuntimeEvidenceBundle(bundleDir);
|
|
197
281
|
if (verified.manifest.deploymentId !== safeDeploymentId) continue;
|
|
198
282
|
try {
|
|
199
283
|
await import_promises2.default.access(receiptPath(receiptsRoot, verified.manifest.artifactId));
|
|
284
|
+
continue;
|
|
200
285
|
} catch (error) {
|
|
201
286
|
if (error.code !== "ENOENT") throw error;
|
|
287
|
+
}
|
|
288
|
+
const support = inspectRuntimeEvidenceBundleSupport(verified);
|
|
289
|
+
if (support.supported) {
|
|
202
290
|
pending.push(verified);
|
|
291
|
+
} else {
|
|
292
|
+
unsupported.push({ bundle: verified, reason: support.reason });
|
|
203
293
|
}
|
|
204
294
|
}
|
|
205
|
-
return
|
|
206
|
-
(
|
|
207
|
-
|
|
295
|
+
return {
|
|
296
|
+
pending: pending.sort(compareBundles),
|
|
297
|
+
unsupported: unsupported.sort(
|
|
298
|
+
(left, right) => compareBundles(left.bundle, right.bundle)
|
|
299
|
+
)
|
|
300
|
+
};
|
|
208
301
|
};
|
|
209
302
|
var syncRuntimeEvidenceBundles = async ({
|
|
210
303
|
source,
|
|
@@ -258,15 +351,16 @@ var syncRuntimeEvidenceBundles = async ({
|
|
|
258
351
|
}
|
|
259
352
|
received.push(await verifyRuntimeEvidenceBundle(destinationDir));
|
|
260
353
|
}
|
|
354
|
+
const statuses = await listRuntimeEvidenceBundleStatuses({
|
|
355
|
+
evidenceRoot,
|
|
356
|
+
deploymentId: safeDeploymentId
|
|
357
|
+
});
|
|
261
358
|
return {
|
|
262
359
|
rsyncArgs,
|
|
263
360
|
stdout: String(transfer.stdout ?? ""),
|
|
264
361
|
stderr: String(transfer.stderr ?? ""),
|
|
265
362
|
received,
|
|
266
|
-
|
|
267
|
-
evidenceRoot,
|
|
268
|
-
deploymentId: safeDeploymentId
|
|
269
|
-
})
|
|
363
|
+
...statuses
|
|
270
364
|
};
|
|
271
365
|
};
|
|
272
366
|
|
|
@@ -303,7 +397,7 @@ var runtimeEvidenceSync = async () => {
|
|
|
303
397
|
});
|
|
304
398
|
console.log(
|
|
305
399
|
import_chalk.default.green(
|
|
306
|
-
`Runtime evidence sync completed: received=${result.received.length} pending=${result.pending.length}`
|
|
400
|
+
`Runtime evidence sync completed: received=${result.received.length} pending=${result.pending.length} unsupported=${result.unsupported.length}`
|
|
307
401
|
)
|
|
308
402
|
);
|
|
309
403
|
console.log(
|
|
@@ -320,6 +414,13 @@ var runtimeEvidenceSync = async () => {
|
|
|
320
414
|
bundleDir: bundle.bundleDir,
|
|
321
415
|
payloadPath: bundle.payloadPath,
|
|
322
416
|
window: bundle.manifest.window
|
|
417
|
+
})),
|
|
418
|
+
unsupported: result.unsupported.map(({ bundle, reason }) => ({
|
|
419
|
+
artifactId: bundle.manifest.artifactId,
|
|
420
|
+
bundleDir: bundle.bundleDir,
|
|
421
|
+
payloadPath: bundle.payloadPath,
|
|
422
|
+
window: bundle.manifest.window,
|
|
423
|
+
reason
|
|
323
424
|
}))
|
|
324
425
|
},
|
|
325
426
|
null,
|
|
@@ -152,6 +152,11 @@ var import_node_child_process = require("child_process");
|
|
|
152
152
|
var import_promises2 = __toESM(require("fs/promises"));
|
|
153
153
|
var import_node_path2 = __toESM(require("path"));
|
|
154
154
|
var import_node_util = require("util");
|
|
155
|
+
|
|
156
|
+
// src/lib/runtimeEvidenceDeployment.ts
|
|
157
|
+
var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
|
|
158
|
+
|
|
159
|
+
// src/lib/runtimeEvidenceSync.ts
|
|
155
160
|
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
156
161
|
var safeSegment = (value, fallback) => {
|
|
157
162
|
const normalized = value.trim().replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
@@ -346,6 +351,138 @@ var buildRuntimeLineageSummary = (rows) => {
|
|
|
346
351
|
maxLossValue: finiteNumber(identity?.maxLossValue)
|
|
347
352
|
};
|
|
348
353
|
};
|
|
354
|
+
var buildEmbeddedLineageScope = ({
|
|
355
|
+
artifact,
|
|
356
|
+
rows,
|
|
357
|
+
strategy
|
|
358
|
+
}) => {
|
|
359
|
+
const deployment = asRecord2(asRecord2(artifact)?.deployment);
|
|
360
|
+
if (finiteNumber(deployment?.schemaVersion) !== 2) return null;
|
|
361
|
+
const deploymentId = finiteString(deployment?.id);
|
|
362
|
+
const accountId = finiteString(deployment?.accountId);
|
|
363
|
+
const deploymentCompositionId = finiteString(
|
|
364
|
+
deployment?.deploymentCompositionId
|
|
365
|
+
);
|
|
366
|
+
if (!deploymentId || !accountId || !deploymentCompositionId) return null;
|
|
367
|
+
const snapshots = asArray(deployment?.strategies).map(asRecord2).filter((item) => item != null).filter((item) => item.enabled === true).filter(
|
|
368
|
+
(item) => !strategy || finiteString(item.strategyName) === strategy
|
|
369
|
+
);
|
|
370
|
+
const targetSeeds = snapshots.map((snapshot) => {
|
|
371
|
+
const strategyName = finiteString(snapshot.strategyName);
|
|
372
|
+
const strategyRevision = finiteString(snapshot.strategyRevision);
|
|
373
|
+
const strategyPackageVersion = finiteString(
|
|
374
|
+
snapshot.strategyPackageVersion
|
|
375
|
+
);
|
|
376
|
+
const strategyDependencyVersions = packageVersionMap(
|
|
377
|
+
snapshot.strategyDependencyVersions
|
|
378
|
+
);
|
|
379
|
+
const runtimePackageVersion = finiteString(
|
|
380
|
+
snapshot.runtimePackageVersion
|
|
381
|
+
);
|
|
382
|
+
return strategyName && strategyRevision && strategyPackageVersion && strategyDependencyVersions && runtimePackageVersion ? {
|
|
383
|
+
strategyName,
|
|
384
|
+
strategyRevision,
|
|
385
|
+
deploymentCompositionId,
|
|
386
|
+
strategyPackageVersion,
|
|
387
|
+
strategyDependencyVersions,
|
|
388
|
+
runtimePackageVersion
|
|
389
|
+
} : null;
|
|
390
|
+
}).filter((item) => item != null);
|
|
391
|
+
if (targetSeeds.length !== snapshots.length || targetSeeds.length === 0) {
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
const lineageRows = [
|
|
395
|
+
...rows.evaluations,
|
|
396
|
+
...rows.signals,
|
|
397
|
+
...rows.trades,
|
|
398
|
+
...rows.lineageScopes.map((scope) => ({
|
|
399
|
+
strategy: scope.strategy,
|
|
400
|
+
deploymentId: scope.deploymentId,
|
|
401
|
+
accountId: scope.accountId,
|
|
402
|
+
runtimeLineage: scope.lineage
|
|
403
|
+
}))
|
|
404
|
+
];
|
|
405
|
+
const identityMatches = (lineage, target) => finiteNumber(lineage?.schemaVersion) === 3 && finiteString(lineage?.strategyRevision) === target.strategyRevision && finiteString(lineage?.deploymentCompositionId) === target.deploymentCompositionId && finiteString(lineage?.strategyPackageVersion) === target.strategyPackageVersion && JSON.stringify(packageVersionMap(lineage?.strategyDependencyVersions)) === JSON.stringify(target.strategyDependencyVersions) && finiteString(lineage?.runtimePackageVersion) === target.runtimePackageVersion;
|
|
406
|
+
const targets = /* @__PURE__ */ new Map();
|
|
407
|
+
for (const seed of targetSeeds) {
|
|
408
|
+
const matchingRows = lineageRows.filter(
|
|
409
|
+
(row) => finiteString(row.strategy) === seed.strategyName && finiteString(row.deploymentId) === deploymentId && finiteString(row.accountId) === accountId && identityMatches(asRecord2(row.runtimeLineage), seed)
|
|
410
|
+
);
|
|
411
|
+
const riskValues = new Set(
|
|
412
|
+
matchingRows.map((row) => finiteNumber(asRecord2(row.runtimeLineage)?.maxLossValue)).filter((value) => value != null)
|
|
413
|
+
);
|
|
414
|
+
targets.set(seed.strategyName, {
|
|
415
|
+
...seed,
|
|
416
|
+
maxLossValue: riskValues.size === 1 ? [...riskValues][0] : null,
|
|
417
|
+
rowsWithLineage: matchingRows.length,
|
|
418
|
+
riskConflict: riskValues.size > 1
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
const belongs = (row) => {
|
|
422
|
+
const strategyName = finiteString(row.strategy);
|
|
423
|
+
const target = strategyName ? targets.get(strategyName) : null;
|
|
424
|
+
const lineage = asRecord2(row.runtimeLineage);
|
|
425
|
+
return Boolean(
|
|
426
|
+
target && target.maxLossValue != null && identityMatches(lineage, target) && finiteNumber(lineage?.maxLossValue) === target.maxLossValue
|
|
427
|
+
);
|
|
428
|
+
};
|
|
429
|
+
const targetValues = [...targets.values()];
|
|
430
|
+
const coverageComplete = targetValues.every(
|
|
431
|
+
(target) => target.rowsWithLineage > 0 && target.maxLossValue != null
|
|
432
|
+
);
|
|
433
|
+
const commonRiskValues = new Set(
|
|
434
|
+
targetValues.map((target) => target.maxLossValue).filter((value) => value != null)
|
|
435
|
+
);
|
|
436
|
+
const singleTarget = targetValues.length === 1 ? targetValues[0] : null;
|
|
437
|
+
const singleLineage = singleTarget?.maxLossValue != null ? {
|
|
438
|
+
schemaVersion: 3,
|
|
439
|
+
strategyRevision: singleTarget.strategyRevision,
|
|
440
|
+
deploymentCompositionId: singleTarget.deploymentCompositionId,
|
|
441
|
+
strategyPackageVersion: singleTarget.strategyPackageVersion,
|
|
442
|
+
strategyDependencyVersions: singleTarget.strategyDependencyVersions,
|
|
443
|
+
runtimePackageVersion: singleTarget.runtimePackageVersion,
|
|
444
|
+
maxLossValue: singleTarget.maxLossValue
|
|
445
|
+
} : null;
|
|
446
|
+
return {
|
|
447
|
+
belongs,
|
|
448
|
+
summary: {
|
|
449
|
+
complete: coverageComplete,
|
|
450
|
+
identityComplete: true,
|
|
451
|
+
coverageComplete,
|
|
452
|
+
conflicts: targetValues.some((target) => target.riskConflict),
|
|
453
|
+
rows: lineageRows.length,
|
|
454
|
+
rowsWithLineage: targetValues.reduce(
|
|
455
|
+
(total, target) => total + target.rowsWithLineage,
|
|
456
|
+
0
|
|
457
|
+
),
|
|
458
|
+
schemaVersion: 3,
|
|
459
|
+
lineageKey: singleLineage ? runtimeLineageKey(singleLineage) : null,
|
|
460
|
+
strategyRevision: singleTarget?.strategyRevision ?? null,
|
|
461
|
+
deploymentCompositionId,
|
|
462
|
+
strategyPackageVersion: singleTarget?.strategyPackageVersion ?? null,
|
|
463
|
+
strategyDependencyVersions: singleTarget?.strategyDependencyVersions ?? null,
|
|
464
|
+
runtimePackageVersion: singleTarget?.runtimePackageVersion ?? null,
|
|
465
|
+
compositionId: null,
|
|
466
|
+
gitSha: null,
|
|
467
|
+
gitDirty: null,
|
|
468
|
+
gateFingerprint: null,
|
|
469
|
+
configFingerprint: null,
|
|
470
|
+
contextFingerprint: null,
|
|
471
|
+
maxLossValue: commonRiskValues.size === 1 ? [...commonRiskValues][0] : null,
|
|
472
|
+
strategyScopes: Object.fromEntries(
|
|
473
|
+
targetValues.map((target) => [
|
|
474
|
+
target.strategyName,
|
|
475
|
+
{
|
|
476
|
+
strategyRevision: target.strategyRevision,
|
|
477
|
+
rowsWithLineage: target.rowsWithLineage,
|
|
478
|
+
maxLossValue: target.maxLossValue,
|
|
479
|
+
complete: target.rowsWithLineage > 0 && target.maxLossValue != null
|
|
480
|
+
}
|
|
481
|
+
])
|
|
482
|
+
)
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
};
|
|
349
486
|
var belongsToRuntimeLineage = (row, summary) => {
|
|
350
487
|
if (!summary.identityComplete || !summary.lineageKey) return false;
|
|
351
488
|
const lineage = asRecord2(row.runtimeLineage);
|
|
@@ -571,7 +708,12 @@ var buildRuntimeScorecard = ({
|
|
|
571
708
|
);
|
|
572
709
|
const deploymentBinding = runtimeDeploymentBinding(runtimeArtifact);
|
|
573
710
|
const rows = extractRuntimeRows(scopedRuntimeArtifact);
|
|
574
|
-
const
|
|
711
|
+
const embeddedLineageScope = buildEmbeddedLineageScope({
|
|
712
|
+
artifact: runtimeArtifact,
|
|
713
|
+
rows,
|
|
714
|
+
strategy
|
|
715
|
+
});
|
|
716
|
+
const runtimeLineage = embeddedLineageScope?.summary ?? buildRuntimeLineageSummary(rows);
|
|
575
717
|
const window = runtimeWindow(runtimeArtifact);
|
|
576
718
|
const startTime = finiteNumber(window.startTime) ?? generatedAt - 864e5;
|
|
577
719
|
const endTime = finiteNumber(window.endTime) ?? generatedAt;
|
|
@@ -620,12 +762,17 @@ var buildRuntimeScorecard = ({
|
|
|
620
762
|
const lineageReason = finiteString(lineage?.reason);
|
|
621
763
|
const calibrationRoot = asRecord2(calibrationArtifact) ?? {};
|
|
622
764
|
const calibrationSummary = asRecord2(calibrationRoot.summary);
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
asRecord2(calibration?.signalToFillAdverseBps)?.avg
|
|
765
|
+
const calibrationSamples = asArray(calibrationRoot.samples).map(asRecord2).filter((item) => item != null).filter((item) => !strategy || finiteString(item.strategy) === strategy).filter(
|
|
766
|
+
(item) => !embeddedLineageScope || embeddedLineageScope.belongs(item)
|
|
626
767
|
);
|
|
627
|
-
const
|
|
628
|
-
|
|
768
|
+
const averageSampleMetric = (field) => {
|
|
769
|
+
const values = calibrationSamples.map((sample) => finiteNumber(sample[field])).filter((value) => value != null);
|
|
770
|
+
return values.length ? round(sum(values) / values.length) : null;
|
|
771
|
+
};
|
|
772
|
+
const fallbackCalibration = strategy ? asRecord2(asRecord2(calibrationSummary?.byStrategy)?.[strategy]) : getCalibrationSummary(calibrationArtifact);
|
|
773
|
+
const actualSlippageBps = embeddedLineageScope ? averageSampleMetric("signalToFillAdverseBps") : finiteNumber(asRecord2(fallbackCalibration?.signalToFillAdverseBps)?.avg);
|
|
774
|
+
const residualVsModelBps = embeddedLineageScope ? averageSampleMetric("residualVsCurrentModelBps") : finiteNumber(
|
|
775
|
+
asRecord2(fallbackCalibration?.residualVsCurrentModelBps)?.avg
|
|
629
776
|
);
|
|
630
777
|
const prospective = getProspectiveSummary(prospectiveEvidenceArtifact);
|
|
631
778
|
const historyTrades = dedupeTrades([
|
|
@@ -633,10 +780,13 @@ var buildRuntimeScorecard = ({
|
|
|
633
780
|
scopedRuntimeArtifact
|
|
634
781
|
]);
|
|
635
782
|
const comparableHistoryTrades = historyTrades.filter(
|
|
636
|
-
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) && belongsToRuntimeLineage(trade, runtimeLineage)
|
|
783
|
+
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) && (embeddedLineageScope ? embeddedLineageScope.belongs(trade) : belongsToRuntimeLineage(trade, runtimeLineage))
|
|
637
784
|
);
|
|
638
785
|
const comparableCurrentClosedTrades = currentClosedTrades.filter(
|
|
639
|
-
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) && belongsToRuntimeLineage(trade, runtimeLineage)
|
|
786
|
+
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) && (embeddedLineageScope ? embeddedLineageScope.belongs(trade) : belongsToRuntimeLineage(trade, runtimeLineage))
|
|
787
|
+
);
|
|
788
|
+
const comparableFills = rows.trades.filter(
|
|
789
|
+
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) && (embeddedLineageScope ? embeddedLineageScope.belongs(trade) : belongsToRuntimeLineage(trade, runtimeLineage))
|
|
640
790
|
);
|
|
641
791
|
const currentDistributions = buildDistributions(rows);
|
|
642
792
|
const previousArtifact = scopedHistoryArtifacts.map((artifact) => ({ artifact, window: runtimeWindow(artifact) })).filter(({ window: candidateWindow }) => {
|
|
@@ -750,7 +900,8 @@ var buildRuntimeScorecard = ({
|
|
|
750
900
|
`${finiteString(signal.orderSkipReason) ?? ""} ${finiteString(signal.orderFailureReason) ?? ""}`
|
|
751
901
|
)
|
|
752
902
|
).length,
|
|
753
|
-
fills:
|
|
903
|
+
fills: comparableFills.length,
|
|
904
|
+
nonComparableFills: rows.trades.length - comparableFills.length,
|
|
754
905
|
closedTrades: currentClosedTrades.length,
|
|
755
906
|
comparableClosedTrades: comparableCurrentClosedTrades.length,
|
|
756
907
|
nonComparableClosedTrades: currentClosedTrades.length - comparableCurrentClosedTrades.length
|
|
@@ -799,7 +950,7 @@ var buildRuntimeScorecard = ({
|
|
|
799
950
|
lineageReason
|
|
800
951
|
},
|
|
801
952
|
execution: {
|
|
802
|
-
available:
|
|
953
|
+
available: actualSlippageBps != null || residualVsModelBps != null,
|
|
803
954
|
actualSignalToFillSlippageBps: actualSlippageBps,
|
|
804
955
|
residualVsCurrentModelBps: residualVsModelBps
|
|
805
956
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/cli",
|
|
3
|
-
"version": "3.1.15
|
|
3
|
+
"version": "3.1.15",
|
|
4
4
|
"description": "Official CLI for the TradeJS TypeScript framework: infra setup, backtests, signals, bots, and ML workflows.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tradejs",
|
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
"tradejs": "dist/cli.js"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@tradejs/connectors": "^3.1.15
|
|
40
|
-
"@tradejs/core": "^3.1.15
|
|
41
|
-
"@tradejs/indicators": "^3.1.15
|
|
42
|
-
"@tradejs/infra": "^3.1.15
|
|
43
|
-
"@tradejs/node": "^3.1.15
|
|
39
|
+
"@tradejs/connectors": "^3.1.15",
|
|
40
|
+
"@tradejs/core": "^3.1.15",
|
|
41
|
+
"@tradejs/indicators": "^3.1.15",
|
|
42
|
+
"@tradejs/infra": "^3.1.15",
|
|
43
|
+
"@tradejs/node": "^3.1.15",
|
|
44
44
|
"@tradejs/strategy-kit": "3.0.3",
|
|
45
|
-
"@tradejs/types": "^3.1.15
|
|
45
|
+
"@tradejs/types": "^3.1.15",
|
|
46
46
|
"args": "^5.0.3",
|
|
47
47
|
"bcryptjs": "^2.4.3",
|
|
48
48
|
"chalk": "4.1.2",
|