@tradejs/cli 3.1.29-beta.292 → 3.1.29-beta.297
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 +968 -680
- package/dist/lib/binanceMarketContextBackfill.js +2 -2
- package/dist/lib/coinMarketCapContextBackfill.js +22 -6
- package/dist/lib/derivativesContextBackfill.js +14 -0
- package/dist/lib/marketContextPrepare.js +24 -8
- package/dist/lib/strategyResearch.js +33 -79
- package/dist/scripts/backtest.js +213 -74
- package/dist/scripts/binanceMarketIngest.js +3 -3
- package/dist/scripts/coverageBackfill.js +1731 -0
- package/dist/scripts/replay.js +24 -8
- package/dist/scripts/replayRunner.js +24 -8
- package/dist/scripts/replayRuntimeEvidence.js +4 -1
- package/dist/scripts/runtimeParity.js +24 -8
- package/dist/scripts/signals.js +24 -8
- package/dist/scripts/signalsDaemon.js +24 -8
- package/dist/scripts/strategyRelease.js +6 -37
- package/dist/scripts/strategyResearch.js +36 -82
- package/package.json +7 -7
- package/dist/lib/researchMetricSnapshot.js +0 -74
|
@@ -380,13 +380,12 @@ var getReferenceSymbols = () => {
|
|
|
380
380
|
};
|
|
381
381
|
var intervalToMarketFeatureInterval = (interval) => {
|
|
382
382
|
const normalized = String(interval).trim().toLowerCase();
|
|
383
|
-
if (normalized === "1" || normalized === "1m") return
|
|
383
|
+
if (normalized === "1" || normalized === "1m") return null;
|
|
384
384
|
if (normalized === "5" || normalized === "5m") return "5m";
|
|
385
385
|
if (normalized === "60" || normalized === "1h") return "1h";
|
|
386
386
|
return "15m";
|
|
387
387
|
};
|
|
388
388
|
var marketIntervalToConnectorInterval = (interval) => {
|
|
389
|
-
if (interval === "1m") return "1";
|
|
390
389
|
if (interval === "5m") return "5";
|
|
391
390
|
if (interval === "1h") return "60";
|
|
392
391
|
return "15";
|
|
@@ -551,6 +550,7 @@ var backfillBinanceMarketContext = async (params, enabled) => {
|
|
|
551
550
|
return skippedBackfillResult();
|
|
552
551
|
}
|
|
553
552
|
const interval = intervalToMarketFeatureInterval(params.interval);
|
|
553
|
+
if (interval === null) return skippedBackfillResult();
|
|
554
554
|
const intervalMs = MARKET_FEATURE_INTERVAL_MS[interval];
|
|
555
555
|
const { breadthStartMs, tradeFlowStartMs, endMs } = resolveBinanceMarketContextBackfillWindow(params);
|
|
556
556
|
if (endMs <= Math.min(breadthStartMs, tradeFlowStartMs)) {
|
|
@@ -362,7 +362,7 @@ var coinMarketCapFetch = async (params) => {
|
|
|
362
362
|
};
|
|
363
363
|
var fetchCoinMarketCapIndexRows = async (params) => {
|
|
364
364
|
const rows = [];
|
|
365
|
-
const maxChunkDays =
|
|
365
|
+
const maxChunkDays = 4;
|
|
366
366
|
const totalChunks = Math.max(
|
|
367
367
|
1,
|
|
368
368
|
Math.ceil(
|
|
@@ -799,11 +799,27 @@ var backfillCoinMarketCapContext = async (params) => {
|
|
|
799
799
|
toMs
|
|
800
800
|
})
|
|
801
801
|
);
|
|
802
|
-
const
|
|
803
|
-
const
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
802
|
+
const ready = (dataset, existing) => params.repairDataset ? params.repairDataset !== dataset : existing;
|
|
803
|
+
const globalDailyReady = ready(
|
|
804
|
+
"cmc-global-1d",
|
|
805
|
+
globalDailyCached || globalDailyBackfillCovered
|
|
806
|
+
);
|
|
807
|
+
const referencesDailyReady = ready(
|
|
808
|
+
"cmc-reference_asset-1d",
|
|
809
|
+
referencesDailyCached || referencesDailyBackfillCovered
|
|
810
|
+
);
|
|
811
|
+
const exchangeLiquidityReady = ready(
|
|
812
|
+
"cmc-exchange_liquidity-1d",
|
|
813
|
+
exchangeLiquidityCached || !exchangeLiquidityEnabled || exchangeLiquidityBackfillCovered
|
|
814
|
+
);
|
|
815
|
+
const fearGreedReady = ready(
|
|
816
|
+
"cmc-fear_greed-1d",
|
|
817
|
+
fearGreedCached || !fearGreedEnabled || fearGreedBackfillCovered
|
|
818
|
+
);
|
|
819
|
+
const indexesReady = ready(
|
|
820
|
+
"cmc-index-1d",
|
|
821
|
+
indexesCached || indexesBackfillCovered
|
|
822
|
+
);
|
|
807
823
|
let globalStatus = resolveBackfillStatus({
|
|
808
824
|
cached: globalDailyCached,
|
|
809
825
|
covered: globalDailyBackfillCovered
|
|
@@ -39,6 +39,7 @@ __export(derivativesContextBackfill_exports, {
|
|
|
39
39
|
isBacktestDerivativesContextEnabled: () => isBacktestDerivativesContextEnabled,
|
|
40
40
|
isDerivativesTargetContextEnabled: () => isDerivativesTargetContextEnabled,
|
|
41
41
|
isSignalsDerivativesContextEnabled: () => isSignalsDerivativesContextEnabled,
|
|
42
|
+
resolveCoinalyzeBackfillMarket: () => resolveCoinalyzeBackfillMarket,
|
|
42
43
|
resolveDerivativesContextBackfillSymbols: () => resolveDerivativesContextBackfillSymbols,
|
|
43
44
|
resolveDerivativesContextBackfillWindow: () => resolveDerivativesContextBackfillWindow,
|
|
44
45
|
resolveDerivativesContextFetchFromMs: () => resolveDerivativesContextFetchFromMs,
|
|
@@ -481,6 +482,18 @@ var buildMatches = (tickers, markets, exchangePriority) => {
|
|
|
481
482
|
}
|
|
482
483
|
return { matches, unmatched };
|
|
483
484
|
};
|
|
485
|
+
async function resolveCoinalyzeBackfillMarket(userName, symbol) {
|
|
486
|
+
const apiKey = await getCoinalyzeApiKey(userName);
|
|
487
|
+
if (!apiKey) throw new Error("Missing Coinalyze API key.");
|
|
488
|
+
const markets = (await fetchCoinalyzeMarkets(apiKey)).filter(
|
|
489
|
+
(market) => market.quote_asset?.toUpperCase() === "USDT" && market.is_perpetual
|
|
490
|
+
);
|
|
491
|
+
const priority = parseList(
|
|
492
|
+
process.env.COINALYZE_EXCHANGE_PRIORITY || process.env.DERIVATIVES_CONTEXT_EXCHANGE_PRIORITY || "A,6,0"
|
|
493
|
+
);
|
|
494
|
+
const { matches } = buildMatches([symbol], markets, priority);
|
|
495
|
+
return { apiKey, marketSymbol: matches[0]?.marketSymbol };
|
|
496
|
+
}
|
|
484
497
|
var normalizeMetricPoint = (metric, point) => {
|
|
485
498
|
if (metric === "oi") {
|
|
486
499
|
return {
|
|
@@ -1042,6 +1055,7 @@ var backfillDerivativesContextForSignals = async (params) => backfillDerivatives
|
|
|
1042
1055
|
isBacktestDerivativesContextEnabled,
|
|
1043
1056
|
isDerivativesTargetContextEnabled,
|
|
1044
1057
|
isSignalsDerivativesContextEnabled,
|
|
1058
|
+
resolveCoinalyzeBackfillMarket,
|
|
1045
1059
|
resolveDerivativesContextBackfillSymbols,
|
|
1046
1060
|
resolveDerivativesContextBackfillWindow,
|
|
1047
1061
|
resolveDerivativesContextFetchFromMs,
|
|
@@ -381,13 +381,12 @@ var getReferenceSymbols = () => {
|
|
|
381
381
|
};
|
|
382
382
|
var intervalToMarketFeatureInterval = (interval) => {
|
|
383
383
|
const normalized = String(interval).trim().toLowerCase();
|
|
384
|
-
if (normalized === "1" || normalized === "1m") return
|
|
384
|
+
if (normalized === "1" || normalized === "1m") return null;
|
|
385
385
|
if (normalized === "5" || normalized === "5m") return "5m";
|
|
386
386
|
if (normalized === "60" || normalized === "1h") return "1h";
|
|
387
387
|
return "15m";
|
|
388
388
|
};
|
|
389
389
|
var marketIntervalToConnectorInterval = (interval) => {
|
|
390
|
-
if (interval === "1m") return "1";
|
|
391
390
|
if (interval === "5m") return "5";
|
|
392
391
|
if (interval === "1h") return "60";
|
|
393
392
|
return "15";
|
|
@@ -552,6 +551,7 @@ var backfillBinanceMarketContext = async (params, enabled) => {
|
|
|
552
551
|
return skippedBackfillResult();
|
|
553
552
|
}
|
|
554
553
|
const interval = intervalToMarketFeatureInterval(params.interval);
|
|
554
|
+
if (interval === null) return skippedBackfillResult();
|
|
555
555
|
const intervalMs = MARKET_FEATURE_INTERVAL_MS[interval];
|
|
556
556
|
const { breadthStartMs, tradeFlowStartMs, endMs } = resolveBinanceMarketContextBackfillWindow(params);
|
|
557
557
|
if (endMs <= Math.min(breadthStartMs, tradeFlowStartMs)) {
|
|
@@ -2132,7 +2132,7 @@ var coinMarketCapFetch = async (params) => {
|
|
|
2132
2132
|
};
|
|
2133
2133
|
var fetchCoinMarketCapIndexRows = async (params) => {
|
|
2134
2134
|
const rows = [];
|
|
2135
|
-
const maxChunkDays =
|
|
2135
|
+
const maxChunkDays = 4;
|
|
2136
2136
|
const totalChunks = Math.max(
|
|
2137
2137
|
1,
|
|
2138
2138
|
Math.ceil(
|
|
@@ -2569,11 +2569,27 @@ var backfillCoinMarketCapContext = async (params) => {
|
|
|
2569
2569
|
toMs
|
|
2570
2570
|
})
|
|
2571
2571
|
);
|
|
2572
|
-
const
|
|
2573
|
-
const
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2572
|
+
const ready = (dataset, existing) => params.repairDataset ? params.repairDataset !== dataset : existing;
|
|
2573
|
+
const globalDailyReady = ready(
|
|
2574
|
+
"cmc-global-1d",
|
|
2575
|
+
globalDailyCached || globalDailyBackfillCovered
|
|
2576
|
+
);
|
|
2577
|
+
const referencesDailyReady = ready(
|
|
2578
|
+
"cmc-reference_asset-1d",
|
|
2579
|
+
referencesDailyCached || referencesDailyBackfillCovered
|
|
2580
|
+
);
|
|
2581
|
+
const exchangeLiquidityReady = ready(
|
|
2582
|
+
"cmc-exchange_liquidity-1d",
|
|
2583
|
+
exchangeLiquidityCached || !exchangeLiquidityEnabled || exchangeLiquidityBackfillCovered
|
|
2584
|
+
);
|
|
2585
|
+
const fearGreedReady = ready(
|
|
2586
|
+
"cmc-fear_greed-1d",
|
|
2587
|
+
fearGreedCached || !fearGreedEnabled || fearGreedBackfillCovered
|
|
2588
|
+
);
|
|
2589
|
+
const indexesReady = ready(
|
|
2590
|
+
"cmc-index-1d",
|
|
2591
|
+
indexesCached || indexesBackfillCovered
|
|
2592
|
+
);
|
|
2577
2593
|
let globalStatus = resolveBackfillStatus({
|
|
2578
2594
|
cached: globalDailyCached,
|
|
2579
2595
|
covered: globalDailyBackfillCovered
|
|
@@ -168,10 +168,10 @@ var init_io = __esm({
|
|
|
168
168
|
sha256Text = (value) => (0, import_node_crypto.createHash)("sha256").update(value).digest("hex");
|
|
169
169
|
sha256Json = (value) => sha256Text(canonicalJson(value));
|
|
170
170
|
sha256File = async (filePath) => {
|
|
171
|
-
const
|
|
171
|
+
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
172
172
|
const input = (0, import_node_fs2.createReadStream)(filePath);
|
|
173
|
-
for await (const chunk of input)
|
|
174
|
-
return
|
|
173
|
+
for await (const chunk of input) hash.update(chunk);
|
|
174
|
+
return hash.digest("hex");
|
|
175
175
|
};
|
|
176
176
|
assertFinite = (value, name) => {
|
|
177
177
|
assert(typeof value === "number" && Number.isFinite(value), name);
|
|
@@ -445,14 +445,14 @@ __export(io_exports, {
|
|
|
445
445
|
verifyResearchState: () => verifyResearchState,
|
|
446
446
|
withResearchLock: () => withResearchLock
|
|
447
447
|
});
|
|
448
|
-
var import_promises2, import_node_path3, import_node_os,
|
|
448
|
+
var import_promises2, import_node_path3, import_node_os, import_node_crypto2, researchDirectory, readJson, boundResearchPath, withResearchLock, verifyResearchState, verifyCompletedResearch, initializeResearchState, isRetainedDeletion;
|
|
449
449
|
var init_io2 = __esm({
|
|
450
450
|
"src/lib/strategyResearch/io.ts"() {
|
|
451
451
|
"use strict";
|
|
452
452
|
import_promises2 = __toESM(require("fs/promises"));
|
|
453
453
|
import_node_path3 = __toESM(require("path"));
|
|
454
454
|
import_node_os = __toESM(require("os"));
|
|
455
|
-
|
|
455
|
+
import_node_crypto2 = require("crypto");
|
|
456
456
|
init_io();
|
|
457
457
|
researchDirectory = (projectRoot, spec) => import_node_path3.default.join(projectRoot, "data/research/strategy", spec.core.researchId);
|
|
458
458
|
readJson = async (file) => JSON.parse(await import_promises2.default.readFile(file, "utf8"));
|
|
@@ -481,7 +481,7 @@ var init_io2 = __esm({
|
|
|
481
481
|
"data/research/strategy/.lock"
|
|
482
482
|
);
|
|
483
483
|
await import_promises2.default.mkdir(import_node_path3.default.dirname(file), { recursive: true });
|
|
484
|
-
const token = (0,
|
|
484
|
+
const token = (0, import_node_crypto2.randomUUID)();
|
|
485
485
|
const acquire = () => import_promises2.default.writeFile(
|
|
486
486
|
file,
|
|
487
487
|
JSON.stringify({ pid: process.pid, host: import_node_os.default.hostname(), token }),
|
|
@@ -577,15 +577,15 @@ var init_io2 = __esm({
|
|
|
577
577
|
await writeJsonAtomic(file, state);
|
|
578
578
|
return state;
|
|
579
579
|
};
|
|
580
|
-
isRetainedDeletion = async (directory, file,
|
|
580
|
+
isRetainedDeletion = async (directory, file, hash) => {
|
|
581
581
|
try {
|
|
582
582
|
const inventory = await readJson(import_node_path3.default.join(directory, "retention.json"));
|
|
583
583
|
const index = inventory.entries.findIndex(
|
|
584
|
-
(entry) => entry.path === file && entry.sha256 ===
|
|
584
|
+
(entry) => entry.path === file && entry.sha256 === hash
|
|
585
585
|
);
|
|
586
586
|
if (index < 0) return false;
|
|
587
587
|
const receipt = await readJson(import_node_path3.default.join(directory, "retention", `${index}.json`));
|
|
588
|
-
return ["applying", "completed"].includes(receipt.status) && receipt.files[0]?.path === file && receipt.files[0]?.sha256 ===
|
|
588
|
+
return ["applying", "completed"].includes(receipt.status) && receipt.files[0]?.path === file && receipt.files[0]?.sha256 === hash;
|
|
589
589
|
} catch (error) {
|
|
590
590
|
if (error.code === "ENOENT") return false;
|
|
591
591
|
throw error;
|
|
@@ -1922,15 +1922,15 @@ var createPocketResult = (rows, predicates, mask, validationRows, testRows, obje
|
|
|
1922
1922
|
};
|
|
1923
1923
|
};
|
|
1924
1924
|
var hashMask = (mask) => {
|
|
1925
|
-
let
|
|
1925
|
+
let hash = 2166136261;
|
|
1926
1926
|
for (let index = 0; index < mask.length; index += 1) {
|
|
1927
1927
|
if (mask[index] !== 1) {
|
|
1928
1928
|
continue;
|
|
1929
1929
|
}
|
|
1930
|
-
|
|
1931
|
-
|
|
1930
|
+
hash ^= index + 1;
|
|
1931
|
+
hash = Math.imul(hash, 16777619);
|
|
1932
1932
|
}
|
|
1933
|
-
return (
|
|
1933
|
+
return (hash >>> 0).toString(36);
|
|
1934
1934
|
};
|
|
1935
1935
|
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;
|
|
1936
1936
|
var estimateCombinationCount = (poolSize, maxDepth, maxCombinations) => {
|
|
@@ -2627,51 +2627,7 @@ var policyVariant = (spec, coreId, policy, id, jev) => {
|
|
|
2627
2627
|
|
|
2628
2628
|
// src/lib/strategyResearch/orchestrator.ts
|
|
2629
2629
|
var import_promises5 = __toESM(require("fs/promises"));
|
|
2630
|
-
|
|
2631
|
-
// src/lib/researchMetricSnapshot.ts
|
|
2632
|
-
var import_node_crypto2 = require("crypto");
|
|
2633
|
-
var import_node_zlib = require("zlib");
|
|
2634
|
-
var MAX_BYTES = 256 * 1024 * 1024;
|
|
2635
|
-
var hash = (bytes) => (0, import_node_crypto2.createHash)("sha256").update(bytes).digest("hex");
|
|
2636
|
-
var validatePermanentResearchMetrics = (value) => {
|
|
2637
|
-
if (!value || typeof value !== "object") return;
|
|
2638
|
-
for (const [key, child] of Object.entries(value)) {
|
|
2639
|
-
if (["matchedPairs", "tradeRows", "allProjectedLeaves"].includes(key) && Array.isArray(child) && child.length)
|
|
2640
|
-
throw new Error(`Temporary payload ${key} is not a permanent metric`);
|
|
2641
|
-
if (key === "trades" && Array.isArray(child) && child.some(
|
|
2642
|
-
(row) => row && typeof row === "object" && ("signalId" in row || "entryTimestamp" in row)
|
|
2643
|
-
))
|
|
2644
|
-
throw new Error("Temporary trade records are not permanent metrics");
|
|
2645
|
-
validatePermanentResearchMetrics(child);
|
|
2646
|
-
}
|
|
2647
|
-
};
|
|
2648
|
-
var encodeResearchMetricSnapshot = (metrics) => {
|
|
2649
|
-
validatePermanentResearchMetrics(metrics);
|
|
2650
|
-
const bytes = Buffer.from(JSON.stringify(metrics));
|
|
2651
|
-
if (bytes.length > MAX_BYTES)
|
|
2652
|
-
throw new Error("Metric snapshot exceeds decoded size limit");
|
|
2653
|
-
return {
|
|
2654
|
-
schema: "tradejs-metric-snapshot/v1",
|
|
2655
|
-
encoding: "gzip+base64",
|
|
2656
|
-
decodedBytes: bytes.length,
|
|
2657
|
-
sha256: hash(bytes),
|
|
2658
|
-
payload: (0, import_node_zlib.gzipSync)(bytes, { level: 9 }).toString("base64")
|
|
2659
|
-
};
|
|
2660
|
-
};
|
|
2661
|
-
var decodeResearchMetricSnapshot = (snapshot) => {
|
|
2662
|
-
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")
|
|
2663
|
-
throw new Error("Invalid metric snapshot envelope");
|
|
2664
|
-
const bytes = (0, import_node_zlib.gunzipSync)(Buffer.from(snapshot.payload, "base64"), {
|
|
2665
|
-
maxOutputLength: snapshot.decodedBytes
|
|
2666
|
-
});
|
|
2667
|
-
if (bytes.length !== snapshot.decodedBytes || hash(bytes) !== snapshot.sha256)
|
|
2668
|
-
throw new Error("Metric snapshot checksum or size mismatch");
|
|
2669
|
-
const metrics = JSON.parse(bytes.toString("utf8"));
|
|
2670
|
-
validatePermanentResearchMetrics(metrics);
|
|
2671
|
-
return metrics;
|
|
2672
|
-
};
|
|
2673
|
-
|
|
2674
|
-
// src/lib/strategyResearch/orchestrator.ts
|
|
2630
|
+
var import_researchMetricSnapshot2 = require("@tradejs/infra/researchMetricSnapshot");
|
|
2675
2631
|
var import_node_path7 = __toESM(require("path"));
|
|
2676
2632
|
|
|
2677
2633
|
// src/lib/coreResearch/metrics.ts
|
|
@@ -3877,8 +3833,9 @@ var import_node_path6 = __toESM(require("path"));
|
|
|
3877
3833
|
|
|
3878
3834
|
// src/lib/strategyRelease/researchRetention.ts
|
|
3879
3835
|
var import_promises3 = __toESM(require("fs/promises"));
|
|
3836
|
+
var import_researchMetricSnapshot = require("@tradejs/infra/researchMetricSnapshot");
|
|
3880
3837
|
var import_node_path5 = __toESM(require("path"));
|
|
3881
|
-
var
|
|
3838
|
+
var import_node_crypto3 = require("crypto");
|
|
3882
3839
|
var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvidence");
|
|
3883
3840
|
|
|
3884
3841
|
// src/lib/strategyRelease/researchFileConsumers.ts
|
|
@@ -4027,7 +3984,7 @@ var mapFiles = async (entries, visit) => {
|
|
|
4027
3984
|
if (worker.status === "rejected") throw worker.reason;
|
|
4028
3985
|
return results;
|
|
4029
3986
|
};
|
|
4030
|
-
var fileSha256 = async (file, bytes) => bytes <= 1024 * 1024 ? (0,
|
|
3987
|
+
var fileSha256 = async (file, bytes) => bytes <= 1024 * 1024 ? (0, import_node_crypto3.createHash)("sha256").update(await import_promises3.default.readFile(file)).digest("hex") : (0, import_strategyReleaseEvidence.strategyEvidenceFileSha256)(file);
|
|
4031
3988
|
var inside = (root, file) => {
|
|
4032
3989
|
const relative = import_node_path5.default.relative(root, file);
|
|
4033
3990
|
return relative !== "" && !relative.startsWith(`..${import_node_path5.default.sep}`) && relative !== ".." && !import_node_path5.default.isAbsolute(relative);
|
|
@@ -4090,7 +4047,7 @@ var applyResearchRetention = async (options) => {
|
|
|
4090
4047
|
throw new Error(
|
|
4091
4048
|
"Complete v2 note needs one verified metric snapshot"
|
|
4092
4049
|
);
|
|
4093
|
-
decodeResearchMetricSnapshot(JSON.parse(blocks[0][1]));
|
|
4050
|
+
(0, import_researchMetricSnapshot.decodeResearchMetricSnapshot)(JSON.parse(blocks[0][1]));
|
|
4094
4051
|
}
|
|
4095
4052
|
} finally {
|
|
4096
4053
|
await handle.close();
|
|
@@ -4205,11 +4162,11 @@ var createResearchRetentionInventory = async (projectRoot, directory, spec, stat
|
|
|
4205
4162
|
}
|
|
4206
4163
|
const files = /* @__PURE__ */ new Map();
|
|
4207
4164
|
for (const stage of Object.values(state.stages)) {
|
|
4208
|
-
for (const [relative,
|
|
4165
|
+
for (const [relative, hash] of Object.entries(stage.artifacts)) {
|
|
4209
4166
|
const file = await boundResearchPath(directory, relative);
|
|
4210
4167
|
if (relative.endsWith("/result.json")) {
|
|
4211
4168
|
const result = await readJson(file);
|
|
4212
|
-
if (result?.dataset) files.set(file,
|
|
4169
|
+
if (result?.dataset) files.set(file, hash);
|
|
4213
4170
|
}
|
|
4214
4171
|
if (relative.endsWith("/sources.json") || relative.endsWith("/payloads.json")) {
|
|
4215
4172
|
const sources = await readJson(file);
|
|
@@ -4226,13 +4183,13 @@ var createResearchRetentionInventory = async (projectRoot, directory, spec, stat
|
|
|
4226
4183
|
}
|
|
4227
4184
|
}
|
|
4228
4185
|
const entries = [];
|
|
4229
|
-
for (const [file,
|
|
4186
|
+
for (const [file, hash] of files) {
|
|
4230
4187
|
const stat = await import_promises4.default.stat(file);
|
|
4231
4188
|
entries.push({
|
|
4232
4189
|
path: file,
|
|
4233
4190
|
kind: "research_payload",
|
|
4234
4191
|
researchId: spec.core.researchId,
|
|
4235
|
-
sha256:
|
|
4192
|
+
sha256: hash,
|
|
4236
4193
|
bytes: stat.size,
|
|
4237
4194
|
createdAt: stat.birthtimeMs,
|
|
4238
4195
|
verified: true,
|
|
@@ -4492,7 +4449,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4492
4449
|
});
|
|
4493
4450
|
let partitionControl;
|
|
4494
4451
|
if (spec.testSince === 0) {
|
|
4495
|
-
const
|
|
4452
|
+
const control = spec.core.variants.find(
|
|
4496
4453
|
(variant) => variant.role === "control"
|
|
4497
4454
|
);
|
|
4498
4455
|
partitionControl = await stage(
|
|
@@ -4509,7 +4466,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4509
4466
|
}
|
|
4510
4467
|
return backend.runVariant(
|
|
4511
4468
|
spec,
|
|
4512
|
-
|
|
4469
|
+
control,
|
|
4513
4470
|
folder,
|
|
4514
4471
|
async (runId) => writeJsonAtomic(import_node_path7.default.join(folder, "native-run.json"), {
|
|
4515
4472
|
runId
|
|
@@ -4531,9 +4488,6 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4531
4488
|
let frozenSelection;
|
|
4532
4489
|
const raw = {};
|
|
4533
4490
|
const discovered = [];
|
|
4534
|
-
const control = spec.core.variants.find(
|
|
4535
|
-
(variant) => variant.role === "control"
|
|
4536
|
-
);
|
|
4537
4491
|
const currentPolicy = {
|
|
4538
4492
|
schema: "tradejs-research-entry-policy/v1",
|
|
4539
4493
|
strategy: spec.core.strategy,
|
|
@@ -5009,7 +4963,7 @@ ${JSON.stringify(spec, null, 2)}
|
|
|
5009
4963
|
## Metrics snapshot (machine-readable)
|
|
5010
4964
|
|
|
5011
4965
|
\`\`\`json
|
|
5012
|
-
${JSON.stringify(encodeResearchMetricSnapshot(compact))}
|
|
4966
|
+
${JSON.stringify((0, import_researchMetricSnapshot2.encodeResearchMetricSnapshot)(compact))}
|
|
5013
4967
|
\`\`\`
|
|
5014
4968
|
|
|
5015
4969
|
## Reported metrics
|
|
@@ -5139,7 +5093,7 @@ var import_registry = require("@tradejs/node/registry");
|
|
|
5139
5093
|
var import_connectors = require("@tradejs/node/connectors");
|
|
5140
5094
|
|
|
5141
5095
|
// src/lib/coreResearch/dataset.ts
|
|
5142
|
-
var
|
|
5096
|
+
var import_node_crypto4 = require("crypto");
|
|
5143
5097
|
var import_node_fs3 = require("fs");
|
|
5144
5098
|
var import_node_path8 = __toESM(require("path"));
|
|
5145
5099
|
var import_node_readline2 = __toESM(require("readline"));
|
|
@@ -5354,8 +5308,8 @@ var readCoreResearchVariant = async (variant) => {
|
|
|
5354
5308
|
for (const inputPath of variant.files) {
|
|
5355
5309
|
const filePath = import_node_path8.default.resolve(inputPath);
|
|
5356
5310
|
const input = (0, import_node_fs3.createReadStream)(filePath);
|
|
5357
|
-
const
|
|
5358
|
-
input.on("data", (chunk) =>
|
|
5311
|
+
const hash = (0, import_node_crypto4.createHash)("sha256");
|
|
5312
|
+
input.on("data", (chunk) => hash.update(chunk));
|
|
5359
5313
|
const lines = import_node_readline2.default.createInterface({ input, crlfDelay: Infinity });
|
|
5360
5314
|
const fileTrades = [];
|
|
5361
5315
|
let lineNumber = 0;
|
|
@@ -5405,7 +5359,7 @@ var readCoreResearchVariant = async (variant) => {
|
|
|
5405
5359
|
trades.push(trade);
|
|
5406
5360
|
fileTrades.push(trade);
|
|
5407
5361
|
}
|
|
5408
|
-
const fileSha2562 =
|
|
5362
|
+
const fileSha2562 = hash.digest("hex");
|
|
5409
5363
|
for (const trade of fileTrades) trade.sourceSha256 = fileSha2562;
|
|
5410
5364
|
sources.push({
|
|
5411
5365
|
path: filePath,
|
|
@@ -5425,7 +5379,7 @@ var readCoreResearchVariant = async (variant) => {
|
|
|
5425
5379
|
};
|
|
5426
5380
|
|
|
5427
5381
|
// src/lib/backtest/checkpoint.ts
|
|
5428
|
-
var
|
|
5382
|
+
var import_node_crypto5 = require("crypto");
|
|
5429
5383
|
var import_constants = require("@tradejs/core/constants");
|
|
5430
5384
|
var import_backtest2 = require("@tradejs/core/backtest");
|
|
5431
5385
|
var import_redis = require("@tradejs/infra/redis");
|
|
@@ -5639,7 +5593,7 @@ init_io2();
|
|
|
5639
5593
|
|
|
5640
5594
|
// src/lib/aiTrainResearch.ts
|
|
5641
5595
|
var import_node_child_process2 = require("child_process");
|
|
5642
|
-
var
|
|
5596
|
+
var import_node_crypto7 = require("crypto");
|
|
5643
5597
|
var import_promises7 = __toESM(require("fs/promises"));
|
|
5644
5598
|
var import_node_path10 = __toESM(require("path"));
|
|
5645
5599
|
|
|
@@ -5651,7 +5605,7 @@ var import_strategies = require("@tradejs/node/strategies");
|
|
|
5651
5605
|
var import_types2 = require("@tradejs/types");
|
|
5652
5606
|
|
|
5653
5607
|
// src/lib/strategyGateFingerprint.ts
|
|
5654
|
-
var
|
|
5608
|
+
var import_node_crypto6 = require("crypto");
|
|
5655
5609
|
var import_node_module = require("module");
|
|
5656
5610
|
var import_promises6 = __toESM(require("fs/promises"));
|
|
5657
5611
|
var import_node_path9 = __toESM(require("path"));
|
|
@@ -5695,7 +5649,7 @@ var normalizeForStableJson = (value) => {
|
|
|
5695
5649
|
}
|
|
5696
5650
|
return value;
|
|
5697
5651
|
};
|
|
5698
|
-
var fingerprintResearchValue = (value) => (0,
|
|
5652
|
+
var fingerprintResearchValue = (value) => (0, import_node_crypto7.createHash)("sha256").update(JSON.stringify(normalizeForStableJson(value))).digest("hex").slice(0, 16);
|
|
5699
5653
|
var fingerprintResearchContextEnvironment = (env = process.env) => fingerprintResearchValue(
|
|
5700
5654
|
Object.fromEntries(
|
|
5701
5655
|
RESEARCH_CONTEXT_ENV_KEYS.map((key) => [key, env[key] ?? null])
|