@tradejs/cli 3.1.14-beta.225 → 3.1.15-beta.227
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
CHANGED
|
@@ -27242,7 +27242,7 @@ async function collectReleaseEvidenceReferences(references) {
|
|
|
27242
27242
|
})
|
|
27243
27243
|
);
|
|
27244
27244
|
}
|
|
27245
|
-
var import_node_crypto12, import_promises26, import_node_path21, import_types10, import_strategyReleaseEvidence3, SHA256_RE2, LINEAGE_FINGERPRINT_RE, STRATEGY_REVISION_RE, DEPLOYMENT_COMPOSITION_ID_RE, REQUIRED_LONG_WINDOWS, REQUIRED_STABLE_TERMINAL_WINDOWS,
|
|
27245
|
+
var import_node_crypto12, import_promises26, import_node_path21, import_types10, import_strategyReleaseEvidence3, SHA256_RE2, LINEAGE_FINGERPRINT_RE, STRATEGY_REVISION_RE, DEPLOYMENT_COMPOSITION_ID_RE, REQUIRED_LONG_WINDOWS, REQUIRED_STABLE_TERMINAL_WINDOWS, MIN_RECENT_DIRECTION_REPAIR_EVENTS, MIN_SELECTION_GRADE_TERMINAL_EVENTS, safeSegment3, compactTimestamp2, verifyFullPeriodChartArtifact, readVerifiedJsonArtifact, verifyResearchDecisionLineage, hasExactRuntimeTarget, deriveStrategyReleaseResearchDecision, canonicalStrategyReleaseJson, strategyReleaseSha256, assertFingerprint, assertLineageFingerprint, releaseReasons, deriveReleaseGates, verifyEvidenceComposition, createStrategyReleaseManifest, createStrategyReleaseEnvelope, verifyStrategyReleaseEnvelope, verifyStrategyEvidenceMarkerEnvelope, releaseMarkers, writeJsonAtomic2, publishStrategyRelease, publishStrategyLiveDiagnosis, finiteString3, finiteNumber6, finiteDirectionPolicy, uniqueStrings, incompleteEvidenceLineage, extractEvidenceLineage, verifyCompletedCoreResearchBundle;
|
|
27246
27246
|
var init_strategyRelease = __esm({
|
|
27247
27247
|
"src/lib/strategyRelease.ts"() {
|
|
27248
27248
|
"use strict";
|
|
@@ -27260,7 +27260,8 @@ var init_strategyRelease = __esm({
|
|
|
27260
27260
|
DEPLOYMENT_COMPOSITION_ID_RE = /^dc1:[a-f0-9]{16}$/;
|
|
27261
27261
|
REQUIRED_LONG_WINDOWS = [1095, 1460, 1825];
|
|
27262
27262
|
REQUIRED_STABLE_TERMINAL_WINDOWS = [365, 180, 90];
|
|
27263
|
-
|
|
27263
|
+
MIN_RECENT_DIRECTION_REPAIR_EVENTS = 20;
|
|
27264
|
+
MIN_SELECTION_GRADE_TERMINAL_EVENTS = 50;
|
|
27264
27265
|
safeSegment3 = import_strategyReleaseEvidence3.safeStrategyEvidenceSegment;
|
|
27265
27266
|
compactTimestamp2 = import_strategyReleaseEvidence3.compactStrategyEvidenceTimestamp;
|
|
27266
27267
|
verifyFullPeriodChartArtifact = async (input) => {
|
|
@@ -27279,16 +27280,51 @@ var init_strategyRelease = __esm({
|
|
|
27279
27280
|
return false;
|
|
27280
27281
|
}
|
|
27281
27282
|
};
|
|
27283
|
+
readVerifiedJsonArtifact = async (artifact) => {
|
|
27284
|
+
if (!artifact?.path || !SHA256_RE2.test(artifact.sha256)) return null;
|
|
27285
|
+
try {
|
|
27286
|
+
const artifactPath = import_node_path21.default.resolve(artifact.path);
|
|
27287
|
+
if (await (0, import_strategyReleaseEvidence3.strategyEvidenceFileSha256)(artifactPath) !== artifact.sha256) {
|
|
27288
|
+
return null;
|
|
27289
|
+
}
|
|
27290
|
+
return JSON.parse(await import_promises26.default.readFile(artifactPath, "utf8"));
|
|
27291
|
+
} catch {
|
|
27292
|
+
return null;
|
|
27293
|
+
}
|
|
27294
|
+
};
|
|
27295
|
+
verifyResearchDecisionLineage = async (input) => {
|
|
27296
|
+
const progress = await readVerifiedJsonArtifact(input.progressArtifact);
|
|
27297
|
+
const selected = await readVerifiedJsonArtifact(
|
|
27298
|
+
input.selectedCompositionArtifact
|
|
27299
|
+
);
|
|
27300
|
+
if (!progress || !selected) return false;
|
|
27301
|
+
const progressSelection = progress.selectedComposition;
|
|
27302
|
+
return Boolean(
|
|
27303
|
+
progress.schema === "tradejs-release-progress/v2" && progress.strategy === input.strategy && progress.status === "complete" && progress.verdictAllowed === true && typeof progress.lineageId === "string" && progress.lineageId.length > 0 && typeof progress.objectiveFingerprint === "string" && SHA256_RE2.test(progress.objectiveFingerprint) && typeof progressSelection?.candidateId === "string" && progressSelection.candidateId.length > 0 && typeof progressSelection.compositionFingerprint === "string" && SHA256_RE2.test(progressSelection.compositionFingerprint) && progressSelection.artifactSha256 === input.selectedCompositionArtifact?.sha256 && selected.schema === "tradejs-release-selected-composition/v2" && selected.strategy === input.strategy && selected.lineageId === progress.lineageId && selected.objectiveFingerprint === progress.objectiveFingerprint && selected.candidateId === progressSelection.candidateId && selected.compositionFingerprint === progressSelection.compositionFingerprint && selected.chartSha256 === input.chartArtifact?.sha256
|
|
27304
|
+
);
|
|
27305
|
+
};
|
|
27282
27306
|
hasExactRuntimeTarget = (target, strategyName) => Boolean(
|
|
27283
27307
|
target?.userName.trim() && target.deploymentId.trim() && target.accountId.trim() && target.strategyName.trim() === strategyName.trim() && STRATEGY_REVISION_RE.test(target.strategyRevision) && DEPLOYMENT_COMPOSITION_ID_RE.test(target.deploymentCompositionId)
|
|
27284
27308
|
);
|
|
27285
27309
|
deriveStrategyReleaseResearchDecision = async (input) => {
|
|
27286
27310
|
const blockers = [];
|
|
27311
|
+
if (!await verifyResearchDecisionLineage(input)) {
|
|
27312
|
+
return {
|
|
27313
|
+
strategy: input.strategy,
|
|
27314
|
+
action: "FORWARD_BLOCKED",
|
|
27315
|
+
repairAllowed: false,
|
|
27316
|
+
targetDirection: input.recentFailure?.direction ?? null,
|
|
27317
|
+
maxLossValue: null,
|
|
27318
|
+
requiresRuntimeBinding: false,
|
|
27319
|
+
blockers: ["RESEARCH_LINEAGE_MISMATCH"],
|
|
27320
|
+
summary: "The progress decision, selected composition, objective, and chart do not resolve to one immutable research lineage."
|
|
27321
|
+
};
|
|
27322
|
+
}
|
|
27287
27323
|
const directionPolicy = input.directionPolicy ?? "both";
|
|
27288
27324
|
const activeDirections = directionPolicy === "long_only" ? ["long"] : directionPolicy === "short_only" ? ["short"] : ["long", "short"];
|
|
27289
27325
|
const suppressedDirection = directionPolicy === "long_only" ? "short" : directionPolicy === "short_only" ? "long" : null;
|
|
27290
|
-
const hasHistoricalEdge = (entry) => entry.pnl > 0 && entry.profitFactor >= 1 && activeDirections.every(
|
|
27291
|
-
(direction) => entry[direction].pnl > 0 && entry[direction].profitFactor >= 1
|
|
27326
|
+
const hasHistoricalEdge = (entry, supportConditioned = false) => (supportConditioned ? (entry.independentEvents ?? entry.trades ?? 0) < MIN_SELECTION_GRADE_TERMINAL_EVENTS || entry.pnl > 0 && entry.profitFactor >= 1 : entry.pnl > 0 && entry.profitFactor >= 1) && activeDirections.every(
|
|
27327
|
+
(direction) => supportConditioned && (entry[direction].independentEvents ?? entry[direction].trades ?? 0) < MIN_SELECTION_GRADE_TERMINAL_EVENTS || entry[direction].pnl > 0 && entry[direction].profitFactor >= 1
|
|
27292
27328
|
) && (suppressedDirection == null || entry[suppressedDirection].trades === 0 && entry[suppressedDirection].pnl === 0);
|
|
27293
27329
|
const byDays = new Map(
|
|
27294
27330
|
input.historicalWindows.map((entry) => [entry.days, entry])
|
|
@@ -27308,7 +27344,16 @@ var init_strategyRelease = __esm({
|
|
|
27308
27344
|
const stableTerminalWindows = REQUIRED_STABLE_TERMINAL_WINDOWS.map(
|
|
27309
27345
|
(days) => byDays.get(days)
|
|
27310
27346
|
).filter((entry) => Boolean(entry));
|
|
27311
|
-
if (stableTerminalWindows.some(
|
|
27347
|
+
if (stableTerminalWindows.some(
|
|
27348
|
+
(entry) => !Number.isFinite(entry.independentEvents ?? entry.trades) || activeDirections.some(
|
|
27349
|
+
(direction) => !Number.isFinite(
|
|
27350
|
+
entry[direction].independentEvents ?? entry[direction].trades
|
|
27351
|
+
)
|
|
27352
|
+
)
|
|
27353
|
+
)) {
|
|
27354
|
+
blockers.push("HISTORICAL_MATRIX_INCOMPLETE");
|
|
27355
|
+
}
|
|
27356
|
+
if (stableTerminalWindows.some((entry) => !hasHistoricalEdge(entry, true))) {
|
|
27312
27357
|
blockers.push("HISTORICAL_EDGE_FAILED");
|
|
27313
27358
|
}
|
|
27314
27359
|
if (blockers.length) {
|
|
@@ -27320,11 +27365,11 @@ var init_strategyRelease = __esm({
|
|
|
27320
27365
|
maxLossValue: null,
|
|
27321
27366
|
requiresRuntimeBinding: false,
|
|
27322
27367
|
blockers,
|
|
27323
|
-
summary: `The final ${directionPolicy} composition
|
|
27368
|
+
summary: `The final ${directionPolicy} composition fails the frozen long-window edge or a selection-grade terminal guardrail. Underpowered and diagnostic terminal cohorts do not cause this stop.`
|
|
27324
27369
|
};
|
|
27325
27370
|
}
|
|
27326
27371
|
const repairAllowed = Boolean(
|
|
27327
|
-
input.recentFailure && input.recentFailure.
|
|
27372
|
+
input.recentFailure && input.recentFailure.independentEvents >= MIN_RECENT_DIRECTION_REPAIR_EVENTS && input.recentFailure.causalMechanismIdentified && input.recentFailure.repairRoundsUsed === 0 && !input.exposedEvaluation
|
|
27328
27373
|
);
|
|
27329
27374
|
if (repairAllowed) {
|
|
27330
27375
|
return {
|
|
@@ -27335,7 +27380,7 @@ var init_strategyRelease = __esm({
|
|
|
27335
27380
|
maxLossValue: null,
|
|
27336
27381
|
requiresRuntimeBinding: false,
|
|
27337
27382
|
blockers: [],
|
|
27338
|
-
summary: "Spend the single terminal-direction repair round on the preregistered causal mechanism, then rebuild the full evidence matrix."
|
|
27383
|
+
summary: "Spend the single terminal-direction repair round on the preregistered causal mechanism with diagnostic independent support, then rebuild the full evidence matrix."
|
|
27339
27384
|
};
|
|
27340
27385
|
}
|
|
27341
27386
|
if (!input.candidateImplemented) blockers.push("CANDIDATE_NOT_IMPLEMENTED");
|
|
@@ -30250,8 +30295,6 @@ var init_runtimeParity2 = __esm({
|
|
|
30250
30295
|
buildReplayAiAnalyses = ({
|
|
30251
30296
|
runtimeTrades,
|
|
30252
30297
|
runtimeSignalEvaluations,
|
|
30253
|
-
strategy,
|
|
30254
|
-
symbol,
|
|
30255
30298
|
toleranceMs
|
|
30256
30299
|
}) => {
|
|
30257
30300
|
const snapshots = [
|
|
@@ -30954,7 +30997,7 @@ var init_runtimeParity2 = __esm({
|
|
|
30954
30997
|
runtimeEntriesCount,
|
|
30955
30998
|
runtimeDuplicateEntriesCount,
|
|
30956
30999
|
backtestEntriesCount,
|
|
30957
|
-
matchedCount,
|
|
31000
|
+
matchedCount: _matchedCount,
|
|
30958
31001
|
runtimeOnlyCount,
|
|
30959
31002
|
backtestOnlyCount,
|
|
30960
31003
|
matchedSummary,
|
|
@@ -31078,7 +31121,7 @@ var init_runtimeParity2 = __esm({
|
|
|
31078
31121
|
window,
|
|
31079
31122
|
connectorName,
|
|
31080
31123
|
replayEnv,
|
|
31081
|
-
runtimeGatesEnabled,
|
|
31124
|
+
runtimeGatesEnabled: _runtimeGatesEnabled,
|
|
31082
31125
|
userName: userName3
|
|
31083
31126
|
}) => [
|
|
31084
31127
|
"\u{1F9EA} <b>TradeJS runtime parity</b>",
|
|
@@ -33784,7 +33827,7 @@ var init_portfolioReplayConnector = __esm({
|
|
|
33784
33827
|
});
|
|
33785
33828
|
};
|
|
33786
33829
|
const getExecutionSlippageBreakdown = ({
|
|
33787
|
-
stage,
|
|
33830
|
+
stage: _stage,
|
|
33788
33831
|
signal
|
|
33789
33832
|
}) => (0, import_trade2.calculateExecutionSlippageBreakdown)({
|
|
33790
33833
|
spreadBps: (0, import_trade2.extractExecutionSpreadBps)(signal),
|
|
@@ -34296,7 +34339,6 @@ var init_historicalSignalsReplay = __esm({
|
|
|
34296
34339
|
});
|
|
34297
34340
|
const cycleSymbolsByTimestamp = /* @__PURE__ */ new Map();
|
|
34298
34341
|
const sharedReplayKeyPrefixes = [];
|
|
34299
|
-
let preparedSymbols = 0;
|
|
34300
34342
|
let skippedSymbols = 0;
|
|
34301
34343
|
const prepareBar = new import_progress12.default(
|
|
34302
34344
|
"prepare :current/:total [:bar][:percent] skipped=:skipped :etas(s) :symbol",
|
|
@@ -34415,7 +34457,6 @@ var init_historicalSignalsReplay = __esm({
|
|
|
34415
34457
|
currentIndex: 0,
|
|
34416
34458
|
strategies: strategiesForSymbol
|
|
34417
34459
|
};
|
|
34418
|
-
preparedSymbols += 1;
|
|
34419
34460
|
prepareBar.tick(1, {
|
|
34420
34461
|
skipped: import_chalk46.default.yellow(skippedSymbols),
|
|
34421
34462
|
symbol: import_chalk46.default.gray(symbol)
|
|
@@ -34445,7 +34486,7 @@ var init_historicalSignalsReplay = __esm({
|
|
|
34445
34486
|
}
|
|
34446
34487
|
);
|
|
34447
34488
|
try {
|
|
34448
|
-
for (const
|
|
34489
|
+
for (const timestamp of orderedTimestamps) {
|
|
34449
34490
|
const cycleStartedAt = Date.now();
|
|
34450
34491
|
const cycleSymbols = cycleSymbolsByTimestamp.get(timestamp) ?? [];
|
|
34451
34492
|
for (const symbolRuntime of cycleSymbols) {
|
|
@@ -36425,9 +36466,6 @@ var init_runtimeComparison = __esm({
|
|
|
36425
36466
|
toleranceMs: REPLAY_RUNTIME_COMPARE_TOLERANCE_MS,
|
|
36426
36467
|
signalTimestampOffsetMs: getReplayEntryTimestampCompareOffsetMs()
|
|
36427
36468
|
});
|
|
36428
|
-
const liveSummaryByStrategy = new Map(
|
|
36429
|
-
liveStrategySummaries.map((summary) => [summary.strategyName, summary])
|
|
36430
|
-
);
|
|
36431
36469
|
const rowByStrategy = /* @__PURE__ */ new Map();
|
|
36432
36470
|
const ensureRow = (strategyName) => {
|
|
36433
36471
|
const existing = rowByStrategy.get(strategyName);
|
|
@@ -283,7 +283,8 @@ var STRATEGY_REVISION_RE = /^sr1:[a-f0-9]{16}$/;
|
|
|
283
283
|
var DEPLOYMENT_COMPOSITION_ID_RE = /^dc1:[a-f0-9]{16}$/;
|
|
284
284
|
var REQUIRED_LONG_WINDOWS = [1095, 1460, 1825];
|
|
285
285
|
var REQUIRED_STABLE_TERMINAL_WINDOWS = [365, 180, 90];
|
|
286
|
-
var
|
|
286
|
+
var MIN_RECENT_DIRECTION_REPAIR_EVENTS = 20;
|
|
287
|
+
var MIN_SELECTION_GRADE_TERMINAL_EVENTS = 50;
|
|
287
288
|
var safeSegment = import_strategyReleaseEvidence.safeStrategyEvidenceSegment;
|
|
288
289
|
var compactTimestamp = import_strategyReleaseEvidence.compactStrategyEvidenceTimestamp;
|
|
289
290
|
var verifyFullPeriodChartArtifact = async (input) => {
|
|
@@ -302,16 +303,51 @@ var verifyFullPeriodChartArtifact = async (input) => {
|
|
|
302
303
|
return false;
|
|
303
304
|
}
|
|
304
305
|
};
|
|
306
|
+
var readVerifiedJsonArtifact = async (artifact) => {
|
|
307
|
+
if (!artifact?.path || !SHA256_RE.test(artifact.sha256)) return null;
|
|
308
|
+
try {
|
|
309
|
+
const artifactPath = import_node_path.default.resolve(artifact.path);
|
|
310
|
+
if (await (0, import_strategyReleaseEvidence.strategyEvidenceFileSha256)(artifactPath) !== artifact.sha256) {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
return JSON.parse(await import_promises.default.readFile(artifactPath, "utf8"));
|
|
314
|
+
} catch {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
var verifyResearchDecisionLineage = async (input) => {
|
|
319
|
+
const progress = await readVerifiedJsonArtifact(input.progressArtifact);
|
|
320
|
+
const selected = await readVerifiedJsonArtifact(
|
|
321
|
+
input.selectedCompositionArtifact
|
|
322
|
+
);
|
|
323
|
+
if (!progress || !selected) return false;
|
|
324
|
+
const progressSelection = progress.selectedComposition;
|
|
325
|
+
return Boolean(
|
|
326
|
+
progress.schema === "tradejs-release-progress/v2" && progress.strategy === input.strategy && progress.status === "complete" && progress.verdictAllowed === true && typeof progress.lineageId === "string" && progress.lineageId.length > 0 && typeof progress.objectiveFingerprint === "string" && SHA256_RE.test(progress.objectiveFingerprint) && typeof progressSelection?.candidateId === "string" && progressSelection.candidateId.length > 0 && typeof progressSelection.compositionFingerprint === "string" && SHA256_RE.test(progressSelection.compositionFingerprint) && progressSelection.artifactSha256 === input.selectedCompositionArtifact?.sha256 && selected.schema === "tradejs-release-selected-composition/v2" && selected.strategy === input.strategy && selected.lineageId === progress.lineageId && selected.objectiveFingerprint === progress.objectiveFingerprint && selected.candidateId === progressSelection.candidateId && selected.compositionFingerprint === progressSelection.compositionFingerprint && selected.chartSha256 === input.chartArtifact?.sha256
|
|
327
|
+
);
|
|
328
|
+
};
|
|
305
329
|
var hasExactRuntimeTarget = (target, strategyName) => Boolean(
|
|
306
330
|
target?.userName.trim() && target.deploymentId.trim() && target.accountId.trim() && target.strategyName.trim() === strategyName.trim() && STRATEGY_REVISION_RE.test(target.strategyRevision) && DEPLOYMENT_COMPOSITION_ID_RE.test(target.deploymentCompositionId)
|
|
307
331
|
);
|
|
308
332
|
var deriveStrategyReleaseResearchDecision = async (input) => {
|
|
309
333
|
const blockers = [];
|
|
334
|
+
if (!await verifyResearchDecisionLineage(input)) {
|
|
335
|
+
return {
|
|
336
|
+
strategy: input.strategy,
|
|
337
|
+
action: "FORWARD_BLOCKED",
|
|
338
|
+
repairAllowed: false,
|
|
339
|
+
targetDirection: input.recentFailure?.direction ?? null,
|
|
340
|
+
maxLossValue: null,
|
|
341
|
+
requiresRuntimeBinding: false,
|
|
342
|
+
blockers: ["RESEARCH_LINEAGE_MISMATCH"],
|
|
343
|
+
summary: "The progress decision, selected composition, objective, and chart do not resolve to one immutable research lineage."
|
|
344
|
+
};
|
|
345
|
+
}
|
|
310
346
|
const directionPolicy = input.directionPolicy ?? "both";
|
|
311
347
|
const activeDirections = directionPolicy === "long_only" ? ["long"] : directionPolicy === "short_only" ? ["short"] : ["long", "short"];
|
|
312
348
|
const suppressedDirection = directionPolicy === "long_only" ? "short" : directionPolicy === "short_only" ? "long" : null;
|
|
313
|
-
const hasHistoricalEdge = (entry) => entry.pnl > 0 && entry.profitFactor >= 1 && activeDirections.every(
|
|
314
|
-
(direction) => entry[direction].pnl > 0 && entry[direction].profitFactor >= 1
|
|
349
|
+
const hasHistoricalEdge = (entry, supportConditioned = false) => (supportConditioned ? (entry.independentEvents ?? entry.trades ?? 0) < MIN_SELECTION_GRADE_TERMINAL_EVENTS || entry.pnl > 0 && entry.profitFactor >= 1 : entry.pnl > 0 && entry.profitFactor >= 1) && activeDirections.every(
|
|
350
|
+
(direction) => supportConditioned && (entry[direction].independentEvents ?? entry[direction].trades ?? 0) < MIN_SELECTION_GRADE_TERMINAL_EVENTS || entry[direction].pnl > 0 && entry[direction].profitFactor >= 1
|
|
315
351
|
) && (suppressedDirection == null || entry[suppressedDirection].trades === 0 && entry[suppressedDirection].pnl === 0);
|
|
316
352
|
const byDays = new Map(
|
|
317
353
|
input.historicalWindows.map((entry) => [entry.days, entry])
|
|
@@ -331,7 +367,16 @@ var deriveStrategyReleaseResearchDecision = async (input) => {
|
|
|
331
367
|
const stableTerminalWindows = REQUIRED_STABLE_TERMINAL_WINDOWS.map(
|
|
332
368
|
(days) => byDays.get(days)
|
|
333
369
|
).filter((entry) => Boolean(entry));
|
|
334
|
-
if (stableTerminalWindows.some(
|
|
370
|
+
if (stableTerminalWindows.some(
|
|
371
|
+
(entry) => !Number.isFinite(entry.independentEvents ?? entry.trades) || activeDirections.some(
|
|
372
|
+
(direction) => !Number.isFinite(
|
|
373
|
+
entry[direction].independentEvents ?? entry[direction].trades
|
|
374
|
+
)
|
|
375
|
+
)
|
|
376
|
+
)) {
|
|
377
|
+
blockers.push("HISTORICAL_MATRIX_INCOMPLETE");
|
|
378
|
+
}
|
|
379
|
+
if (stableTerminalWindows.some((entry) => !hasHistoricalEdge(entry, true))) {
|
|
335
380
|
blockers.push("HISTORICAL_EDGE_FAILED");
|
|
336
381
|
}
|
|
337
382
|
if (blockers.length) {
|
|
@@ -343,11 +388,11 @@ var deriveStrategyReleaseResearchDecision = async (input) => {
|
|
|
343
388
|
maxLossValue: null,
|
|
344
389
|
requiresRuntimeBinding: false,
|
|
345
390
|
blockers,
|
|
346
|
-
summary: `The final ${directionPolicy} composition
|
|
391
|
+
summary: `The final ${directionPolicy} composition fails the frozen long-window edge or a selection-grade terminal guardrail. Underpowered and diagnostic terminal cohorts do not cause this stop.`
|
|
347
392
|
};
|
|
348
393
|
}
|
|
349
394
|
const repairAllowed = Boolean(
|
|
350
|
-
input.recentFailure && input.recentFailure.
|
|
395
|
+
input.recentFailure && input.recentFailure.independentEvents >= MIN_RECENT_DIRECTION_REPAIR_EVENTS && input.recentFailure.causalMechanismIdentified && input.recentFailure.repairRoundsUsed === 0 && !input.exposedEvaluation
|
|
351
396
|
);
|
|
352
397
|
if (repairAllowed) {
|
|
353
398
|
return {
|
|
@@ -358,7 +403,7 @@ var deriveStrategyReleaseResearchDecision = async (input) => {
|
|
|
358
403
|
maxLossValue: null,
|
|
359
404
|
requiresRuntimeBinding: false,
|
|
360
405
|
blockers: [],
|
|
361
|
-
summary: "Spend the single terminal-direction repair round on the preregistered causal mechanism, then rebuild the full evidence matrix."
|
|
406
|
+
summary: "Spend the single terminal-direction repair round on the preregistered causal mechanism with diagnostic independent support, then rebuild the full evidence matrix."
|
|
362
407
|
};
|
|
363
408
|
}
|
|
364
409
|
if (!input.candidateImplemented) blockers.push("CANDIDATE_NOT_IMPLEMENTED");
|
package/dist/scripts/replay.js
CHANGED
|
@@ -5179,7 +5179,7 @@ var createPortfolioReplayConnector = (connector) => {
|
|
|
5179
5179
|
});
|
|
5180
5180
|
};
|
|
5181
5181
|
const getExecutionSlippageBreakdown = ({
|
|
5182
|
-
stage,
|
|
5182
|
+
stage: _stage,
|
|
5183
5183
|
signal
|
|
5184
5184
|
}) => (0, import_trade.calculateExecutionSlippageBreakdown)({
|
|
5185
5185
|
spreadBps: (0, import_trade.extractExecutionSpreadBps)(signal),
|
|
@@ -5713,7 +5713,6 @@ var runHistoricalSignalsReplay = async ({
|
|
|
5713
5713
|
});
|
|
5714
5714
|
const cycleSymbolsByTimestamp = /* @__PURE__ */ new Map();
|
|
5715
5715
|
const sharedReplayKeyPrefixes = [];
|
|
5716
|
-
let preparedSymbols = 0;
|
|
5717
5716
|
let skippedSymbols = 0;
|
|
5718
5717
|
const prepareBar = new import_progress4.default(
|
|
5719
5718
|
"prepare :current/:total [:bar][:percent] skipped=:skipped :etas(s) :symbol",
|
|
@@ -5832,7 +5831,6 @@ var runHistoricalSignalsReplay = async ({
|
|
|
5832
5831
|
currentIndex: 0,
|
|
5833
5832
|
strategies: strategiesForSymbol
|
|
5834
5833
|
};
|
|
5835
|
-
preparedSymbols += 1;
|
|
5836
5834
|
prepareBar.tick(1, {
|
|
5837
5835
|
skipped: import_chalk9.default.yellow(skippedSymbols),
|
|
5838
5836
|
symbol: import_chalk9.default.gray(symbol)
|
|
@@ -5862,7 +5860,7 @@ var runHistoricalSignalsReplay = async ({
|
|
|
5862
5860
|
}
|
|
5863
5861
|
);
|
|
5864
5862
|
try {
|
|
5865
|
-
for (const
|
|
5863
|
+
for (const timestamp of orderedTimestamps) {
|
|
5866
5864
|
const cycleStartedAt = Date.now();
|
|
5867
5865
|
const cycleSymbols = cycleSymbolsByTimestamp.get(timestamp) ?? [];
|
|
5868
5866
|
for (const symbolRuntime of cycleSymbols) {
|
|
@@ -8234,9 +8232,6 @@ var saveAndPrintReplayExchangeComparison = async ({
|
|
|
8234
8232
|
toleranceMs: REPLAY_RUNTIME_COMPARE_TOLERANCE_MS,
|
|
8235
8233
|
signalTimestampOffsetMs: getReplayEntryTimestampCompareOffsetMs()
|
|
8236
8234
|
});
|
|
8237
|
-
const liveSummaryByStrategy = new Map(
|
|
8238
|
-
liveStrategySummaries.map((summary) => [summary.strategyName, summary])
|
|
8239
|
-
);
|
|
8240
8235
|
const rowByStrategy = /* @__PURE__ */ new Map();
|
|
8241
8236
|
const ensureRow = (strategyName) => {
|
|
8242
8237
|
const existing = rowByStrategy.get(strategyName);
|
|
@@ -5182,7 +5182,7 @@ var createPortfolioReplayConnector = (connector) => {
|
|
|
5182
5182
|
});
|
|
5183
5183
|
};
|
|
5184
5184
|
const getExecutionSlippageBreakdown = ({
|
|
5185
|
-
stage,
|
|
5185
|
+
stage: _stage,
|
|
5186
5186
|
signal
|
|
5187
5187
|
}) => (0, import_trade.calculateExecutionSlippageBreakdown)({
|
|
5188
5188
|
spreadBps: (0, import_trade.extractExecutionSpreadBps)(signal),
|
|
@@ -5716,7 +5716,6 @@ var runHistoricalSignalsReplay = async ({
|
|
|
5716
5716
|
});
|
|
5717
5717
|
const cycleSymbolsByTimestamp = /* @__PURE__ */ new Map();
|
|
5718
5718
|
const sharedReplayKeyPrefixes = [];
|
|
5719
|
-
let preparedSymbols = 0;
|
|
5720
5719
|
let skippedSymbols = 0;
|
|
5721
5720
|
const prepareBar = new import_progress4.default(
|
|
5722
5721
|
"prepare :current/:total [:bar][:percent] skipped=:skipped :etas(s) :symbol",
|
|
@@ -5835,7 +5834,6 @@ var runHistoricalSignalsReplay = async ({
|
|
|
5835
5834
|
currentIndex: 0,
|
|
5836
5835
|
strategies: strategiesForSymbol
|
|
5837
5836
|
};
|
|
5838
|
-
preparedSymbols += 1;
|
|
5839
5837
|
prepareBar.tick(1, {
|
|
5840
5838
|
skipped: import_chalk9.default.yellow(skippedSymbols),
|
|
5841
5839
|
symbol: import_chalk9.default.gray(symbol)
|
|
@@ -5865,7 +5863,7 @@ var runHistoricalSignalsReplay = async ({
|
|
|
5865
5863
|
}
|
|
5866
5864
|
);
|
|
5867
5865
|
try {
|
|
5868
|
-
for (const
|
|
5866
|
+
for (const timestamp of orderedTimestamps) {
|
|
5869
5867
|
const cycleStartedAt = Date.now();
|
|
5870
5868
|
const cycleSymbols = cycleSymbolsByTimestamp.get(timestamp) ?? [];
|
|
5871
5869
|
for (const symbolRuntime of cycleSymbols) {
|
|
@@ -8237,9 +8235,6 @@ var saveAndPrintReplayExchangeComparison = async ({
|
|
|
8237
8235
|
toleranceMs: REPLAY_RUNTIME_COMPARE_TOLERANCE_MS,
|
|
8238
8236
|
signalTimestampOffsetMs: getReplayEntryTimestampCompareOffsetMs()
|
|
8239
8237
|
});
|
|
8240
|
-
const liveSummaryByStrategy = new Map(
|
|
8241
|
-
liveStrategySummaries.map((summary) => [summary.strategyName, summary])
|
|
8242
|
-
);
|
|
8243
8238
|
const rowByStrategy = /* @__PURE__ */ new Map();
|
|
8244
8239
|
const ensureRow = (strategyName) => {
|
|
8245
8240
|
const existing = rowByStrategy.get(strategyName);
|
|
@@ -4908,8 +4908,6 @@ var createConnector = async ({
|
|
|
4908
4908
|
var buildReplayAiAnalyses = ({
|
|
4909
4909
|
runtimeTrades,
|
|
4910
4910
|
runtimeSignalEvaluations,
|
|
4911
|
-
strategy,
|
|
4912
|
-
symbol,
|
|
4913
4911
|
toleranceMs
|
|
4914
4912
|
}) => {
|
|
4915
4913
|
const snapshots = [
|
|
@@ -5612,7 +5610,7 @@ var buildRuntimeParityMessage = ({
|
|
|
5612
5610
|
runtimeEntriesCount,
|
|
5613
5611
|
runtimeDuplicateEntriesCount,
|
|
5614
5612
|
backtestEntriesCount,
|
|
5615
|
-
matchedCount,
|
|
5613
|
+
matchedCount: _matchedCount,
|
|
5616
5614
|
runtimeOnlyCount,
|
|
5617
5615
|
backtestOnlyCount,
|
|
5618
5616
|
matchedSummary,
|
|
@@ -5736,7 +5734,7 @@ var buildRuntimeParityNoTargetsMessage = ({
|
|
|
5736
5734
|
window,
|
|
5737
5735
|
connectorName,
|
|
5738
5736
|
replayEnv,
|
|
5739
|
-
runtimeGatesEnabled,
|
|
5737
|
+
runtimeGatesEnabled: _runtimeGatesEnabled,
|
|
5740
5738
|
userName
|
|
5741
5739
|
}) => [
|
|
5742
5740
|
"\u{1F9EA} <b>TradeJS runtime parity</b>",
|
|
@@ -233,7 +233,8 @@ var STRATEGY_REVISION_RE = /^sr1:[a-f0-9]{16}$/;
|
|
|
233
233
|
var DEPLOYMENT_COMPOSITION_ID_RE = /^dc1:[a-f0-9]{16}$/;
|
|
234
234
|
var REQUIRED_LONG_WINDOWS = [1095, 1460, 1825];
|
|
235
235
|
var REQUIRED_STABLE_TERMINAL_WINDOWS = [365, 180, 90];
|
|
236
|
-
var
|
|
236
|
+
var MIN_RECENT_DIRECTION_REPAIR_EVENTS = 20;
|
|
237
|
+
var MIN_SELECTION_GRADE_TERMINAL_EVENTS = 50;
|
|
237
238
|
var safeSegment = import_strategyReleaseEvidence.safeStrategyEvidenceSegment;
|
|
238
239
|
var compactTimestamp = import_strategyReleaseEvidence.compactStrategyEvidenceTimestamp;
|
|
239
240
|
var verifyFullPeriodChartArtifact = async (input) => {
|
|
@@ -252,16 +253,51 @@ var verifyFullPeriodChartArtifact = async (input) => {
|
|
|
252
253
|
return false;
|
|
253
254
|
}
|
|
254
255
|
};
|
|
256
|
+
var readVerifiedJsonArtifact = async (artifact) => {
|
|
257
|
+
if (!artifact?.path || !SHA256_RE.test(artifact.sha256)) return null;
|
|
258
|
+
try {
|
|
259
|
+
const artifactPath = import_node_path.default.resolve(artifact.path);
|
|
260
|
+
if (await (0, import_strategyReleaseEvidence.strategyEvidenceFileSha256)(artifactPath) !== artifact.sha256) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
return JSON.parse(await import_promises.default.readFile(artifactPath, "utf8"));
|
|
264
|
+
} catch {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
var verifyResearchDecisionLineage = async (input) => {
|
|
269
|
+
const progress = await readVerifiedJsonArtifact(input.progressArtifact);
|
|
270
|
+
const selected = await readVerifiedJsonArtifact(
|
|
271
|
+
input.selectedCompositionArtifact
|
|
272
|
+
);
|
|
273
|
+
if (!progress || !selected) return false;
|
|
274
|
+
const progressSelection = progress.selectedComposition;
|
|
275
|
+
return Boolean(
|
|
276
|
+
progress.schema === "tradejs-release-progress/v2" && progress.strategy === input.strategy && progress.status === "complete" && progress.verdictAllowed === true && typeof progress.lineageId === "string" && progress.lineageId.length > 0 && typeof progress.objectiveFingerprint === "string" && SHA256_RE.test(progress.objectiveFingerprint) && typeof progressSelection?.candidateId === "string" && progressSelection.candidateId.length > 0 && typeof progressSelection.compositionFingerprint === "string" && SHA256_RE.test(progressSelection.compositionFingerprint) && progressSelection.artifactSha256 === input.selectedCompositionArtifact?.sha256 && selected.schema === "tradejs-release-selected-composition/v2" && selected.strategy === input.strategy && selected.lineageId === progress.lineageId && selected.objectiveFingerprint === progress.objectiveFingerprint && selected.candidateId === progressSelection.candidateId && selected.compositionFingerprint === progressSelection.compositionFingerprint && selected.chartSha256 === input.chartArtifact?.sha256
|
|
277
|
+
);
|
|
278
|
+
};
|
|
255
279
|
var hasExactRuntimeTarget = (target, strategyName) => Boolean(
|
|
256
280
|
target?.userName.trim() && target.deploymentId.trim() && target.accountId.trim() && target.strategyName.trim() === strategyName.trim() && STRATEGY_REVISION_RE.test(target.strategyRevision) && DEPLOYMENT_COMPOSITION_ID_RE.test(target.deploymentCompositionId)
|
|
257
281
|
);
|
|
258
282
|
var deriveStrategyReleaseResearchDecision = async (input) => {
|
|
259
283
|
const blockers = [];
|
|
284
|
+
if (!await verifyResearchDecisionLineage(input)) {
|
|
285
|
+
return {
|
|
286
|
+
strategy: input.strategy,
|
|
287
|
+
action: "FORWARD_BLOCKED",
|
|
288
|
+
repairAllowed: false,
|
|
289
|
+
targetDirection: input.recentFailure?.direction ?? null,
|
|
290
|
+
maxLossValue: null,
|
|
291
|
+
requiresRuntimeBinding: false,
|
|
292
|
+
blockers: ["RESEARCH_LINEAGE_MISMATCH"],
|
|
293
|
+
summary: "The progress decision, selected composition, objective, and chart do not resolve to one immutable research lineage."
|
|
294
|
+
};
|
|
295
|
+
}
|
|
260
296
|
const directionPolicy = input.directionPolicy ?? "both";
|
|
261
297
|
const activeDirections = directionPolicy === "long_only" ? ["long"] : directionPolicy === "short_only" ? ["short"] : ["long", "short"];
|
|
262
298
|
const suppressedDirection = directionPolicy === "long_only" ? "short" : directionPolicy === "short_only" ? "long" : null;
|
|
263
|
-
const hasHistoricalEdge = (entry) => entry.pnl > 0 && entry.profitFactor >= 1 && activeDirections.every(
|
|
264
|
-
(direction) => entry[direction].pnl > 0 && entry[direction].profitFactor >= 1
|
|
299
|
+
const hasHistoricalEdge = (entry, supportConditioned = false) => (supportConditioned ? (entry.independentEvents ?? entry.trades ?? 0) < MIN_SELECTION_GRADE_TERMINAL_EVENTS || entry.pnl > 0 && entry.profitFactor >= 1 : entry.pnl > 0 && entry.profitFactor >= 1) && activeDirections.every(
|
|
300
|
+
(direction) => supportConditioned && (entry[direction].independentEvents ?? entry[direction].trades ?? 0) < MIN_SELECTION_GRADE_TERMINAL_EVENTS || entry[direction].pnl > 0 && entry[direction].profitFactor >= 1
|
|
265
301
|
) && (suppressedDirection == null || entry[suppressedDirection].trades === 0 && entry[suppressedDirection].pnl === 0);
|
|
266
302
|
const byDays = new Map(
|
|
267
303
|
input.historicalWindows.map((entry) => [entry.days, entry])
|
|
@@ -281,7 +317,16 @@ var deriveStrategyReleaseResearchDecision = async (input) => {
|
|
|
281
317
|
const stableTerminalWindows = REQUIRED_STABLE_TERMINAL_WINDOWS.map(
|
|
282
318
|
(days) => byDays.get(days)
|
|
283
319
|
).filter((entry) => Boolean(entry));
|
|
284
|
-
if (stableTerminalWindows.some(
|
|
320
|
+
if (stableTerminalWindows.some(
|
|
321
|
+
(entry) => !Number.isFinite(entry.independentEvents ?? entry.trades) || activeDirections.some(
|
|
322
|
+
(direction) => !Number.isFinite(
|
|
323
|
+
entry[direction].independentEvents ?? entry[direction].trades
|
|
324
|
+
)
|
|
325
|
+
)
|
|
326
|
+
)) {
|
|
327
|
+
blockers.push("HISTORICAL_MATRIX_INCOMPLETE");
|
|
328
|
+
}
|
|
329
|
+
if (stableTerminalWindows.some((entry) => !hasHistoricalEdge(entry, true))) {
|
|
285
330
|
blockers.push("HISTORICAL_EDGE_FAILED");
|
|
286
331
|
}
|
|
287
332
|
if (blockers.length) {
|
|
@@ -293,11 +338,11 @@ var deriveStrategyReleaseResearchDecision = async (input) => {
|
|
|
293
338
|
maxLossValue: null,
|
|
294
339
|
requiresRuntimeBinding: false,
|
|
295
340
|
blockers,
|
|
296
|
-
summary: `The final ${directionPolicy} composition
|
|
341
|
+
summary: `The final ${directionPolicy} composition fails the frozen long-window edge or a selection-grade terminal guardrail. Underpowered and diagnostic terminal cohorts do not cause this stop.`
|
|
297
342
|
};
|
|
298
343
|
}
|
|
299
344
|
const repairAllowed = Boolean(
|
|
300
|
-
input.recentFailure && input.recentFailure.
|
|
345
|
+
input.recentFailure && input.recentFailure.independentEvents >= MIN_RECENT_DIRECTION_REPAIR_EVENTS && input.recentFailure.causalMechanismIdentified && input.recentFailure.repairRoundsUsed === 0 && !input.exposedEvaluation
|
|
301
346
|
);
|
|
302
347
|
if (repairAllowed) {
|
|
303
348
|
return {
|
|
@@ -308,7 +353,7 @@ var deriveStrategyReleaseResearchDecision = async (input) => {
|
|
|
308
353
|
maxLossValue: null,
|
|
309
354
|
requiresRuntimeBinding: false,
|
|
310
355
|
blockers: [],
|
|
311
|
-
summary: "Spend the single terminal-direction repair round on the preregistered causal mechanism, then rebuild the full evidence matrix."
|
|
356
|
+
summary: "Spend the single terminal-direction repair round on the preregistered causal mechanism with diagnostic independent support, then rebuild the full evidence matrix."
|
|
312
357
|
};
|
|
313
358
|
}
|
|
314
359
|
if (!input.candidateImplemented) blockers.push("CANDIDATE_NOT_IMPLEMENTED");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/cli",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.15-beta.227",
|
|
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.
|
|
40
|
-
"@tradejs/core": "^3.1.
|
|
41
|
-
"@tradejs/indicators": "^3.1.
|
|
42
|
-
"@tradejs/infra": "^3.1.
|
|
43
|
-
"@tradejs/node": "^3.1.
|
|
39
|
+
"@tradejs/connectors": "^3.1.15-beta.227",
|
|
40
|
+
"@tradejs/core": "^3.1.15-beta.227",
|
|
41
|
+
"@tradejs/indicators": "^3.1.15-beta.227",
|
|
42
|
+
"@tradejs/infra": "^3.1.15-beta.227",
|
|
43
|
+
"@tradejs/node": "^3.1.15-beta.227",
|
|
44
44
|
"@tradejs/strategy-kit": "3.0.3",
|
|
45
|
-
"@tradejs/types": "^3.1.
|
|
45
|
+
"@tradejs/types": "^3.1.15-beta.227",
|
|
46
46
|
"args": "^5.0.3",
|
|
47
47
|
"bcryptjs": "^2.4.3",
|
|
48
48
|
"chalk": "4.1.2",
|