@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.
- package/dist/cli.js +2337 -1168
- package/dist/lib/aiPocketSearch.js +37 -3
- package/dist/lib/aiTrainDataset.js +1 -0
- package/dist/lib/aiTrainEvaluationDump.js +7 -2
- package/dist/lib/aiTrainResearch.js +11 -7
- package/dist/lib/coreResearch.js +12 -4
- package/dist/lib/researchMetricSnapshot.js +74 -0
- package/dist/lib/researchVisuals.js +910 -0
- package/dist/lib/strategyRelease.js +8 -2
- package/dist/lib/strategyResearch.js +133 -33
- package/dist/lib/tickerProfiles.js +76 -0
- package/dist/scripts/aiPocketSearch.js +38 -3
- package/dist/scripts/aiTrain.js +29 -17
- package/dist/scripts/coreResearch.js +12 -4
- package/dist/scripts/replay.js +53 -4
- package/dist/scripts/replayRunner.js +53 -4
- package/dist/scripts/researchVisuals.js +955 -0
- package/dist/scripts/strategyRelease.js +59 -7
- package/dist/scripts/strategyResearch.js +136 -36
- package/dist/scripts/tickerProfiles.js +114 -0
- package/package.json +8 -7
|
@@ -1355,12 +1355,18 @@ async function collectReleaseEvidenceReferences(references) {
|
|
|
1355
1355
|
}
|
|
1356
1356
|
const nested = (value) => value != null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
1357
1357
|
const array = (value) => Array.isArray(value) ? value : [];
|
|
1358
|
-
const semanticallyValid = reference.kind === "core_research" ?
|
|
1358
|
+
const semanticallyValid = reference.kind === "core_research" ? [
|
|
1359
|
+
"tradejs-core-research-result/v1",
|
|
1360
|
+
"tradejs-core-research-result/v2"
|
|
1361
|
+
].includes(String(artifact.schema)) || artifact.schema === "tradejs-core-research-manifest/v1" && artifact.status === "completed" : reference.kind === "ai_gate" ? nested(artifact.run)?.mode === "local-deterministic" && nested(artifact.research)?.lineage != null && nested(artifact.outcome) != null : reference.kind === "runtime_parity" ? artifact.reportType === "replay-runtime-evidence" && nested(nested(artifact.replay)?.runtimeComparison) != null : reference.kind === "execution_calibration" ? artifact.reportType === "execution-calibration" && nested(artifact.summary) != null : reference.kind === "runtime_evidence" ? artifact.reportType === "runtime-evidence" : artifact.reportType === "runtime-scorecard";
|
|
1359
1362
|
assert2(
|
|
1360
1363
|
semanticallyValid,
|
|
1361
1364
|
`evidence ${reference.artifactId} does not match ${reference.kind}`
|
|
1362
1365
|
);
|
|
1363
|
-
if (reference.kind === "core_research" &&
|
|
1366
|
+
if (reference.kind === "core_research" && [
|
|
1367
|
+
"tradejs-core-research-result/v1",
|
|
1368
|
+
"tradejs-core-research-result/v2"
|
|
1369
|
+
].includes(String(artifact.schema))) {
|
|
1364
1370
|
await verifyCompletedCoreResearchBundle({
|
|
1365
1371
|
artifact,
|
|
1366
1372
|
resultPath: reference.path,
|
|
@@ -75,10 +75,10 @@ var init_io = __esm({
|
|
|
75
75
|
sha256Text = (value) => (0, import_node_crypto.createHash)("sha256").update(value).digest("hex");
|
|
76
76
|
sha256Json = (value) => sha256Text(canonicalJson(value));
|
|
77
77
|
sha256File = async (filePath) => {
|
|
78
|
-
const
|
|
78
|
+
const hash2 = (0, import_node_crypto.createHash)("sha256");
|
|
79
79
|
const input = (0, import_node_fs.createReadStream)(filePath);
|
|
80
|
-
for await (const chunk of input)
|
|
81
|
-
return
|
|
80
|
+
for await (const chunk of input) hash2.update(chunk);
|
|
81
|
+
return hash2.digest("hex");
|
|
82
82
|
};
|
|
83
83
|
assertFinite = (value, name) => {
|
|
84
84
|
assert(typeof value === "number" && Number.isFinite(value), name);
|
|
@@ -336,14 +336,14 @@ __export(io_exports, {
|
|
|
336
336
|
verifyResearchState: () => verifyResearchState,
|
|
337
337
|
withResearchLock: () => withResearchLock
|
|
338
338
|
});
|
|
339
|
-
var import_promises2, import_node_path2, import_node_os,
|
|
339
|
+
var import_promises2, import_node_path2, import_node_os, import_node_crypto3, researchDirectory, readJson, boundResearchPath, withResearchLock, verifyResearchState, verifyCompletedResearch, initializeResearchState, isRetainedDeletion;
|
|
340
340
|
var init_io2 = __esm({
|
|
341
341
|
"src/lib/strategyResearch/io.ts"() {
|
|
342
342
|
"use strict";
|
|
343
343
|
import_promises2 = __toESM(require("fs/promises"));
|
|
344
344
|
import_node_path2 = __toESM(require("path"));
|
|
345
345
|
import_node_os = __toESM(require("os"));
|
|
346
|
-
|
|
346
|
+
import_node_crypto3 = require("crypto");
|
|
347
347
|
init_io();
|
|
348
348
|
researchDirectory = (projectRoot, spec) => import_node_path2.default.join(projectRoot, "data/research/strategy", spec.core.researchId);
|
|
349
349
|
readJson = async (file) => JSON.parse(await import_promises2.default.readFile(file, "utf8"));
|
|
@@ -372,7 +372,7 @@ var init_io2 = __esm({
|
|
|
372
372
|
"data/research/strategy/.lock"
|
|
373
373
|
);
|
|
374
374
|
await import_promises2.default.mkdir(import_node_path2.default.dirname(file), { recursive: true });
|
|
375
|
-
const token = (0,
|
|
375
|
+
const token = (0, import_node_crypto3.randomUUID)();
|
|
376
376
|
const acquire = () => import_promises2.default.writeFile(
|
|
377
377
|
file,
|
|
378
378
|
JSON.stringify({ pid: process.pid, host: import_node_os.default.hostname(), token }),
|
|
@@ -468,15 +468,15 @@ var init_io2 = __esm({
|
|
|
468
468
|
await writeJsonAtomic(file, state);
|
|
469
469
|
return state;
|
|
470
470
|
};
|
|
471
|
-
isRetainedDeletion = async (directory, file,
|
|
471
|
+
isRetainedDeletion = async (directory, file, hash2) => {
|
|
472
472
|
try {
|
|
473
473
|
const inventory = await readJson(import_node_path2.default.join(directory, "retention.json"));
|
|
474
474
|
const index = inventory.entries.findIndex(
|
|
475
|
-
(entry) => entry.path === file && entry.sha256 ===
|
|
475
|
+
(entry) => entry.path === file && entry.sha256 === hash2
|
|
476
476
|
);
|
|
477
477
|
if (index < 0) return false;
|
|
478
478
|
const receipt = await readJson(import_node_path2.default.join(directory, "retention", `${index}.json`));
|
|
479
|
-
return ["applying", "completed"].includes(receipt.status) && receipt.files[0]?.path === file && receipt.files[0]?.sha256 ===
|
|
479
|
+
return ["applying", "completed"].includes(receipt.status) && receipt.files[0]?.path === file && receipt.files[0]?.sha256 === hash2;
|
|
480
480
|
} catch (error) {
|
|
481
481
|
if (error.code === "ENOENT") return false;
|
|
482
482
|
throw error;
|
|
@@ -499,6 +499,7 @@ module.exports = __toCommonJS(strategyResearch_exports);
|
|
|
499
499
|
init_io();
|
|
500
500
|
|
|
501
501
|
// src/lib/aiPocketSearch/features.ts
|
|
502
|
+
var import_aiFeatures = require("@tradejs/core/aiFeatures");
|
|
502
503
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
503
504
|
var DAYS_PER_WEEK = 7;
|
|
504
505
|
var DAYS_PER_MONTH = 30.4375;
|
|
@@ -867,15 +868,25 @@ var addFlattenedFeatures = ({
|
|
|
867
868
|
value,
|
|
868
869
|
segments,
|
|
869
870
|
maxDepth,
|
|
870
|
-
shouldSkipPath = () => false
|
|
871
|
+
shouldSkipPath = () => false,
|
|
872
|
+
onFeatureExcluded
|
|
871
873
|
}) => {
|
|
872
874
|
if (!segments.length && !isPlainRecord(value)) {
|
|
873
875
|
return;
|
|
874
876
|
}
|
|
875
|
-
if (segments.length > maxDepth || isOutcomePath(segments)
|
|
877
|
+
if (segments.length > maxDepth || isOutcomePath(segments)) {
|
|
878
|
+
onFeatureExcluded?.({
|
|
879
|
+
path: segments.join("."),
|
|
880
|
+
classification: segments.length > maxDepth ? "depth-limit" : "derived-policy"
|
|
881
|
+
});
|
|
876
882
|
return;
|
|
877
883
|
}
|
|
884
|
+
if (shouldSkipPath(segments)) return;
|
|
878
885
|
if (Array.isArray(value)) {
|
|
886
|
+
onFeatureExcluded?.({
|
|
887
|
+
path: segments.join("."),
|
|
888
|
+
classification: "unprojected-array"
|
|
889
|
+
});
|
|
879
890
|
return;
|
|
880
891
|
}
|
|
881
892
|
if (isFeaturePrimitive(value)) {
|
|
@@ -897,7 +908,8 @@ var addFlattenedFeatures = ({
|
|
|
897
908
|
value: child,
|
|
898
909
|
segments: [...segments, key],
|
|
899
910
|
maxDepth,
|
|
900
|
-
shouldSkipPath
|
|
911
|
+
shouldSkipPath,
|
|
912
|
+
onFeatureExcluded
|
|
901
913
|
});
|
|
902
914
|
}
|
|
903
915
|
};
|
|
@@ -1109,7 +1121,10 @@ var collectAiPocketFeatureSnapshot = ({
|
|
|
1109
1121
|
value: source,
|
|
1110
1122
|
segments: [],
|
|
1111
1123
|
maxDepth: 8,
|
|
1124
|
+
onFeatureExcluded,
|
|
1112
1125
|
shouldSkipPath: (segments) => {
|
|
1126
|
+
if (segments.join(".") === "additionalIndicators.baseContext.tickerProfile" || segments.join(".") === "additionalIndicators.tickerProfile" || segments.join(".") === "additionalIndicators.portfolioContext")
|
|
1127
|
+
return true;
|
|
1113
1128
|
if (isOperatorExcluded(segments.join("."))) {
|
|
1114
1129
|
return true;
|
|
1115
1130
|
}
|
|
@@ -1127,6 +1142,10 @@ var collectAiPocketFeatureSnapshot = ({
|
|
|
1127
1142
|
return true;
|
|
1128
1143
|
}
|
|
1129
1144
|
if (featureProfile === "compact" && isCompactFeaturePathSkipped(segments)) {
|
|
1145
|
+
onFeatureExcluded?.({
|
|
1146
|
+
path: segments.join("."),
|
|
1147
|
+
classification: "compact-profile"
|
|
1148
|
+
});
|
|
1130
1149
|
return true;
|
|
1131
1150
|
}
|
|
1132
1151
|
if (featurePolicy !== "causal-stationary") {
|
|
@@ -1161,6 +1180,21 @@ var collectAiPocketFeatureSnapshot = ({
|
|
|
1161
1180
|
delete features[key];
|
|
1162
1181
|
}
|
|
1163
1182
|
}
|
|
1183
|
+
const registered = payload.featureSnapshot;
|
|
1184
|
+
if (registered) {
|
|
1185
|
+
(0, import_aiFeatures.validateAiFeatureSnapshot)(registered);
|
|
1186
|
+
for (const definition of registered.definitions) {
|
|
1187
|
+
const path13 = `registered.${definition.id}`;
|
|
1188
|
+
if (isOperatorExcluded(path13)) continue;
|
|
1189
|
+
const value = registered.values[definition.id];
|
|
1190
|
+
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";
|
|
1191
|
+
if (classification !== "eligible") {
|
|
1192
|
+
onFeatureExcluded?.({ path: path13, classification });
|
|
1193
|
+
continue;
|
|
1194
|
+
}
|
|
1195
|
+
features[path13] = value;
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1164
1198
|
return { features, featureCoverage };
|
|
1165
1199
|
};
|
|
1166
1200
|
var collectAiPocketFeatures = (options) => collectAiPocketFeatureSnapshot(options).features;
|
|
@@ -1779,15 +1813,15 @@ var createPocketResult = (rows, predicates, mask, validationRows, testRows, obje
|
|
|
1779
1813
|
};
|
|
1780
1814
|
};
|
|
1781
1815
|
var hashMask = (mask) => {
|
|
1782
|
-
let
|
|
1816
|
+
let hash2 = 2166136261;
|
|
1783
1817
|
for (let index = 0; index < mask.length; index += 1) {
|
|
1784
1818
|
if (mask[index] !== 1) {
|
|
1785
1819
|
continue;
|
|
1786
1820
|
}
|
|
1787
|
-
|
|
1788
|
-
|
|
1821
|
+
hash2 ^= index + 1;
|
|
1822
|
+
hash2 = Math.imul(hash2, 16777619);
|
|
1789
1823
|
}
|
|
1790
|
-
return (
|
|
1824
|
+
return (hash2 >>> 0).toString(36);
|
|
1791
1825
|
};
|
|
1792
1826
|
var isBetterRepresentativePocket = (candidate, existing, compare) => candidate.depth < existing.depth || candidate.depth === existing.depth && candidate.condition.length < existing.condition.length || candidate.depth === existing.depth && candidate.condition.length === existing.condition.length && compare(candidate, existing) < 0;
|
|
1793
1827
|
var estimateCombinationCount = (poolSize, maxDepth, maxCombinations) => {
|
|
@@ -2484,6 +2518,51 @@ var policyVariant = (spec, coreId, policy, id, jev) => {
|
|
|
2484
2518
|
|
|
2485
2519
|
// src/lib/strategyResearch/orchestrator.ts
|
|
2486
2520
|
var import_promises5 = __toESM(require("fs/promises"));
|
|
2521
|
+
|
|
2522
|
+
// src/lib/researchMetricSnapshot.ts
|
|
2523
|
+
var import_node_crypto2 = require("crypto");
|
|
2524
|
+
var import_node_zlib = require("zlib");
|
|
2525
|
+
var MAX_BYTES = 256 * 1024 * 1024;
|
|
2526
|
+
var hash = (bytes) => (0, import_node_crypto2.createHash)("sha256").update(bytes).digest("hex");
|
|
2527
|
+
var validatePermanentResearchMetrics = (value) => {
|
|
2528
|
+
if (!value || typeof value !== "object") return;
|
|
2529
|
+
for (const [key, child] of Object.entries(value)) {
|
|
2530
|
+
if (["matchedPairs", "tradeRows", "allProjectedLeaves"].includes(key) && Array.isArray(child) && child.length)
|
|
2531
|
+
throw new Error(`Temporary payload ${key} is not a permanent metric`);
|
|
2532
|
+
if (key === "trades" && Array.isArray(child) && child.some(
|
|
2533
|
+
(row) => row && typeof row === "object" && ("signalId" in row || "entryTimestamp" in row)
|
|
2534
|
+
))
|
|
2535
|
+
throw new Error("Temporary trade records are not permanent metrics");
|
|
2536
|
+
validatePermanentResearchMetrics(child);
|
|
2537
|
+
}
|
|
2538
|
+
};
|
|
2539
|
+
var encodeResearchMetricSnapshot = (metrics) => {
|
|
2540
|
+
validatePermanentResearchMetrics(metrics);
|
|
2541
|
+
const bytes = Buffer.from(JSON.stringify(metrics));
|
|
2542
|
+
if (bytes.length > MAX_BYTES)
|
|
2543
|
+
throw new Error("Metric snapshot exceeds decoded size limit");
|
|
2544
|
+
return {
|
|
2545
|
+
schema: "tradejs-metric-snapshot/v1",
|
|
2546
|
+
encoding: "gzip+base64",
|
|
2547
|
+
decodedBytes: bytes.length,
|
|
2548
|
+
sha256: hash(bytes),
|
|
2549
|
+
payload: (0, import_node_zlib.gzipSync)(bytes, { level: 9 }).toString("base64")
|
|
2550
|
+
};
|
|
2551
|
+
};
|
|
2552
|
+
var decodeResearchMetricSnapshot = (snapshot) => {
|
|
2553
|
+
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")
|
|
2554
|
+
throw new Error("Invalid metric snapshot envelope");
|
|
2555
|
+
const bytes = (0, import_node_zlib.gunzipSync)(Buffer.from(snapshot.payload, "base64"), {
|
|
2556
|
+
maxOutputLength: snapshot.decodedBytes
|
|
2557
|
+
});
|
|
2558
|
+
if (bytes.length !== snapshot.decodedBytes || hash(bytes) !== snapshot.sha256)
|
|
2559
|
+
throw new Error("Metric snapshot checksum or size mismatch");
|
|
2560
|
+
const metrics = JSON.parse(bytes.toString("utf8"));
|
|
2561
|
+
validatePermanentResearchMetrics(metrics);
|
|
2562
|
+
return metrics;
|
|
2563
|
+
};
|
|
2564
|
+
|
|
2565
|
+
// src/lib/strategyResearch/orchestrator.ts
|
|
2487
2566
|
var import_node_path6 = __toESM(require("path"));
|
|
2488
2567
|
|
|
2489
2568
|
// src/lib/coreResearch/metrics.ts
|
|
@@ -3690,7 +3769,7 @@ var import_node_path5 = __toESM(require("path"));
|
|
|
3690
3769
|
// src/lib/strategyRelease/researchRetention.ts
|
|
3691
3770
|
var import_promises3 = __toESM(require("fs/promises"));
|
|
3692
3771
|
var import_node_path4 = __toESM(require("path"));
|
|
3693
|
-
var
|
|
3772
|
+
var import_node_crypto4 = require("crypto");
|
|
3694
3773
|
var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvidence");
|
|
3695
3774
|
|
|
3696
3775
|
// src/lib/strategyRelease/researchFileConsumers.ts
|
|
@@ -3839,7 +3918,7 @@ var mapFiles = async (entries, visit) => {
|
|
|
3839
3918
|
if (worker.status === "rejected") throw worker.reason;
|
|
3840
3919
|
return results;
|
|
3841
3920
|
};
|
|
3842
|
-
var fileSha256 = async (file, bytes) => bytes <= 1024 * 1024 ? (0,
|
|
3921
|
+
var fileSha256 = async (file, bytes) => bytes <= 1024 * 1024 ? (0, import_node_crypto4.createHash)("sha256").update(await import_promises3.default.readFile(file)).digest("hex") : (0, import_strategyReleaseEvidence.strategyEvidenceFileSha256)(file);
|
|
3843
3922
|
var inside = (root, file) => {
|
|
3844
3923
|
const relative = import_node_path4.default.relative(root, file);
|
|
3845
3924
|
return relative !== "" && !relative.startsWith(`..${import_node_path4.default.sep}`) && relative !== ".." && !import_node_path4.default.isAbsolute(relative);
|
|
@@ -3883,13 +3962,27 @@ var applyResearchRetention = async (options) => {
|
|
|
3883
3962
|
const header = Buffer.alloc(4096);
|
|
3884
3963
|
const { bytesRead } = await handle.read(header, 0, header.length, 0);
|
|
3885
3964
|
const frontmatter = header.subarray(0, bytesRead).toString("utf8").match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
3886
|
-
if (!frontmatter || !/^schema:\s*tradejs-research\/
|
|
3965
|
+
if (!frontmatter || !/^schema:\s*tradejs-research\/v[12]\s*$/m.test(frontmatter[1]) || !(retired ? /^reproduction:\s*(?:complete|partial|blocked|legacy-partial)\s*$/m.test(
|
|
3887
3966
|
frontmatter[1]
|
|
3888
3967
|
) : /^reproduction:\s*complete\s*$/m.test(frontmatter[1]))) {
|
|
3889
3968
|
throw new Error(
|
|
3890
3969
|
`Research note must have reproduction: complete: ${file}`
|
|
3891
3970
|
);
|
|
3892
3971
|
}
|
|
3972
|
+
if (!retired && /^schema:\s*tradejs-research\/v2\s*$/m.test(frontmatter[1])) {
|
|
3973
|
+
if ((await import_promises3.default.stat(file)).size > 8 * 1024 * 1024)
|
|
3974
|
+
throw new Error("Compact permanent note exceeds 8 MiB");
|
|
3975
|
+
const content = await import_promises3.default.readFile(file, "utf8");
|
|
3976
|
+
const section = content.split("## Metrics snapshot (machine-readable)")[1]?.split("## Reported metrics")[0] ?? "";
|
|
3977
|
+
const blocks = [
|
|
3978
|
+
...section.matchAll(/```json\r?\n([\s\S]*?)\r?\n```/g)
|
|
3979
|
+
];
|
|
3980
|
+
if (blocks.length !== 1)
|
|
3981
|
+
throw new Error(
|
|
3982
|
+
"Complete v2 note needs one verified metric snapshot"
|
|
3983
|
+
);
|
|
3984
|
+
decodeResearchMetricSnapshot(JSON.parse(blocks[0][1]));
|
|
3985
|
+
}
|
|
3893
3986
|
} finally {
|
|
3894
3987
|
await handle.close();
|
|
3895
3988
|
}
|
|
@@ -4003,11 +4096,11 @@ var createResearchRetentionInventory = async (projectRoot, directory, spec, stat
|
|
|
4003
4096
|
}
|
|
4004
4097
|
const files = /* @__PURE__ */ new Map();
|
|
4005
4098
|
for (const stage of Object.values(state.stages)) {
|
|
4006
|
-
for (const [relative,
|
|
4099
|
+
for (const [relative, hash2] of Object.entries(stage.artifacts)) {
|
|
4007
4100
|
const file = await boundResearchPath(directory, relative);
|
|
4008
4101
|
if (relative.endsWith("/result.json")) {
|
|
4009
4102
|
const result = await readJson(file);
|
|
4010
|
-
if (result?.dataset) files.set(file,
|
|
4103
|
+
if (result?.dataset) files.set(file, hash2);
|
|
4011
4104
|
}
|
|
4012
4105
|
if (relative.endsWith("/sources.json") || relative.endsWith("/payloads.json")) {
|
|
4013
4106
|
const sources = await readJson(file);
|
|
@@ -4024,13 +4117,13 @@ var createResearchRetentionInventory = async (projectRoot, directory, spec, stat
|
|
|
4024
4117
|
}
|
|
4025
4118
|
}
|
|
4026
4119
|
const entries = [];
|
|
4027
|
-
for (const [file,
|
|
4120
|
+
for (const [file, hash2] of files) {
|
|
4028
4121
|
const stat = await import_promises4.default.stat(file);
|
|
4029
4122
|
entries.push({
|
|
4030
4123
|
path: file,
|
|
4031
4124
|
kind: "research_payload",
|
|
4032
4125
|
researchId: spec.core.researchId,
|
|
4033
|
-
sha256:
|
|
4126
|
+
sha256: hash2,
|
|
4034
4127
|
bytes: stat.size,
|
|
4035
4128
|
createdAt: stat.birthtimeMs,
|
|
4036
4129
|
verified: true,
|
|
@@ -4774,7 +4867,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4774
4867
|
)
|
|
4775
4868
|
};
|
|
4776
4869
|
const note = `---
|
|
4777
|
-
schema: tradejs-research/
|
|
4870
|
+
schema: tradejs-research/v2
|
|
4778
4871
|
strategy: '${spec.core.strategy}'
|
|
4779
4872
|
date: '${spec.core.createdAt.slice(0, 10)}'
|
|
4780
4873
|
kind: 'backtest'
|
|
@@ -4807,7 +4900,7 @@ ${JSON.stringify(spec, null, 2)}
|
|
|
4807
4900
|
## Metrics snapshot (machine-readable)
|
|
4808
4901
|
|
|
4809
4902
|
\`\`\`json
|
|
4810
|
-
${JSON.stringify(compact
|
|
4903
|
+
${JSON.stringify(encodeResearchMetricSnapshot(compact))}
|
|
4811
4904
|
\`\`\`
|
|
4812
4905
|
|
|
4813
4906
|
## Reported metrics
|
|
@@ -4826,6 +4919,10 @@ ${directory}/report.html
|
|
|
4826
4919
|
|
|
4827
4920
|
${conclusion.nextAction} Current-snapshot universe; no deployment authorization. Temporary payloads are deleted only after the permanent record is verified; new trade-level questions require a frozen rerun.
|
|
4828
4921
|
`;
|
|
4922
|
+
if (Buffer.byteLength(note) > 8 * 1024 * 1024)
|
|
4923
|
+
throw new Error(
|
|
4924
|
+
"Compact permanent note exceeds 8 MiB; archive source separately, never truncate metrics"
|
|
4925
|
+
);
|
|
4829
4926
|
await import_promises5.default.writeFile(
|
|
4830
4927
|
import_node_path6.default.join(
|
|
4831
4928
|
noteDirectory,
|
|
@@ -4933,7 +5030,7 @@ var import_registry = require("@tradejs/node/registry");
|
|
|
4933
5030
|
var import_connectors = require("@tradejs/node/connectors");
|
|
4934
5031
|
|
|
4935
5032
|
// src/lib/coreResearch/dataset.ts
|
|
4936
|
-
var
|
|
5033
|
+
var import_node_crypto5 = require("crypto");
|
|
4937
5034
|
var import_node_fs2 = require("fs");
|
|
4938
5035
|
var import_node_path7 = __toESM(require("path"));
|
|
4939
5036
|
var import_node_readline = __toESM(require("readline"));
|
|
@@ -5148,8 +5245,8 @@ var readCoreResearchVariant = async (variant) => {
|
|
|
5148
5245
|
for (const inputPath of variant.files) {
|
|
5149
5246
|
const filePath = import_node_path7.default.resolve(inputPath);
|
|
5150
5247
|
const input = (0, import_node_fs2.createReadStream)(filePath);
|
|
5151
|
-
const
|
|
5152
|
-
input.on("data", (chunk) =>
|
|
5248
|
+
const hash2 = (0, import_node_crypto5.createHash)("sha256");
|
|
5249
|
+
input.on("data", (chunk) => hash2.update(chunk));
|
|
5153
5250
|
const lines = import_node_readline.default.createInterface({ input, crlfDelay: Infinity });
|
|
5154
5251
|
const fileTrades = [];
|
|
5155
5252
|
let lineNumber = 0;
|
|
@@ -5199,7 +5296,7 @@ var readCoreResearchVariant = async (variant) => {
|
|
|
5199
5296
|
trades.push(trade);
|
|
5200
5297
|
fileTrades.push(trade);
|
|
5201
5298
|
}
|
|
5202
|
-
const fileSha2562 =
|
|
5299
|
+
const fileSha2562 = hash2.digest("hex");
|
|
5203
5300
|
for (const trade of fileTrades) trade.sourceSha256 = fileSha2562;
|
|
5204
5301
|
sources.push({
|
|
5205
5302
|
path: filePath,
|
|
@@ -5219,7 +5316,7 @@ var readCoreResearchVariant = async (variant) => {
|
|
|
5219
5316
|
};
|
|
5220
5317
|
|
|
5221
5318
|
// src/lib/backtest/checkpoint.ts
|
|
5222
|
-
var
|
|
5319
|
+
var import_node_crypto6 = require("crypto");
|
|
5223
5320
|
var import_constants = require("@tradejs/core/constants");
|
|
5224
5321
|
var import_backtest2 = require("@tradejs/core/backtest");
|
|
5225
5322
|
var import_redis = require("@tradejs/infra/redis");
|
|
@@ -5419,6 +5516,7 @@ var extractSignalFromAiDatasetRow = (row) => {
|
|
|
5419
5516
|
const { payload } = row;
|
|
5420
5517
|
return {
|
|
5421
5518
|
...payload.signal,
|
|
5519
|
+
aiFeatureReplay: { snapshot: payload.featureSnapshot ?? null },
|
|
5422
5520
|
strategy: payload.signal.strategy,
|
|
5423
5521
|
figures: payload.figures ?? {},
|
|
5424
5522
|
indicators: payload.indicators ?? {},
|
|
@@ -5432,7 +5530,7 @@ init_io2();
|
|
|
5432
5530
|
|
|
5433
5531
|
// src/lib/aiTrainResearch.ts
|
|
5434
5532
|
var import_node_child_process2 = require("child_process");
|
|
5435
|
-
var
|
|
5533
|
+
var import_node_crypto8 = require("crypto");
|
|
5436
5534
|
var import_promises7 = __toESM(require("fs/promises"));
|
|
5437
5535
|
var import_node_path9 = __toESM(require("path"));
|
|
5438
5536
|
|
|
@@ -5444,7 +5542,7 @@ var import_strategies = require("@tradejs/node/strategies");
|
|
|
5444
5542
|
var import_types2 = require("@tradejs/types");
|
|
5445
5543
|
|
|
5446
5544
|
// src/lib/strategyGateFingerprint.ts
|
|
5447
|
-
var
|
|
5545
|
+
var import_node_crypto7 = require("crypto");
|
|
5448
5546
|
var import_node_module = require("module");
|
|
5449
5547
|
var import_promises6 = __toESM(require("fs/promises"));
|
|
5450
5548
|
var import_node_path8 = __toESM(require("path"));
|
|
@@ -5457,6 +5555,8 @@ var RESEARCH_CONTEXT_ENV_KEYS = [
|
|
|
5457
5555
|
"INTERVAL",
|
|
5458
5556
|
"DERIVATIVES_CONTEXT_ENABLED",
|
|
5459
5557
|
"DERIVATIVES_CONTEXT_TARGET_ENABLED",
|
|
5558
|
+
"TICKER_PROFILES_PROVIDER",
|
|
5559
|
+
"TICKER_PROFILES_UNIVERSE",
|
|
5460
5560
|
"DERIVATIVES_CONTEXT_LOOKBACK_HOURS",
|
|
5461
5561
|
"DERIVATIVES_CONTEXT_EXTRA_REFERENCE_SYMBOLS",
|
|
5462
5562
|
"DERIVATIVES_CONTEXT_EXCHANGE_PRIORITY",
|
|
@@ -5486,7 +5586,7 @@ var normalizeForStableJson = (value) => {
|
|
|
5486
5586
|
}
|
|
5487
5587
|
return value;
|
|
5488
5588
|
};
|
|
5489
|
-
var fingerprintResearchValue = (value) => (0,
|
|
5589
|
+
var fingerprintResearchValue = (value) => (0, import_node_crypto8.createHash)("sha256").update(JSON.stringify(normalizeForStableJson(value))).digest("hex").slice(0, 16);
|
|
5490
5590
|
var fingerprintResearchContextEnvironment = (env = process.env) => fingerprintResearchValue(
|
|
5491
5591
|
Object.fromEntries(
|
|
5492
5592
|
RESEARCH_CONTEXT_ENV_KEYS.map((key) => [key, env[key] ?? null])
|
|
@@ -0,0 +1,76 @@
|
|
|
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/tickerProfiles.ts
|
|
21
|
+
var tickerProfiles_exports = {};
|
|
22
|
+
__export(tickerProfiles_exports, {
|
|
23
|
+
prepareTickerProfiles: () => prepareTickerProfiles
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(tickerProfiles_exports);
|
|
26
|
+
var import_tickerProfiles = require("@tradejs/core/tickerProfiles");
|
|
27
|
+
var import_candles = require("@tradejs/infra/timescale/candles");
|
|
28
|
+
var import_tickerProfiles2 = require("@tradejs/infra/tickerProfiles");
|
|
29
|
+
var prepareTickerProfiles = async ({
|
|
30
|
+
projectRoot,
|
|
31
|
+
provider,
|
|
32
|
+
universeId,
|
|
33
|
+
symbols,
|
|
34
|
+
start,
|
|
35
|
+
end
|
|
36
|
+
}) => {
|
|
37
|
+
if (!Number.isSafeInteger(end) || end <= start)
|
|
38
|
+
throw new Error("Invalid profile time window");
|
|
39
|
+
if (!symbols.length || new Set(symbols).size !== symbols.length || symbols.some((s) => !/^[A-Z0-9]+USDT$/.test(s)))
|
|
40
|
+
throw new Error("Supply a unique explicit USDT universe");
|
|
41
|
+
if (!symbols.includes("BTCUSDT") || !symbols.includes("ETHUSDT"))
|
|
42
|
+
throw new Error("The universe must include BTCUSDT and ETHUSDT references");
|
|
43
|
+
const receipts = [];
|
|
44
|
+
for (let asOf = (0, import_tickerProfiles.tickerProfileMonth)(start); asOf < end; asOf = (0, import_tickerProfiles.tickerProfileNextMonth)(asOf)) {
|
|
45
|
+
const candlesBySymbol = {};
|
|
46
|
+
for (const symbol of [...symbols].sort())
|
|
47
|
+
candlesBySymbol[symbol] = await (0, import_candles.getKlineCandlesRange)(
|
|
48
|
+
provider,
|
|
49
|
+
symbol,
|
|
50
|
+
60,
|
|
51
|
+
asOf - 721 * 36e5,
|
|
52
|
+
asOf - 36e5
|
|
53
|
+
);
|
|
54
|
+
const snapshot = (0, import_tickerProfiles.buildTickerProfileSnapshot)({
|
|
55
|
+
asOf,
|
|
56
|
+
provider,
|
|
57
|
+
universeId,
|
|
58
|
+
membership: "frozen-list",
|
|
59
|
+
candlesBySymbol
|
|
60
|
+
});
|
|
61
|
+
const snapshotId = await (0, import_tickerProfiles2.writeTickerProfiles)(projectRoot, snapshot);
|
|
62
|
+
receipts.push({
|
|
63
|
+
asOf,
|
|
64
|
+
snapshotId,
|
|
65
|
+
symbols: snapshot.profiles.length,
|
|
66
|
+
unknown: snapshot.profiles.filter(
|
|
67
|
+
(p) => p.moneyGroup === "unknown" || p.volatilityGroup === "unknown"
|
|
68
|
+
).length
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return receipts;
|
|
72
|
+
};
|
|
73
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
74
|
+
0 && (module.exports = {
|
|
75
|
+
prepareTickerProfiles
|
|
76
|
+
});
|
|
@@ -592,6 +592,7 @@ var import_progress = __toESM(require("progress"));
|
|
|
592
592
|
var import_ai = require("@tradejs/infra/ai");
|
|
593
593
|
|
|
594
594
|
// src/lib/aiPocketSearch/features.ts
|
|
595
|
+
var import_aiFeatures = require("@tradejs/core/aiFeatures");
|
|
595
596
|
var DAY_MS2 = 24 * 60 * 60 * 1e3;
|
|
596
597
|
var DAYS_PER_WEEK = 7;
|
|
597
598
|
var DAYS_PER_MONTH = 30.4375;
|
|
@@ -960,15 +961,25 @@ var addFlattenedFeatures = ({
|
|
|
960
961
|
value,
|
|
961
962
|
segments,
|
|
962
963
|
maxDepth,
|
|
963
|
-
shouldSkipPath = () => false
|
|
964
|
+
shouldSkipPath = () => false,
|
|
965
|
+
onFeatureExcluded
|
|
964
966
|
}) => {
|
|
965
967
|
if (!segments.length && !isPlainRecord(value)) {
|
|
966
968
|
return;
|
|
967
969
|
}
|
|
968
|
-
if (segments.length > maxDepth || isOutcomePath(segments)
|
|
970
|
+
if (segments.length > maxDepth || isOutcomePath(segments)) {
|
|
971
|
+
onFeatureExcluded?.({
|
|
972
|
+
path: segments.join("."),
|
|
973
|
+
classification: segments.length > maxDepth ? "depth-limit" : "derived-policy"
|
|
974
|
+
});
|
|
969
975
|
return;
|
|
970
976
|
}
|
|
977
|
+
if (shouldSkipPath(segments)) return;
|
|
971
978
|
if (Array.isArray(value)) {
|
|
979
|
+
onFeatureExcluded?.({
|
|
980
|
+
path: segments.join("."),
|
|
981
|
+
classification: "unprojected-array"
|
|
982
|
+
});
|
|
972
983
|
return;
|
|
973
984
|
}
|
|
974
985
|
if (isFeaturePrimitive(value)) {
|
|
@@ -990,7 +1001,8 @@ var addFlattenedFeatures = ({
|
|
|
990
1001
|
value: child,
|
|
991
1002
|
segments: [...segments, key],
|
|
992
1003
|
maxDepth,
|
|
993
|
-
shouldSkipPath
|
|
1004
|
+
shouldSkipPath,
|
|
1005
|
+
onFeatureExcluded
|
|
994
1006
|
});
|
|
995
1007
|
}
|
|
996
1008
|
};
|
|
@@ -1202,7 +1214,10 @@ var collectAiPocketFeatureSnapshot = ({
|
|
|
1202
1214
|
value: source,
|
|
1203
1215
|
segments: [],
|
|
1204
1216
|
maxDepth: 8,
|
|
1217
|
+
onFeatureExcluded,
|
|
1205
1218
|
shouldSkipPath: (segments) => {
|
|
1219
|
+
if (segments.join(".") === "additionalIndicators.baseContext.tickerProfile" || segments.join(".") === "additionalIndicators.tickerProfile" || segments.join(".") === "additionalIndicators.portfolioContext")
|
|
1220
|
+
return true;
|
|
1206
1221
|
if (isOperatorExcluded(segments.join("."))) {
|
|
1207
1222
|
return true;
|
|
1208
1223
|
}
|
|
@@ -1220,6 +1235,10 @@ var collectAiPocketFeatureSnapshot = ({
|
|
|
1220
1235
|
return true;
|
|
1221
1236
|
}
|
|
1222
1237
|
if (featureProfile === "compact" && isCompactFeaturePathSkipped(segments)) {
|
|
1238
|
+
onFeatureExcluded?.({
|
|
1239
|
+
path: segments.join("."),
|
|
1240
|
+
classification: "compact-profile"
|
|
1241
|
+
});
|
|
1223
1242
|
return true;
|
|
1224
1243
|
}
|
|
1225
1244
|
if (featurePolicy !== "causal-stationary") {
|
|
@@ -1254,6 +1273,21 @@ var collectAiPocketFeatureSnapshot = ({
|
|
|
1254
1273
|
delete features[key];
|
|
1255
1274
|
}
|
|
1256
1275
|
}
|
|
1276
|
+
const registered = payload.featureSnapshot;
|
|
1277
|
+
if (registered) {
|
|
1278
|
+
(0, import_aiFeatures.validateAiFeatureSnapshot)(registered);
|
|
1279
|
+
for (const definition of registered.definitions) {
|
|
1280
|
+
const path3 = `registered.${definition.id}`;
|
|
1281
|
+
if (isOperatorExcluded(path3)) continue;
|
|
1282
|
+
const value = registered.values[definition.id];
|
|
1283
|
+
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";
|
|
1284
|
+
if (classification !== "eligible") {
|
|
1285
|
+
onFeatureExcluded?.({ path: path3, classification });
|
|
1286
|
+
continue;
|
|
1287
|
+
}
|
|
1288
|
+
features[path3] = value;
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1257
1291
|
return { features, featureCoverage };
|
|
1258
1292
|
};
|
|
1259
1293
|
|
|
@@ -3667,6 +3701,7 @@ var extractSignalFromAiDatasetRow = (row) => {
|
|
|
3667
3701
|
const { payload } = row;
|
|
3668
3702
|
return {
|
|
3669
3703
|
...payload.signal,
|
|
3704
|
+
aiFeatureReplay: { snapshot: payload.featureSnapshot ?? null },
|
|
3670
3705
|
strategy: payload.signal.strategy,
|
|
3671
3706
|
figures: payload.figures ?? {},
|
|
3672
3707
|
indicators: payload.indicators ?? {},
|