@tradejs/cli 3.1.29-beta.290 → 3.1.29-beta.291

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.
@@ -34,6 +34,7 @@ __export(aiPocketSearch_exports, {
34
34
  module.exports = __toCommonJS(aiPocketSearch_exports);
35
35
 
36
36
  // src/lib/aiPocketSearch/features.ts
37
+ var import_aiFeatures = require("@tradejs/core/aiFeatures");
37
38
  var DAY_MS = 24 * 60 * 60 * 1e3;
38
39
  var DAYS_PER_WEEK = 7;
39
40
  var DAYS_PER_MONTH = 30.4375;
@@ -402,15 +403,25 @@ var addFlattenedFeatures = ({
402
403
  value,
403
404
  segments,
404
405
  maxDepth,
405
- shouldSkipPath = () => false
406
+ shouldSkipPath = () => false,
407
+ onFeatureExcluded
406
408
  }) => {
407
409
  if (!segments.length && !isPlainRecord(value)) {
408
410
  return;
409
411
  }
410
- if (segments.length > maxDepth || isOutcomePath(segments) || shouldSkipPath(segments)) {
412
+ if (segments.length > maxDepth || isOutcomePath(segments)) {
413
+ onFeatureExcluded?.({
414
+ path: segments.join("."),
415
+ classification: segments.length > maxDepth ? "depth-limit" : "derived-policy"
416
+ });
411
417
  return;
412
418
  }
419
+ if (shouldSkipPath(segments)) return;
413
420
  if (Array.isArray(value)) {
421
+ onFeatureExcluded?.({
422
+ path: segments.join("."),
423
+ classification: "unprojected-array"
424
+ });
414
425
  return;
415
426
  }
416
427
  if (isFeaturePrimitive(value)) {
@@ -432,7 +443,8 @@ var addFlattenedFeatures = ({
432
443
  value: child,
433
444
  segments: [...segments, key],
434
445
  maxDepth,
435
- shouldSkipPath
446
+ shouldSkipPath,
447
+ onFeatureExcluded
436
448
  });
437
449
  }
438
450
  };
@@ -644,7 +656,10 @@ var collectAiPocketFeatureSnapshot = ({
644
656
  value: source,
645
657
  segments: [],
646
658
  maxDepth: 8,
659
+ onFeatureExcluded,
647
660
  shouldSkipPath: (segments) => {
661
+ if (segments.join(".") === "additionalIndicators.baseContext.tickerProfile" || segments.join(".") === "additionalIndicators.tickerProfile" || segments.join(".") === "additionalIndicators.portfolioContext")
662
+ return true;
648
663
  if (isOperatorExcluded(segments.join("."))) {
649
664
  return true;
650
665
  }
@@ -662,6 +677,10 @@ var collectAiPocketFeatureSnapshot = ({
662
677
  return true;
663
678
  }
664
679
  if (featureProfile === "compact" && isCompactFeaturePathSkipped(segments)) {
680
+ onFeatureExcluded?.({
681
+ path: segments.join("."),
682
+ classification: "compact-profile"
683
+ });
665
684
  return true;
666
685
  }
667
686
  if (featurePolicy !== "causal-stationary") {
@@ -696,6 +715,21 @@ var collectAiPocketFeatureSnapshot = ({
696
715
  delete features[key];
697
716
  }
698
717
  }
718
+ const registered = payload.featureSnapshot;
719
+ if (registered) {
720
+ (0, import_aiFeatures.validateAiFeatureSnapshot)(registered);
721
+ for (const definition of registered.definitions) {
722
+ const path = `registered.${definition.id}`;
723
+ if (isOperatorExcluded(path)) continue;
724
+ const value = registered.values[definition.id];
725
+ const classification = definition.role === "outcome" || definition.role === "policy" ? "derived-policy" : definition.role !== "input" ? definition.role : featurePolicy === "causal-stationary" && !definition.stationary ? "raw-nonstationary" : value === null || value === "unknown" ? "data-quality" : "eligible";
726
+ if (classification !== "eligible") {
727
+ onFeatureExcluded?.({ path, classification });
728
+ continue;
729
+ }
730
+ features[path] = value;
731
+ }
732
+ }
699
733
  return { features, featureCoverage };
700
734
  };
701
735
  var collectAiPocketFeatures = (options) => collectAiPocketFeatureSnapshot(options).features;
@@ -27,6 +27,7 @@ var extractSignalFromAiDatasetRow = (row) => {
27
27
  const { payload } = row;
28
28
  return {
29
29
  ...payload.signal,
30
+ aiFeatureReplay: { snapshot: payload.featureSnapshot ?? null },
30
31
  strategy: payload.signal.strategy,
31
32
  figures: payload.figures ?? {},
32
33
  indicators: payload.indicators ?? {},
@@ -30,7 +30,9 @@ var BASE_CONTEXT_FEATURE_SECTIONS = [
30
30
  "relative",
31
31
  "derivatives",
32
32
  "mtf",
33
- "gateFeatures"
33
+ "gateFeatures",
34
+ "tickerProfile",
35
+ "portfolioContext"
34
36
  ];
35
37
  var asRecord = (value) => typeof value === "object" && value != null && !Array.isArray(value) ? value : null;
36
38
  var collectStrategyGateFeatures = (baseContext) => {
@@ -47,6 +49,7 @@ var pickBaseContextFeatureSections = (baseContext) => Object.fromEntries(
47
49
  );
48
50
  var buildAiTrainEvaluationFeatureSnapshot = ({
49
51
  additionalIndicators,
52
+ featureSnapshot,
50
53
  mode
51
54
  }) => {
52
55
  if (mode === "none") {
@@ -56,12 +59,14 @@ var buildAiTrainEvaluationFeatureSnapshot = ({
56
59
  const baseContext = asRecord(additional?.baseContext);
57
60
  if (!baseContext) {
58
61
  return {
59
- baseContextAvailable: false
62
+ baseContextAvailable: false,
63
+ ...featureSnapshot ? { featureSnapshot } : {}
60
64
  };
61
65
  }
62
66
  const strategyGateFeatures = collectStrategyGateFeatures(baseContext);
63
67
  const snapshot = {
64
68
  baseContextAvailable: true,
69
+ ...featureSnapshot ? { featureSnapshot } : {},
65
70
  gateFeatures: baseContext.gateFeatures ?? null,
66
71
  ...strategyGateFeatures ? { strategyGateFeatures } : {}
67
72
  };
@@ -405,6 +405,8 @@ var RESEARCH_CONTEXT_ENV_KEYS = [
405
405
  "INTERVAL",
406
406
  "DERIVATIVES_CONTEXT_ENABLED",
407
407
  "DERIVATIVES_CONTEXT_TARGET_ENABLED",
408
+ "TICKER_PROFILES_PROVIDER",
409
+ "TICKER_PROFILES_UNIVERSE",
408
410
  "DERIVATIVES_CONTEXT_LOOKBACK_HOURS",
409
411
  "DERIVATIVES_CONTEXT_EXTRA_REFERENCE_SYMBOLS",
410
412
  "DERIVATIVES_CONTEXT_EXCHANGE_PRIORITY",
@@ -439,13 +441,15 @@ var writeAiTrainResearchSnapshot = async ({
439
441
  }) => {
440
442
  const resolvedPath = import_node_path2.default.resolve(outputPath);
441
443
  await import_promises2.default.mkdir(import_node_path2.default.dirname(resolvedPath), { recursive: true });
442
- await import_promises2.default.writeFile(
443
- resolvedPath,
444
- `${JSON.stringify(result, null, 2)}
445
- `,
446
- "utf8"
447
- );
448
- return resolvedPath;
444
+ const bytes = `${JSON.stringify(result)}
445
+ `;
446
+ await import_promises2.default.writeFile(resolvedPath, bytes, "utf8");
447
+ return {
448
+ schema: "tradejs-research-report-receipt/v1",
449
+ path: resolvedPath,
450
+ bytes: Buffer.byteLength(bytes),
451
+ sha256: (0, import_node_crypto2.createHash)("sha256").update(bytes).digest("hex")
452
+ };
449
453
  };
450
454
  var normalizeForStableJson = (value) => {
451
455
  if (Array.isArray(value)) {
@@ -66,7 +66,7 @@ var import_node_path = __toESM(require("path"));
66
66
 
67
67
  // src/lib/coreResearch/types.ts
68
68
  var CORE_RESEARCH_SCHEMA = "tradejs-core-research/v1";
69
- var CORE_RESEARCH_RESULT_SCHEMA = "tradejs-core-research-result/v1";
69
+ var CORE_RESEARCH_RESULT_SCHEMA = "tradejs-core-research-result/v2";
70
70
  var CORE_RESEARCH_LEDGER_SCHEMA = "tradejs-core-research-ledger/v1";
71
71
 
72
72
  // src/lib/coreResearch/io.ts
@@ -740,6 +740,14 @@ var writeCoreResearchTrades = async (params) => {
740
740
  }
741
741
  await closeOutput(output);
742
742
  };
743
+ var summarizeCoreResearchComparison = (comparison) => {
744
+ const { matchedPairs, ...summary } = comparison;
745
+ return {
746
+ ...summary,
747
+ exitReasonChanges: matchedPairs.filter((pair) => pair.exitReasonChanged).length,
748
+ exitCodeChanges: matchedPairs.filter((pair) => pair.exitCodeChanged).length
749
+ };
750
+ };
743
751
 
744
752
  // src/lib/coreResearch/metrics.ts
745
753
  var DAY_MS = 24 * 60 * 60 * 1e3;
@@ -1815,7 +1823,7 @@ var buildCurveSvg = (tradesByVariant, cohort, curve) => {
1815
1823
  )}</svg><div class="legend">${series.map((entry) => `<span><i style="background:${entry.color}"></i>${escapeHtml(entry.id)}</span>`).join("")}</div>`;
1816
1824
  };
1817
1825
  var comparisonCards = (comparisons) => comparisons.map(
1818
- (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&gt;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>`
1826
+ (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.exitReasonChanges}</dd><dt>Exit code changes</dt><dd>${comparison.exitCodeChanges}</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&gt;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>`
1819
1827
  ).join("");
1820
1828
  var regimeRows = (variants) => {
1821
1829
  const keys = [
@@ -2472,7 +2480,7 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
2472
2480
  regimeCausality: "signal-time payload.additionalIndicators.baseContext only"
2473
2481
  },
2474
2482
  variants: analyses,
2475
- comparisons,
2483
+ comparisons: comparisons.map(summarizeCoreResearchComparison),
2476
2484
  multipleTesting: {
2477
2485
  family: spec.hypothesis.family,
2478
2486
  hypotheses: Math.max(comparisons.length, familyHypotheses),
@@ -2505,7 +2513,7 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
2505
2513
  artifactHashes: sourceHashes
2506
2514
  };
2507
2515
  await writeJsonAtomic(paths.resultPath, result);
2508
- await writeJsonAtomic(paths.comparisonPath, comparisons);
2516
+ await writeJsonAtomic(paths.comparisonPath, result.comparisons);
2509
2517
  await writeCoreResearchMatches({ filePath: paths.matchesPath, comparisons });
2510
2518
  await writeCoreResearchTrades({
2511
2519
  filePath: paths.tradesPath,
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/lib/researchMetricSnapshot.ts
21
+ var researchMetricSnapshot_exports = {};
22
+ __export(researchMetricSnapshot_exports, {
23
+ decodeResearchMetricSnapshot: () => decodeResearchMetricSnapshot,
24
+ encodeResearchMetricSnapshot: () => encodeResearchMetricSnapshot,
25
+ validatePermanentResearchMetrics: () => validatePermanentResearchMetrics
26
+ });
27
+ module.exports = __toCommonJS(researchMetricSnapshot_exports);
28
+ var import_node_crypto = require("crypto");
29
+ var import_node_zlib = require("zlib");
30
+ var MAX_BYTES = 256 * 1024 * 1024;
31
+ var hash = (bytes) => (0, import_node_crypto.createHash)("sha256").update(bytes).digest("hex");
32
+ var validatePermanentResearchMetrics = (value) => {
33
+ if (!value || typeof value !== "object") return;
34
+ for (const [key, child] of Object.entries(value)) {
35
+ if (["matchedPairs", "tradeRows", "allProjectedLeaves"].includes(key) && Array.isArray(child) && child.length)
36
+ throw new Error(`Temporary payload ${key} is not a permanent metric`);
37
+ if (key === "trades" && Array.isArray(child) && child.some(
38
+ (row) => row && typeof row === "object" && ("signalId" in row || "entryTimestamp" in row)
39
+ ))
40
+ throw new Error("Temporary trade records are not permanent metrics");
41
+ validatePermanentResearchMetrics(child);
42
+ }
43
+ };
44
+ var encodeResearchMetricSnapshot = (metrics) => {
45
+ validatePermanentResearchMetrics(metrics);
46
+ const bytes = Buffer.from(JSON.stringify(metrics));
47
+ if (bytes.length > MAX_BYTES)
48
+ throw new Error("Metric snapshot exceeds decoded size limit");
49
+ return {
50
+ schema: "tradejs-metric-snapshot/v1",
51
+ encoding: "gzip+base64",
52
+ decodedBytes: bytes.length,
53
+ sha256: hash(bytes),
54
+ payload: (0, import_node_zlib.gzipSync)(bytes, { level: 9 }).toString("base64")
55
+ };
56
+ };
57
+ var decodeResearchMetricSnapshot = (snapshot) => {
58
+ if (!snapshot || typeof snapshot !== "object" || !("schema" in snapshot) || snapshot.schema !== "tradejs-metric-snapshot/v1" || !("encoding" in snapshot) || snapshot.encoding !== "gzip+base64" || !("decodedBytes" in snapshot) || typeof snapshot.decodedBytes !== "number" || !Number.isSafeInteger(snapshot.decodedBytes) || snapshot.decodedBytes <= 0 || snapshot.decodedBytes > MAX_BYTES || !("sha256" in snapshot) || typeof snapshot.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(snapshot.sha256) || !("payload" in snapshot) || typeof snapshot.payload !== "string")
59
+ throw new Error("Invalid metric snapshot envelope");
60
+ const bytes = (0, import_node_zlib.gunzipSync)(Buffer.from(snapshot.payload, "base64"), {
61
+ maxOutputLength: snapshot.decodedBytes
62
+ });
63
+ if (bytes.length !== snapshot.decodedBytes || hash(bytes) !== snapshot.sha256)
64
+ throw new Error("Metric snapshot checksum or size mismatch");
65
+ const metrics = JSON.parse(bytes.toString("utf8"));
66
+ validatePermanentResearchMetrics(metrics);
67
+ return metrics;
68
+ };
69
+ // Annotate the CommonJS export names for ESM import in node:
70
+ 0 && (module.exports = {
71
+ decodeResearchMetricSnapshot,
72
+ encodeResearchMetricSnapshot,
73
+ validatePermanentResearchMetrics
74
+ });