@tradejs/cli 3.1.29-beta.266 → 3.1.29-beta.268
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 +29 -8
- package/dist/lib/coreResearch.js +29 -8
- package/dist/scripts/coreResearch.js +29 -8
- package/package.json +7 -7
package/dist/cli.js
CHANGED
|
@@ -28332,7 +28332,12 @@ var init_artifacts = __esm({
|
|
|
28332
28332
|
"controlPnl",
|
|
28333
28333
|
"candidatePnl",
|
|
28334
28334
|
"pnlDelta",
|
|
28335
|
-
"
|
|
28335
|
+
"controlExitReason",
|
|
28336
|
+
"candidateExitReason",
|
|
28337
|
+
"exitReasonChanged",
|
|
28338
|
+
"controlExitCode",
|
|
28339
|
+
"candidateExitCode",
|
|
28340
|
+
"exitCodeChanged"
|
|
28336
28341
|
].map(csv).join(",") + "\n"
|
|
28337
28342
|
);
|
|
28338
28343
|
for (const comparison of params.comparisons) {
|
|
@@ -28350,7 +28355,12 @@ var init_artifacts = __esm({
|
|
|
28350
28355
|
pair.control.netProfit,
|
|
28351
28356
|
pair.candidate.netProfit,
|
|
28352
28357
|
pair.pnlDelta,
|
|
28353
|
-
pair.
|
|
28358
|
+
pair.control.exitReason,
|
|
28359
|
+
pair.candidate.exitReason,
|
|
28360
|
+
pair.exitReasonChanged,
|
|
28361
|
+
pair.control.exitCode,
|
|
28362
|
+
pair.candidate.exitCode,
|
|
28363
|
+
pair.exitCodeChanged
|
|
28354
28364
|
].map(csv).join(",") + "\n"
|
|
28355
28365
|
);
|
|
28356
28366
|
}
|
|
@@ -28995,6 +29005,7 @@ var init_comparison = __esm({
|
|
|
28995
29005
|
candidate: candidateTrade,
|
|
28996
29006
|
pnlDelta: candidateTrade.netProfit - controlTrade.netProfit,
|
|
28997
29007
|
exitReasonChanged: candidateTrade.exitReason !== controlTrade.exitReason,
|
|
29008
|
+
exitCodeChanged: candidateTrade.exitCode !== controlTrade.exitCode,
|
|
28998
29009
|
entryTimestampDeltaMs: candidateTrade.entryTimestamp - controlTrade.entryTimestamp,
|
|
28999
29010
|
exitTimestampDeltaMs: candidateTrade.exitTimestamp - controlTrade.exitTimestamp
|
|
29000
29011
|
});
|
|
@@ -29212,6 +29223,7 @@ var init_dataset2 = __esm({
|
|
|
29212
29223
|
"totalSlippageCost"
|
|
29213
29224
|
),
|
|
29214
29225
|
exitReason: result.exitReason,
|
|
29226
|
+
...result.exitCode ? { exitCode: result.exitCode } : {},
|
|
29215
29227
|
regime: resolveCoreResearchRegime(row)
|
|
29216
29228
|
};
|
|
29217
29229
|
};
|
|
@@ -29255,7 +29267,7 @@ var init_dataset2 = __esm({
|
|
|
29255
29267
|
}
|
|
29256
29268
|
const primary = primaryRows[0];
|
|
29257
29269
|
if (cycle.some(
|
|
29258
|
-
(trade) => trade.exitTimestamp !== primary.exitTimestamp || trade.exitReason !== primary.exitReason
|
|
29270
|
+
(trade) => trade.exitTimestamp !== primary.exitTimestamp || trade.exitReason !== primary.exitReason || trade.exitCode !== primary.exitCode
|
|
29259
29271
|
)) {
|
|
29260
29272
|
throw new Error(
|
|
29261
29273
|
`Position cycle ${identity} contains inconsistent final exits`
|
|
@@ -29444,7 +29456,7 @@ var init_report = __esm({
|
|
|
29444
29456
|
)}</svg><div class="legend">${series.map((entry) => `<span><i style="background:${entry.color}"></i>${escapeHtml4(entry.id)}</span>`).join("")}</div>`;
|
|
29445
29457
|
};
|
|
29446
29458
|
comparisonCards = (comparisons) => comparisons.map(
|
|
29447
|
-
(comparison) => `<article class="card"><h3>${escapeHtml4(comparison.candidateId)} vs ${escapeHtml4(comparison.controlId)}</h3><p class="verdict ${comparison.selection.passed ? "positive" : "negative"}">${comparison.selection.passed ? "PASS selection" : "REJECT selection"}</p><dl><dt>Matched</dt><dd>${comparison.matched}</dd><dt>Control only</dt><dd>${comparison.controlOnly}</dd><dt>Candidate only</dt><dd>${comparison.candidateOnly}</dd><dt>Identity retained</dt><dd>${format2(comparison.matchedIdentityPctOfControl)}%</dd><dt>Matched \u0394PnL</dt><dd>${format2(comparison.cohorts.ALL.matchedPnlDelta)}</dd><dt>Removed control PnL</dt><dd>${format2(comparison.cohorts.ALL.controlOnlyPnl)}</dd><dt>Added candidate PnL</dt><dd>${format2(comparison.cohorts.ALL.candidateOnlyPnl)}</dd><dt>Aggregate \u0394PnL</dt><dd>${format2(comparison.cohorts.ALL.delta.pnl)}</dd><dt>Aggregate \u0394DD</dt><dd>${format2(comparison.cohorts.ALL.delta.realizedMaxDrawdown)}</dd><dt>Bootstrap P(\u0394>0)</dt><dd>${format2(comparison.bootstrap.probabilityPositive, 4)}</dd><dt>Holm p</dt><dd>${format2(comparison.bootstrap.holmAdjustedPValue, 4)}</dd></dl><p>${comparison.selection.failedRules.length ? escapeHtml4(comparison.selection.failedRules.map((rule) => `${rule.scope}.${rule.metric} ${rule.expected}`).join("; ")) : "All preregistered rules passed."}</p></article>`
|
|
29459
|
+
(comparison) => `<article class="card"><h3>${escapeHtml4(comparison.candidateId)} vs ${escapeHtml4(comparison.controlId)}</h3><p class="verdict ${comparison.selection.passed ? "positive" : "negative"}">${comparison.selection.passed ? "PASS selection" : "REJECT selection"}</p><dl><dt>Matched</dt><dd>${comparison.matched}</dd><dt>Control only</dt><dd>${comparison.controlOnly}</dd><dt>Candidate only</dt><dd>${comparison.candidateOnly}</dd><dt>Identity retained</dt><dd>${format2(comparison.matchedIdentityPctOfControl)}%</dd><dt>Exit reason changes</dt><dd>${comparison.matchedPairs.filter((pair) => pair.exitReasonChanged).length}</dd><dt>Exit code changes</dt><dd>${comparison.matchedPairs.filter((pair) => pair.exitCodeChanged).length}</dd><dt>Matched \u0394PnL</dt><dd>${format2(comparison.cohorts.ALL.matchedPnlDelta)}</dd><dt>Removed control PnL</dt><dd>${format2(comparison.cohorts.ALL.controlOnlyPnl)}</dd><dt>Added candidate PnL</dt><dd>${format2(comparison.cohorts.ALL.candidateOnlyPnl)}</dd><dt>Aggregate \u0394PnL</dt><dd>${format2(comparison.cohorts.ALL.delta.pnl)}</dd><dt>Aggregate \u0394DD</dt><dd>${format2(comparison.cohorts.ALL.delta.realizedMaxDrawdown)}</dd><dt>Bootstrap P(\u0394>0)</dt><dd>${format2(comparison.bootstrap.probabilityPositive, 4)}</dd><dt>Holm p</dt><dd>${format2(comparison.bootstrap.holmAdjustedPValue, 4)}</dd></dl><p>${comparison.selection.failedRules.length ? escapeHtml4(comparison.selection.failedRules.map((rule) => `${rule.scope}.${rule.metric} ${rule.expected}`).join("; ")) : "All preregistered rules passed."}</p></article>`
|
|
29448
29460
|
).join("");
|
|
29449
29461
|
regimeRows = (variants) => {
|
|
29450
29462
|
const keys = [
|
|
@@ -29458,7 +29470,7 @@ var init_report = __esm({
|
|
|
29458
29470
|
).join("");
|
|
29459
29471
|
};
|
|
29460
29472
|
traceRows = (variants) => variants.map(
|
|
29461
|
-
(variant) => `<tr><td>${escapeHtml4(variant.variant.label)}</td><td>${escapeHtml4(variant.reconciliation.status)}</td><td>${escapeHtml4(JSON.stringify(variant.setupIdentitySources))}</td><td>${escapeHtml4(JSON.stringify(variant.traceFunnel.events))}</td><td>${escapeHtml4(JSON.stringify(variant.traceFunnel.skipCounts))}</td><td>${escapeHtml4(variant.latestSignalTimeRegime?.key ?? "n/a")}</td></tr>`
|
|
29473
|
+
(variant) => `<tr><td>${escapeHtml4(variant.variant.label)}</td><td>${escapeHtml4(variant.reconciliation.status)}</td><td>${escapeHtml4(JSON.stringify(variant.setupIdentitySources))}</td><td>${escapeHtml4(JSON.stringify(variant.traceFunnel.events))}</td><td>${escapeHtml4(JSON.stringify(variant.traceFunnel.skipCounts))}</td><td>${escapeHtml4(JSON.stringify(variant.traceFunnel.exitCodes))}</td><td>${escapeHtml4(variant.latestSignalTimeRegime?.key ?? "n/a")}</td></tr>`
|
|
29462
29474
|
).join("");
|
|
29463
29475
|
buildCoreResearchHtml = (params) => {
|
|
29464
29476
|
const { spec, result, tradesByVariant } = params;
|
|
@@ -29484,7 +29496,7 @@ var init_report = __esm({
|
|
|
29484
29496
|
([key, value]) => `<span class="${value === "present" ? "positive" : "negative"}">${escapeHtml4(key)}: ${value}</span>`
|
|
29485
29497
|
).join(
|
|
29486
29498
|
""
|
|
29487
|
-
)}</section><h2>ALL equity</h2>${buildCurveSvg(tradesByVariant, "ALL", "equity")}<h2>ALL realized drawdown</h2>${buildCurveSvg(tradesByVariant, "ALL", "drawdown")}<h2>LONG equity</h2>${buildCurveSvg(tradesByVariant, "LONG", "equity")}<h2>LONG realized drawdown</h2>${buildCurveSvg(tradesByVariant, "LONG", "drawdown")}<h2>SHORT equity</h2>${buildCurveSvg(tradesByVariant, "SHORT", "equity")}<h2>SHORT realized drawdown</h2>${buildCurveSvg(tradesByVariant, "SHORT", "drawdown")}<h2>Fixed cohort metrics</h2><p class="muted">Avg PnL/trade = cohort PnL / cohort
|
|
29499
|
+
)}</section><h2>ALL equity</h2>${buildCurveSvg(tradesByVariant, "ALL", "equity")}<h2>ALL realized drawdown</h2>${buildCurveSvg(tradesByVariant, "ALL", "drawdown")}<h2>LONG equity</h2>${buildCurveSvg(tradesByVariant, "LONG", "equity")}<h2>LONG realized drawdown</h2>${buildCurveSvg(tradesByVariant, "LONG", "drawdown")}<h2>SHORT equity</h2>${buildCurveSvg(tradesByVariant, "SHORT", "equity")}<h2>SHORT realized drawdown</h2>${buildCurveSvg(tradesByVariant, "SHORT", "drawdown")}<h2>Fixed cohort metrics</h2><p class="muted">Avg PnL/trade = cohort PnL / cohort completed positions. ALL drawdown is aggregate portfolio; LONG/SHORT drawdowns are side-only.</p><div class="scroll"><table><thead><tr><th>Variant</th><th>Window</th><th>Cohort</th><th>N</th><th>PnL</th><th>Avg PnL/trade</th><th>PF</th><th>WR</th><th>Realized DD</th><th>Cad/day</th><th>Avg win</th><th>Avg loss</th><th>Payoff</th><th>Median</th><th>P05</th><th>P95</th><th>Median hold h</th><th>Max loss streak</th></tr></thead><tbody>${allRows}</tbody></table></div><h2>Fold and monthly robustness</h2><div class="scroll"><table><thead><tr><th>Variant</th><th>Window</th><th>Cohort</th><th>N</th><th>PnL</th><th>Avg PnL/trade</th><th>PF</th><th>WR</th><th>Realized DD</th><th>Cad/day</th><th>Avg win</th><th>Avg loss</th><th>Payoff</th><th>Median</th><th>P05</th><th>P95</th><th>Median hold h</th><th>Max loss streak</th></tr></thead><tbody>${robustnessRows}</tbody></table></div><h2>Cost stress</h2><div class="scroll"><table><thead><tr><th>Variant</th><th>Extra round-trip bps</th><th>N</th><th>PnL</th><th>Avg PnL/trade</th><th>PF</th><th>Realized DD</th></tr></thead><tbody>${costRows}</tbody></table></div><h2>Signal-time market regimes</h2><div class="scroll"><table><thead><tr><th>Trend | Volatility | Breadth | Derivatives</th><th>Variant</th><th>N</th><th>PnL</th><th>PF</th><th>WR</th></tr></thead><tbody>${regimeRows(result.variants)}</tbody></table></div><h2>Trace funnel and reconciliation</h2><div class="scroll"><table><thead><tr><th>Variant</th><th>Reconcile</th><th>Setup identity source</th><th>Events</th><th>Top skips</th><th>Exit codes</th><th>Latest signal-time regime</th></tr></thead><tbody>${traceRows(result.variants)}</tbody></table></div><h2>Multiple testing / overfitting</h2><pre>${escapeHtml4(JSON.stringify({ multipleTesting: result.multipleTesting, overfittingDiagnostics: result.overfittingDiagnostics }, null, 2))}</pre><h2>Lineage</h2><pre>${escapeHtml4(JSON.stringify({ stage: spec.stage, universeSha256: spec.universe.sha256, lineage: spec.lineage ?? null, artifactHashes: result.artifactHashes }, null, 2))}</pre></main></body></html>`;
|
|
29488
29500
|
};
|
|
29489
29501
|
}
|
|
29490
29502
|
});
|
|
@@ -29786,8 +29798,9 @@ var init_trace = __esm({
|
|
|
29786
29798
|
import_promises24 = __toESM(require("fs/promises"));
|
|
29787
29799
|
import_node_path18 = __toESM(require("path"));
|
|
29788
29800
|
summarizeCoreResearchTrace = async (filePaths = []) => {
|
|
29789
|
-
const events =
|
|
29790
|
-
const skipCounts =
|
|
29801
|
+
const events = /* @__PURE__ */ Object.create(null);
|
|
29802
|
+
const skipCounts = /* @__PURE__ */ Object.create(null);
|
|
29803
|
+
const exitCodes = /* @__PURE__ */ Object.create(null);
|
|
29791
29804
|
for (const inputPath of filePaths) {
|
|
29792
29805
|
const filePath = import_node_path18.default.resolve(inputPath);
|
|
29793
29806
|
const text = await import_promises24.default.readFile(filePath, "utf8");
|
|
@@ -29807,6 +29820,9 @@ var init_trace = __esm({
|
|
|
29807
29820
|
skipCounts[reason] = (skipCounts[reason] ?? 0) + count;
|
|
29808
29821
|
}
|
|
29809
29822
|
}
|
|
29823
|
+
if (event.event === "position_exited" && event.exitCode) {
|
|
29824
|
+
exitCodes[event.exitCode] = (exitCodes[event.exitCode] ?? 0) + 1;
|
|
29825
|
+
}
|
|
29810
29826
|
}
|
|
29811
29827
|
}
|
|
29812
29828
|
return {
|
|
@@ -29815,6 +29831,11 @@ var init_trace = __esm({
|
|
|
29815
29831
|
Object.entries(skipCounts).sort(
|
|
29816
29832
|
([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
|
|
29817
29833
|
)
|
|
29834
|
+
),
|
|
29835
|
+
exitCodes: Object.fromEntries(
|
|
29836
|
+
Object.entries(exitCodes).sort(
|
|
29837
|
+
([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
|
|
29838
|
+
)
|
|
29818
29839
|
)
|
|
29819
29840
|
};
|
|
29820
29841
|
};
|
package/dist/lib/coreResearch.js
CHANGED
|
@@ -691,7 +691,12 @@ var writeCoreResearchMatches = async (params) => {
|
|
|
691
691
|
"controlPnl",
|
|
692
692
|
"candidatePnl",
|
|
693
693
|
"pnlDelta",
|
|
694
|
-
"
|
|
694
|
+
"controlExitReason",
|
|
695
|
+
"candidateExitReason",
|
|
696
|
+
"exitReasonChanged",
|
|
697
|
+
"controlExitCode",
|
|
698
|
+
"candidateExitCode",
|
|
699
|
+
"exitCodeChanged"
|
|
695
700
|
].map(csv).join(",") + "\n"
|
|
696
701
|
);
|
|
697
702
|
for (const comparison of params.comparisons) {
|
|
@@ -709,7 +714,12 @@ var writeCoreResearchMatches = async (params) => {
|
|
|
709
714
|
pair.control.netProfit,
|
|
710
715
|
pair.candidate.netProfit,
|
|
711
716
|
pair.pnlDelta,
|
|
712
|
-
pair.
|
|
717
|
+
pair.control.exitReason,
|
|
718
|
+
pair.candidate.exitReason,
|
|
719
|
+
pair.exitReasonChanged,
|
|
720
|
+
pair.control.exitCode,
|
|
721
|
+
pair.candidate.exitCode,
|
|
722
|
+
pair.exitCodeChanged
|
|
713
723
|
].map(csv).join(",") + "\n"
|
|
714
724
|
);
|
|
715
725
|
}
|
|
@@ -1326,6 +1336,7 @@ var compareCoreResearchVariants = (params) => {
|
|
|
1326
1336
|
candidate: candidateTrade,
|
|
1327
1337
|
pnlDelta: candidateTrade.netProfit - controlTrade.netProfit,
|
|
1328
1338
|
exitReasonChanged: candidateTrade.exitReason !== controlTrade.exitReason,
|
|
1339
|
+
exitCodeChanged: candidateTrade.exitCode !== controlTrade.exitCode,
|
|
1329
1340
|
entryTimestampDeltaMs: candidateTrade.entryTimestamp - controlTrade.entryTimestamp,
|
|
1330
1341
|
exitTimestampDeltaMs: candidateTrade.exitTimestamp - controlTrade.exitTimestamp
|
|
1331
1342
|
});
|
|
@@ -1537,6 +1548,7 @@ var normalizeCompletedTrade = (params) => {
|
|
|
1537
1548
|
"totalSlippageCost"
|
|
1538
1549
|
),
|
|
1539
1550
|
exitReason: result.exitReason,
|
|
1551
|
+
...result.exitCode ? { exitCode: result.exitCode } : {},
|
|
1540
1552
|
regime: resolveCoreResearchRegime(row)
|
|
1541
1553
|
};
|
|
1542
1554
|
};
|
|
@@ -1580,7 +1592,7 @@ var aggregatePositionCycles = (trades) => {
|
|
|
1580
1592
|
}
|
|
1581
1593
|
const primary = primaryRows[0];
|
|
1582
1594
|
if (cycle.some(
|
|
1583
|
-
(trade) => trade.exitTimestamp !== primary.exitTimestamp || trade.exitReason !== primary.exitReason
|
|
1595
|
+
(trade) => trade.exitTimestamp !== primary.exitTimestamp || trade.exitReason !== primary.exitReason || trade.exitCode !== primary.exitCode
|
|
1584
1596
|
)) {
|
|
1585
1597
|
throw new Error(
|
|
1586
1598
|
`Position cycle ${identity} contains inconsistent final exits`
|
|
@@ -1762,7 +1774,7 @@ var buildCurveSvg = (tradesByVariant, cohort, curve) => {
|
|
|
1762
1774
|
)}</svg><div class="legend">${series.map((entry) => `<span><i style="background:${entry.color}"></i>${escapeHtml(entry.id)}</span>`).join("")}</div>`;
|
|
1763
1775
|
};
|
|
1764
1776
|
var comparisonCards = (comparisons) => comparisons.map(
|
|
1765
|
-
(comparison) => `<article class="card"><h3>${escapeHtml(comparison.candidateId)} vs ${escapeHtml(comparison.controlId)}</h3><p class="verdict ${comparison.selection.passed ? "positive" : "negative"}">${comparison.selection.passed ? "PASS selection" : "REJECT selection"}</p><dl><dt>Matched</dt><dd>${comparison.matched}</dd><dt>Control only</dt><dd>${comparison.controlOnly}</dd><dt>Candidate only</dt><dd>${comparison.candidateOnly}</dd><dt>Identity retained</dt><dd>${format(comparison.matchedIdentityPctOfControl)}%</dd><dt>Matched \u0394PnL</dt><dd>${format(comparison.cohorts.ALL.matchedPnlDelta)}</dd><dt>Removed control PnL</dt><dd>${format(comparison.cohorts.ALL.controlOnlyPnl)}</dd><dt>Added candidate PnL</dt><dd>${format(comparison.cohorts.ALL.candidateOnlyPnl)}</dd><dt>Aggregate \u0394PnL</dt><dd>${format(comparison.cohorts.ALL.delta.pnl)}</dd><dt>Aggregate \u0394DD</dt><dd>${format(comparison.cohorts.ALL.delta.realizedMaxDrawdown)}</dd><dt>Bootstrap P(\u0394>0)</dt><dd>${format(comparison.bootstrap.probabilityPositive, 4)}</dd><dt>Holm p</dt><dd>${format(comparison.bootstrap.holmAdjustedPValue, 4)}</dd></dl><p>${comparison.selection.failedRules.length ? escapeHtml(comparison.selection.failedRules.map((rule) => `${rule.scope}.${rule.metric} ${rule.expected}`).join("; ")) : "All preregistered rules passed."}</p></article>`
|
|
1777
|
+
(comparison) => `<article class="card"><h3>${escapeHtml(comparison.candidateId)} vs ${escapeHtml(comparison.controlId)}</h3><p class="verdict ${comparison.selection.passed ? "positive" : "negative"}">${comparison.selection.passed ? "PASS selection" : "REJECT selection"}</p><dl><dt>Matched</dt><dd>${comparison.matched}</dd><dt>Control only</dt><dd>${comparison.controlOnly}</dd><dt>Candidate only</dt><dd>${comparison.candidateOnly}</dd><dt>Identity retained</dt><dd>${format(comparison.matchedIdentityPctOfControl)}%</dd><dt>Exit reason changes</dt><dd>${comparison.matchedPairs.filter((pair) => pair.exitReasonChanged).length}</dd><dt>Exit code changes</dt><dd>${comparison.matchedPairs.filter((pair) => pair.exitCodeChanged).length}</dd><dt>Matched \u0394PnL</dt><dd>${format(comparison.cohorts.ALL.matchedPnlDelta)}</dd><dt>Removed control PnL</dt><dd>${format(comparison.cohorts.ALL.controlOnlyPnl)}</dd><dt>Added candidate PnL</dt><dd>${format(comparison.cohorts.ALL.candidateOnlyPnl)}</dd><dt>Aggregate \u0394PnL</dt><dd>${format(comparison.cohorts.ALL.delta.pnl)}</dd><dt>Aggregate \u0394DD</dt><dd>${format(comparison.cohorts.ALL.delta.realizedMaxDrawdown)}</dd><dt>Bootstrap P(\u0394>0)</dt><dd>${format(comparison.bootstrap.probabilityPositive, 4)}</dd><dt>Holm p</dt><dd>${format(comparison.bootstrap.holmAdjustedPValue, 4)}</dd></dl><p>${comparison.selection.failedRules.length ? escapeHtml(comparison.selection.failedRules.map((rule) => `${rule.scope}.${rule.metric} ${rule.expected}`).join("; ")) : "All preregistered rules passed."}</p></article>`
|
|
1766
1778
|
).join("");
|
|
1767
1779
|
var regimeRows = (variants) => {
|
|
1768
1780
|
const keys = [
|
|
@@ -1776,7 +1788,7 @@ var regimeRows = (variants) => {
|
|
|
1776
1788
|
).join("");
|
|
1777
1789
|
};
|
|
1778
1790
|
var traceRows = (variants) => variants.map(
|
|
1779
|
-
(variant) => `<tr><td>${escapeHtml(variant.variant.label)}</td><td>${escapeHtml(variant.reconciliation.status)}</td><td>${escapeHtml(JSON.stringify(variant.setupIdentitySources))}</td><td>${escapeHtml(JSON.stringify(variant.traceFunnel.events))}</td><td>${escapeHtml(JSON.stringify(variant.traceFunnel.skipCounts))}</td><td>${escapeHtml(variant.latestSignalTimeRegime?.key ?? "n/a")}</td></tr>`
|
|
1791
|
+
(variant) => `<tr><td>${escapeHtml(variant.variant.label)}</td><td>${escapeHtml(variant.reconciliation.status)}</td><td>${escapeHtml(JSON.stringify(variant.setupIdentitySources))}</td><td>${escapeHtml(JSON.stringify(variant.traceFunnel.events))}</td><td>${escapeHtml(JSON.stringify(variant.traceFunnel.skipCounts))}</td><td>${escapeHtml(JSON.stringify(variant.traceFunnel.exitCodes))}</td><td>${escapeHtml(variant.latestSignalTimeRegime?.key ?? "n/a")}</td></tr>`
|
|
1780
1792
|
).join("");
|
|
1781
1793
|
var buildCoreResearchHtml = (params) => {
|
|
1782
1794
|
const { spec, result, tradesByVariant } = params;
|
|
@@ -1802,7 +1814,7 @@ var buildCoreResearchHtml = (params) => {
|
|
|
1802
1814
|
([key, value]) => `<span class="${value === "present" ? "positive" : "negative"}">${escapeHtml(key)}: ${value}</span>`
|
|
1803
1815
|
).join(
|
|
1804
1816
|
""
|
|
1805
|
-
)}</section><h2>ALL equity</h2>${buildCurveSvg(tradesByVariant, "ALL", "equity")}<h2>ALL realized drawdown</h2>${buildCurveSvg(tradesByVariant, "ALL", "drawdown")}<h2>LONG equity</h2>${buildCurveSvg(tradesByVariant, "LONG", "equity")}<h2>LONG realized drawdown</h2>${buildCurveSvg(tradesByVariant, "LONG", "drawdown")}<h2>SHORT equity</h2>${buildCurveSvg(tradesByVariant, "SHORT", "equity")}<h2>SHORT realized drawdown</h2>${buildCurveSvg(tradesByVariant, "SHORT", "drawdown")}<h2>Fixed cohort metrics</h2><p class="muted">Avg PnL/trade = cohort PnL / cohort
|
|
1817
|
+
)}</section><h2>ALL equity</h2>${buildCurveSvg(tradesByVariant, "ALL", "equity")}<h2>ALL realized drawdown</h2>${buildCurveSvg(tradesByVariant, "ALL", "drawdown")}<h2>LONG equity</h2>${buildCurveSvg(tradesByVariant, "LONG", "equity")}<h2>LONG realized drawdown</h2>${buildCurveSvg(tradesByVariant, "LONG", "drawdown")}<h2>SHORT equity</h2>${buildCurveSvg(tradesByVariant, "SHORT", "equity")}<h2>SHORT realized drawdown</h2>${buildCurveSvg(tradesByVariant, "SHORT", "drawdown")}<h2>Fixed cohort metrics</h2><p class="muted">Avg PnL/trade = cohort PnL / cohort completed positions. ALL drawdown is aggregate portfolio; LONG/SHORT drawdowns are side-only.</p><div class="scroll"><table><thead><tr><th>Variant</th><th>Window</th><th>Cohort</th><th>N</th><th>PnL</th><th>Avg PnL/trade</th><th>PF</th><th>WR</th><th>Realized DD</th><th>Cad/day</th><th>Avg win</th><th>Avg loss</th><th>Payoff</th><th>Median</th><th>P05</th><th>P95</th><th>Median hold h</th><th>Max loss streak</th></tr></thead><tbody>${allRows}</tbody></table></div><h2>Fold and monthly robustness</h2><div class="scroll"><table><thead><tr><th>Variant</th><th>Window</th><th>Cohort</th><th>N</th><th>PnL</th><th>Avg PnL/trade</th><th>PF</th><th>WR</th><th>Realized DD</th><th>Cad/day</th><th>Avg win</th><th>Avg loss</th><th>Payoff</th><th>Median</th><th>P05</th><th>P95</th><th>Median hold h</th><th>Max loss streak</th></tr></thead><tbody>${robustnessRows}</tbody></table></div><h2>Cost stress</h2><div class="scroll"><table><thead><tr><th>Variant</th><th>Extra round-trip bps</th><th>N</th><th>PnL</th><th>Avg PnL/trade</th><th>PF</th><th>Realized DD</th></tr></thead><tbody>${costRows}</tbody></table></div><h2>Signal-time market regimes</h2><div class="scroll"><table><thead><tr><th>Trend | Volatility | Breadth | Derivatives</th><th>Variant</th><th>N</th><th>PnL</th><th>PF</th><th>WR</th></tr></thead><tbody>${regimeRows(result.variants)}</tbody></table></div><h2>Trace funnel and reconciliation</h2><div class="scroll"><table><thead><tr><th>Variant</th><th>Reconcile</th><th>Setup identity source</th><th>Events</th><th>Top skips</th><th>Exit codes</th><th>Latest signal-time regime</th></tr></thead><tbody>${traceRows(result.variants)}</tbody></table></div><h2>Multiple testing / overfitting</h2><pre>${escapeHtml(JSON.stringify({ multipleTesting: result.multipleTesting, overfittingDiagnostics: result.overfittingDiagnostics }, null, 2))}</pre><h2>Lineage</h2><pre>${escapeHtml(JSON.stringify({ stage: spec.stage, universeSha256: spec.universe.sha256, lineage: spec.lineage ?? null, artifactHashes: result.artifactHashes }, null, 2))}</pre></main></body></html>`;
|
|
1806
1818
|
};
|
|
1807
1819
|
|
|
1808
1820
|
// src/lib/backtest/checkpoint.ts
|
|
@@ -2108,8 +2120,9 @@ var applyCoreResearchRobustnessGuardrails = (params) => {
|
|
|
2108
2120
|
var import_promises3 = __toESM(require("fs/promises"));
|
|
2109
2121
|
var import_node_path4 = __toESM(require("path"));
|
|
2110
2122
|
var summarizeCoreResearchTrace = async (filePaths = []) => {
|
|
2111
|
-
const events =
|
|
2112
|
-
const skipCounts =
|
|
2123
|
+
const events = /* @__PURE__ */ Object.create(null);
|
|
2124
|
+
const skipCounts = /* @__PURE__ */ Object.create(null);
|
|
2125
|
+
const exitCodes = /* @__PURE__ */ Object.create(null);
|
|
2113
2126
|
for (const inputPath of filePaths) {
|
|
2114
2127
|
const filePath = import_node_path4.default.resolve(inputPath);
|
|
2115
2128
|
const text = await import_promises3.default.readFile(filePath, "utf8");
|
|
@@ -2129,6 +2142,9 @@ var summarizeCoreResearchTrace = async (filePaths = []) => {
|
|
|
2129
2142
|
skipCounts[reason] = (skipCounts[reason] ?? 0) + count;
|
|
2130
2143
|
}
|
|
2131
2144
|
}
|
|
2145
|
+
if (event.event === "position_exited" && event.exitCode) {
|
|
2146
|
+
exitCodes[event.exitCode] = (exitCodes[event.exitCode] ?? 0) + 1;
|
|
2147
|
+
}
|
|
2132
2148
|
}
|
|
2133
2149
|
}
|
|
2134
2150
|
return {
|
|
@@ -2137,6 +2153,11 @@ var summarizeCoreResearchTrace = async (filePaths = []) => {
|
|
|
2137
2153
|
Object.entries(skipCounts).sort(
|
|
2138
2154
|
([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
|
|
2139
2155
|
)
|
|
2156
|
+
),
|
|
2157
|
+
exitCodes: Object.fromEntries(
|
|
2158
|
+
Object.entries(exitCodes).sort(
|
|
2159
|
+
([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
|
|
2160
|
+
)
|
|
2140
2161
|
)
|
|
2141
2162
|
};
|
|
2142
2163
|
};
|
|
@@ -682,7 +682,12 @@ var writeCoreResearchMatches = async (params) => {
|
|
|
682
682
|
"controlPnl",
|
|
683
683
|
"candidatePnl",
|
|
684
684
|
"pnlDelta",
|
|
685
|
-
"
|
|
685
|
+
"controlExitReason",
|
|
686
|
+
"candidateExitReason",
|
|
687
|
+
"exitReasonChanged",
|
|
688
|
+
"controlExitCode",
|
|
689
|
+
"candidateExitCode",
|
|
690
|
+
"exitCodeChanged"
|
|
686
691
|
].map(csv).join(",") + "\n"
|
|
687
692
|
);
|
|
688
693
|
for (const comparison of params.comparisons) {
|
|
@@ -700,7 +705,12 @@ var writeCoreResearchMatches = async (params) => {
|
|
|
700
705
|
pair.control.netProfit,
|
|
701
706
|
pair.candidate.netProfit,
|
|
702
707
|
pair.pnlDelta,
|
|
703
|
-
pair.
|
|
708
|
+
pair.control.exitReason,
|
|
709
|
+
pair.candidate.exitReason,
|
|
710
|
+
pair.exitReasonChanged,
|
|
711
|
+
pair.control.exitCode,
|
|
712
|
+
pair.candidate.exitCode,
|
|
713
|
+
pair.exitCodeChanged
|
|
704
714
|
].map(csv).join(",") + "\n"
|
|
705
715
|
);
|
|
706
716
|
}
|
|
@@ -1317,6 +1327,7 @@ var compareCoreResearchVariants = (params) => {
|
|
|
1317
1327
|
candidate: candidateTrade,
|
|
1318
1328
|
pnlDelta: candidateTrade.netProfit - controlTrade.netProfit,
|
|
1319
1329
|
exitReasonChanged: candidateTrade.exitReason !== controlTrade.exitReason,
|
|
1330
|
+
exitCodeChanged: candidateTrade.exitCode !== controlTrade.exitCode,
|
|
1320
1331
|
entryTimestampDeltaMs: candidateTrade.entryTimestamp - controlTrade.entryTimestamp,
|
|
1321
1332
|
exitTimestampDeltaMs: candidateTrade.exitTimestamp - controlTrade.exitTimestamp
|
|
1322
1333
|
});
|
|
@@ -1528,6 +1539,7 @@ var normalizeCompletedTrade = (params) => {
|
|
|
1528
1539
|
"totalSlippageCost"
|
|
1529
1540
|
),
|
|
1530
1541
|
exitReason: result.exitReason,
|
|
1542
|
+
...result.exitCode ? { exitCode: result.exitCode } : {},
|
|
1531
1543
|
regime: resolveCoreResearchRegime(row)
|
|
1532
1544
|
};
|
|
1533
1545
|
};
|
|
@@ -1571,7 +1583,7 @@ var aggregatePositionCycles = (trades) => {
|
|
|
1571
1583
|
}
|
|
1572
1584
|
const primary = primaryRows[0];
|
|
1573
1585
|
if (cycle.some(
|
|
1574
|
-
(trade) => trade.exitTimestamp !== primary.exitTimestamp || trade.exitReason !== primary.exitReason
|
|
1586
|
+
(trade) => trade.exitTimestamp !== primary.exitTimestamp || trade.exitReason !== primary.exitReason || trade.exitCode !== primary.exitCode
|
|
1575
1587
|
)) {
|
|
1576
1588
|
throw new Error(
|
|
1577
1589
|
`Position cycle ${identity} contains inconsistent final exits`
|
|
@@ -1753,7 +1765,7 @@ var buildCurveSvg = (tradesByVariant, cohort, curve) => {
|
|
|
1753
1765
|
)}</svg><div class="legend">${series.map((entry) => `<span><i style="background:${entry.color}"></i>${escapeHtml(entry.id)}</span>`).join("")}</div>`;
|
|
1754
1766
|
};
|
|
1755
1767
|
var comparisonCards = (comparisons) => comparisons.map(
|
|
1756
|
-
(comparison) => `<article class="card"><h3>${escapeHtml(comparison.candidateId)} vs ${escapeHtml(comparison.controlId)}</h3><p class="verdict ${comparison.selection.passed ? "positive" : "negative"}">${comparison.selection.passed ? "PASS selection" : "REJECT selection"}</p><dl><dt>Matched</dt><dd>${comparison.matched}</dd><dt>Control only</dt><dd>${comparison.controlOnly}</dd><dt>Candidate only</dt><dd>${comparison.candidateOnly}</dd><dt>Identity retained</dt><dd>${format(comparison.matchedIdentityPctOfControl)}%</dd><dt>Matched \u0394PnL</dt><dd>${format(comparison.cohorts.ALL.matchedPnlDelta)}</dd><dt>Removed control PnL</dt><dd>${format(comparison.cohorts.ALL.controlOnlyPnl)}</dd><dt>Added candidate PnL</dt><dd>${format(comparison.cohorts.ALL.candidateOnlyPnl)}</dd><dt>Aggregate \u0394PnL</dt><dd>${format(comparison.cohorts.ALL.delta.pnl)}</dd><dt>Aggregate \u0394DD</dt><dd>${format(comparison.cohorts.ALL.delta.realizedMaxDrawdown)}</dd><dt>Bootstrap P(\u0394>0)</dt><dd>${format(comparison.bootstrap.probabilityPositive, 4)}</dd><dt>Holm p</dt><dd>${format(comparison.bootstrap.holmAdjustedPValue, 4)}</dd></dl><p>${comparison.selection.failedRules.length ? escapeHtml(comparison.selection.failedRules.map((rule) => `${rule.scope}.${rule.metric} ${rule.expected}`).join("; ")) : "All preregistered rules passed."}</p></article>`
|
|
1768
|
+
(comparison) => `<article class="card"><h3>${escapeHtml(comparison.candidateId)} vs ${escapeHtml(comparison.controlId)}</h3><p class="verdict ${comparison.selection.passed ? "positive" : "negative"}">${comparison.selection.passed ? "PASS selection" : "REJECT selection"}</p><dl><dt>Matched</dt><dd>${comparison.matched}</dd><dt>Control only</dt><dd>${comparison.controlOnly}</dd><dt>Candidate only</dt><dd>${comparison.candidateOnly}</dd><dt>Identity retained</dt><dd>${format(comparison.matchedIdentityPctOfControl)}%</dd><dt>Exit reason changes</dt><dd>${comparison.matchedPairs.filter((pair) => pair.exitReasonChanged).length}</dd><dt>Exit code changes</dt><dd>${comparison.matchedPairs.filter((pair) => pair.exitCodeChanged).length}</dd><dt>Matched \u0394PnL</dt><dd>${format(comparison.cohorts.ALL.matchedPnlDelta)}</dd><dt>Removed control PnL</dt><dd>${format(comparison.cohorts.ALL.controlOnlyPnl)}</dd><dt>Added candidate PnL</dt><dd>${format(comparison.cohorts.ALL.candidateOnlyPnl)}</dd><dt>Aggregate \u0394PnL</dt><dd>${format(comparison.cohorts.ALL.delta.pnl)}</dd><dt>Aggregate \u0394DD</dt><dd>${format(comparison.cohorts.ALL.delta.realizedMaxDrawdown)}</dd><dt>Bootstrap P(\u0394>0)</dt><dd>${format(comparison.bootstrap.probabilityPositive, 4)}</dd><dt>Holm p</dt><dd>${format(comparison.bootstrap.holmAdjustedPValue, 4)}</dd></dl><p>${comparison.selection.failedRules.length ? escapeHtml(comparison.selection.failedRules.map((rule) => `${rule.scope}.${rule.metric} ${rule.expected}`).join("; ")) : "All preregistered rules passed."}</p></article>`
|
|
1757
1769
|
).join("");
|
|
1758
1770
|
var regimeRows = (variants) => {
|
|
1759
1771
|
const keys = [
|
|
@@ -1767,7 +1779,7 @@ var regimeRows = (variants) => {
|
|
|
1767
1779
|
).join("");
|
|
1768
1780
|
};
|
|
1769
1781
|
var traceRows = (variants) => variants.map(
|
|
1770
|
-
(variant) => `<tr><td>${escapeHtml(variant.variant.label)}</td><td>${escapeHtml(variant.reconciliation.status)}</td><td>${escapeHtml(JSON.stringify(variant.setupIdentitySources))}</td><td>${escapeHtml(JSON.stringify(variant.traceFunnel.events))}</td><td>${escapeHtml(JSON.stringify(variant.traceFunnel.skipCounts))}</td><td>${escapeHtml(variant.latestSignalTimeRegime?.key ?? "n/a")}</td></tr>`
|
|
1782
|
+
(variant) => `<tr><td>${escapeHtml(variant.variant.label)}</td><td>${escapeHtml(variant.reconciliation.status)}</td><td>${escapeHtml(JSON.stringify(variant.setupIdentitySources))}</td><td>${escapeHtml(JSON.stringify(variant.traceFunnel.events))}</td><td>${escapeHtml(JSON.stringify(variant.traceFunnel.skipCounts))}</td><td>${escapeHtml(JSON.stringify(variant.traceFunnel.exitCodes))}</td><td>${escapeHtml(variant.latestSignalTimeRegime?.key ?? "n/a")}</td></tr>`
|
|
1771
1783
|
).join("");
|
|
1772
1784
|
var buildCoreResearchHtml = (params) => {
|
|
1773
1785
|
const { spec, result, tradesByVariant } = params;
|
|
@@ -1793,7 +1805,7 @@ var buildCoreResearchHtml = (params) => {
|
|
|
1793
1805
|
([key, value]) => `<span class="${value === "present" ? "positive" : "negative"}">${escapeHtml(key)}: ${value}</span>`
|
|
1794
1806
|
).join(
|
|
1795
1807
|
""
|
|
1796
|
-
)}</section><h2>ALL equity</h2>${buildCurveSvg(tradesByVariant, "ALL", "equity")}<h2>ALL realized drawdown</h2>${buildCurveSvg(tradesByVariant, "ALL", "drawdown")}<h2>LONG equity</h2>${buildCurveSvg(tradesByVariant, "LONG", "equity")}<h2>LONG realized drawdown</h2>${buildCurveSvg(tradesByVariant, "LONG", "drawdown")}<h2>SHORT equity</h2>${buildCurveSvg(tradesByVariant, "SHORT", "equity")}<h2>SHORT realized drawdown</h2>${buildCurveSvg(tradesByVariant, "SHORT", "drawdown")}<h2>Fixed cohort metrics</h2><p class="muted">Avg PnL/trade = cohort PnL / cohort
|
|
1808
|
+
)}</section><h2>ALL equity</h2>${buildCurveSvg(tradesByVariant, "ALL", "equity")}<h2>ALL realized drawdown</h2>${buildCurveSvg(tradesByVariant, "ALL", "drawdown")}<h2>LONG equity</h2>${buildCurveSvg(tradesByVariant, "LONG", "equity")}<h2>LONG realized drawdown</h2>${buildCurveSvg(tradesByVariant, "LONG", "drawdown")}<h2>SHORT equity</h2>${buildCurveSvg(tradesByVariant, "SHORT", "equity")}<h2>SHORT realized drawdown</h2>${buildCurveSvg(tradesByVariant, "SHORT", "drawdown")}<h2>Fixed cohort metrics</h2><p class="muted">Avg PnL/trade = cohort PnL / cohort completed positions. ALL drawdown is aggregate portfolio; LONG/SHORT drawdowns are side-only.</p><div class="scroll"><table><thead><tr><th>Variant</th><th>Window</th><th>Cohort</th><th>N</th><th>PnL</th><th>Avg PnL/trade</th><th>PF</th><th>WR</th><th>Realized DD</th><th>Cad/day</th><th>Avg win</th><th>Avg loss</th><th>Payoff</th><th>Median</th><th>P05</th><th>P95</th><th>Median hold h</th><th>Max loss streak</th></tr></thead><tbody>${allRows}</tbody></table></div><h2>Fold and monthly robustness</h2><div class="scroll"><table><thead><tr><th>Variant</th><th>Window</th><th>Cohort</th><th>N</th><th>PnL</th><th>Avg PnL/trade</th><th>PF</th><th>WR</th><th>Realized DD</th><th>Cad/day</th><th>Avg win</th><th>Avg loss</th><th>Payoff</th><th>Median</th><th>P05</th><th>P95</th><th>Median hold h</th><th>Max loss streak</th></tr></thead><tbody>${robustnessRows}</tbody></table></div><h2>Cost stress</h2><div class="scroll"><table><thead><tr><th>Variant</th><th>Extra round-trip bps</th><th>N</th><th>PnL</th><th>Avg PnL/trade</th><th>PF</th><th>Realized DD</th></tr></thead><tbody>${costRows}</tbody></table></div><h2>Signal-time market regimes</h2><div class="scroll"><table><thead><tr><th>Trend | Volatility | Breadth | Derivatives</th><th>Variant</th><th>N</th><th>PnL</th><th>PF</th><th>WR</th></tr></thead><tbody>${regimeRows(result.variants)}</tbody></table></div><h2>Trace funnel and reconciliation</h2><div class="scroll"><table><thead><tr><th>Variant</th><th>Reconcile</th><th>Setup identity source</th><th>Events</th><th>Top skips</th><th>Exit codes</th><th>Latest signal-time regime</th></tr></thead><tbody>${traceRows(result.variants)}</tbody></table></div><h2>Multiple testing / overfitting</h2><pre>${escapeHtml(JSON.stringify({ multipleTesting: result.multipleTesting, overfittingDiagnostics: result.overfittingDiagnostics }, null, 2))}</pre><h2>Lineage</h2><pre>${escapeHtml(JSON.stringify({ stage: spec.stage, universeSha256: spec.universe.sha256, lineage: spec.lineage ?? null, artifactHashes: result.artifactHashes }, null, 2))}</pre></main></body></html>`;
|
|
1797
1809
|
};
|
|
1798
1810
|
|
|
1799
1811
|
// src/lib/backtest/checkpoint.ts
|
|
@@ -2099,8 +2111,9 @@ var applyCoreResearchRobustnessGuardrails = (params) => {
|
|
|
2099
2111
|
var import_promises3 = __toESM(require("fs/promises"));
|
|
2100
2112
|
var import_node_path4 = __toESM(require("path"));
|
|
2101
2113
|
var summarizeCoreResearchTrace = async (filePaths = []) => {
|
|
2102
|
-
const events =
|
|
2103
|
-
const skipCounts =
|
|
2114
|
+
const events = /* @__PURE__ */ Object.create(null);
|
|
2115
|
+
const skipCounts = /* @__PURE__ */ Object.create(null);
|
|
2116
|
+
const exitCodes = /* @__PURE__ */ Object.create(null);
|
|
2104
2117
|
for (const inputPath of filePaths) {
|
|
2105
2118
|
const filePath = import_node_path4.default.resolve(inputPath);
|
|
2106
2119
|
const text = await import_promises3.default.readFile(filePath, "utf8");
|
|
@@ -2120,6 +2133,9 @@ var summarizeCoreResearchTrace = async (filePaths = []) => {
|
|
|
2120
2133
|
skipCounts[reason] = (skipCounts[reason] ?? 0) + count;
|
|
2121
2134
|
}
|
|
2122
2135
|
}
|
|
2136
|
+
if (event.event === "position_exited" && event.exitCode) {
|
|
2137
|
+
exitCodes[event.exitCode] = (exitCodes[event.exitCode] ?? 0) + 1;
|
|
2138
|
+
}
|
|
2123
2139
|
}
|
|
2124
2140
|
}
|
|
2125
2141
|
return {
|
|
@@ -2128,6 +2144,11 @@ var summarizeCoreResearchTrace = async (filePaths = []) => {
|
|
|
2128
2144
|
Object.entries(skipCounts).sort(
|
|
2129
2145
|
([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
|
|
2130
2146
|
)
|
|
2147
|
+
),
|
|
2148
|
+
exitCodes: Object.fromEntries(
|
|
2149
|
+
Object.entries(exitCodes).sort(
|
|
2150
|
+
([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
|
|
2151
|
+
)
|
|
2131
2152
|
)
|
|
2132
2153
|
};
|
|
2133
2154
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/cli",
|
|
3
|
-
"version": "3.1.29-beta.
|
|
3
|
+
"version": "3.1.29-beta.268",
|
|
4
4
|
"description": "Official CLI for the TradeJS TypeScript framework: infra setup, backtests, signals, bots, and ML workflows.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tradejs",
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
"tradejs": "dist/cli.js"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@tradejs/connectors": "^3.1.29-beta.
|
|
41
|
-
"@tradejs/core": "^3.1.29-beta.
|
|
42
|
-
"@tradejs/indicators": "^3.1.29-beta.
|
|
43
|
-
"@tradejs/infra": "^3.1.29-beta.
|
|
44
|
-
"@tradejs/node": "^3.1.29-beta.
|
|
40
|
+
"@tradejs/connectors": "^3.1.29-beta.268",
|
|
41
|
+
"@tradejs/core": "^3.1.29-beta.268",
|
|
42
|
+
"@tradejs/indicators": "^3.1.29-beta.268",
|
|
43
|
+
"@tradejs/infra": "^3.1.29-beta.268",
|
|
44
|
+
"@tradejs/node": "^3.1.29-beta.268",
|
|
45
45
|
"@tradejs/strategy-kit": "3.0.6",
|
|
46
|
-
"@tradejs/types": "^3.1.29-beta.
|
|
46
|
+
"@tradejs/types": "^3.1.29-beta.268",
|
|
47
47
|
"args": "^5.0.3",
|
|
48
48
|
"bcryptjs": "^2.4.3",
|
|
49
49
|
"chalk": "4.1.2",
|