@tradejs/cli 2.0.16 → 2.0.18
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 +271 -68
- package/dist/lib/hyperliquidWhaleBackfill.js +37 -1
- package/dist/lib/marketContextPrepare.js +27 -1
- package/dist/lib/runtimeEvidenceArtifacts.js +13 -1
- package/dist/scripts/backtest.js +53 -3
- package/dist/scripts/hyperliquidWhaleBackfill.js +27 -1
- package/dist/scripts/hyperliquidWhalesUpdate.js +1 -0
- package/dist/scripts/replay.js +189 -30
- package/dist/scripts/replayRunner.js +189 -30
- package/dist/scripts/runtimeEvidence.js +13 -1
- package/dist/scripts/runtimeParity.js +27 -1
- package/dist/scripts/signals.js +29 -3
- package/dist/scripts/signalsDaemon.js +29 -3
- package/package.json +9 -9
package/dist/cli.js
CHANGED
|
@@ -3678,8 +3678,8 @@ var init_aiPocketSearch = __esm({
|
|
|
3678
3678
|
"volumeusd",
|
|
3679
3679
|
"vwap"
|
|
3680
3680
|
]);
|
|
3681
|
-
classifyAiPocketFeaturePath = (
|
|
3682
|
-
const segments = (Array.isArray(
|
|
3681
|
+
classifyAiPocketFeaturePath = (path25) => {
|
|
3682
|
+
const segments = (Array.isArray(path25) ? path25 : path25.split(".")).filter(
|
|
3683
3683
|
Boolean
|
|
3684
3684
|
);
|
|
3685
3685
|
const normalized = segments.map((segment) => segment.toLowerCase());
|
|
@@ -10868,27 +10868,27 @@ var init_coinMarketCapContextBackfill = __esm({
|
|
|
10868
10868
|
totalCredits: 0,
|
|
10869
10869
|
byPath: /* @__PURE__ */ new Map()
|
|
10870
10870
|
});
|
|
10871
|
-
getCoinMarketCapPathLabel = (
|
|
10872
|
-
if (
|
|
10873
|
-
if (
|
|
10874
|
-
if (
|
|
10875
|
-
if (
|
|
10876
|
-
if (
|
|
10877
|
-
if (
|
|
10878
|
-
return
|
|
10879
|
-
};
|
|
10880
|
-
recordCoinMarketCapFetchStats = (stats,
|
|
10871
|
+
getCoinMarketCapPathLabel = (path25) => {
|
|
10872
|
+
if (path25.includes("global-metrics")) return "global";
|
|
10873
|
+
if (path25.includes("cryptocurrency/quotes")) return "reference";
|
|
10874
|
+
if (path25.includes("exchange/quotes")) return "exchangeLiquidity";
|
|
10875
|
+
if (path25.includes("fear-and-greed")) return "fearGreed";
|
|
10876
|
+
if (path25.includes("cmc100")) return "cmc100";
|
|
10877
|
+
if (path25.includes("cmc20")) return "cmc20";
|
|
10878
|
+
return path25;
|
|
10879
|
+
};
|
|
10880
|
+
recordCoinMarketCapFetchStats = (stats, path25, creditCount) => {
|
|
10881
10881
|
if (!stats) return;
|
|
10882
|
-
const existing = stats.byPath.get(
|
|
10882
|
+
const existing = stats.byPath.get(path25) ?? { requests: 0, credits: 0 };
|
|
10883
10883
|
existing.requests += 1;
|
|
10884
10884
|
existing.credits += creditCount ?? 0;
|
|
10885
10885
|
stats.requests += 1;
|
|
10886
10886
|
stats.totalCredits += creditCount ?? 0;
|
|
10887
|
-
stats.byPath.set(
|
|
10887
|
+
stats.byPath.set(path25, existing);
|
|
10888
10888
|
};
|
|
10889
10889
|
formatCoinMarketCapFetchStats = (stats) => {
|
|
10890
10890
|
const byPath = [...stats.byPath.entries()].map(
|
|
10891
|
-
([
|
|
10891
|
+
([path25, item]) => `${getCoinMarketCapPathLabel(path25)}=${item.requests}req/${item.credits}cr`
|
|
10892
10892
|
).join(" ");
|
|
10893
10893
|
return `apiRequests=${stats.requests} apiCredits=${stats.totalCredits}${byPath ? ` ${byPath}` : ""}`;
|
|
10894
10894
|
};
|
|
@@ -11865,10 +11865,11 @@ var init_hyperliquidRateLimiter = __esm({
|
|
|
11865
11865
|
});
|
|
11866
11866
|
|
|
11867
11867
|
// src/lib/hyperliquidWhaleBackfill.ts
|
|
11868
|
-
var import_timescale4, import_strategies4, DEFAULT_BASE_URL, DEFAULT_CONCURRENCY, DEFAULT_RATE_LIMIT_WEIGHT, MAX_PAGE_SIZE, MAX_PAGES_PER_WHALE, REQUEST_WEIGHT, sleep3, positiveInt, minuteCeil, nextMinute, fetchHyperliquidUserFillsByTime, runConcurrent, backfillHyperliquidWhaleContext;
|
|
11868
|
+
var import_progress6, import_timescale4, import_strategies4, DEFAULT_BASE_URL, DEFAULT_CONCURRENCY, DEFAULT_RATE_LIMIT_WEIGHT, MAX_PAGE_SIZE, MAX_PAGES_PER_WHALE, REQUEST_WEIGHT, sleep3, positiveInt, minuteCeil, nextMinute, fetchHyperliquidUserFillsByTime, runConcurrent, backfillHyperliquidWhaleContext;
|
|
11869
11869
|
var init_hyperliquidWhaleBackfill = __esm({
|
|
11870
11870
|
"src/lib/hyperliquidWhaleBackfill.ts"() {
|
|
11871
11871
|
"use strict";
|
|
11872
|
+
import_progress6 = __toESM(require("progress"));
|
|
11872
11873
|
import_timescale4 = require("@tradejs/infra/timescale");
|
|
11873
11874
|
import_strategies4 = require("@tradejs/node/strategies");
|
|
11874
11875
|
init_hyperliquidWhaleData();
|
|
@@ -12094,11 +12095,36 @@ var init_hyperliquidWhaleBackfill = __esm({
|
|
|
12094
12095
|
toMs,
|
|
12095
12096
|
...identity
|
|
12096
12097
|
});
|
|
12098
|
+
const totalCoverageBuckets = Math.ceil(
|
|
12099
|
+
(toMs - fromMs) / HYPERLIQUID_WHALE_BUCKET_MS
|
|
12100
|
+
);
|
|
12101
|
+
const coverageBar = new import_progress6.default(
|
|
12102
|
+
"Hyperliquid coverage :current/:total [:bar][:percent] :eta(s) rows=:rows chunk=:chunk",
|
|
12103
|
+
{
|
|
12104
|
+
total: Math.max(1, totalCoverageBuckets),
|
|
12105
|
+
width: 24
|
|
12106
|
+
}
|
|
12107
|
+
);
|
|
12108
|
+
let displayedCoverageBuckets = 0;
|
|
12097
12109
|
const coverageBuckets = await (0, import_timescale4.rebuildHyperliquidWhaleCoverageRows)({
|
|
12098
12110
|
fromMs,
|
|
12099
12111
|
toMs,
|
|
12100
12112
|
expectedWhales: whales.addresses.length,
|
|
12101
|
-
...identity
|
|
12113
|
+
...identity,
|
|
12114
|
+
onProgress: (progress) => {
|
|
12115
|
+
const next = Math.max(
|
|
12116
|
+
displayedCoverageBuckets,
|
|
12117
|
+
Math.min(progress.completedBuckets, coverageBar.total)
|
|
12118
|
+
);
|
|
12119
|
+
const delta = next - displayedCoverageBuckets;
|
|
12120
|
+
if (delta > 0) {
|
|
12121
|
+
coverageBar.tick(delta, {
|
|
12122
|
+
rows: progress.rows,
|
|
12123
|
+
chunk: `${progress.chunkIndex}/${progress.totalChunks}`
|
|
12124
|
+
});
|
|
12125
|
+
displayedCoverageBuckets = next;
|
|
12126
|
+
}
|
|
12127
|
+
}
|
|
12102
12128
|
});
|
|
12103
12129
|
const result = {
|
|
12104
12130
|
cached: false,
|
|
@@ -13490,14 +13516,31 @@ var init_runState = __esm({
|
|
|
13490
13516
|
});
|
|
13491
13517
|
|
|
13492
13518
|
// src/lib/backtest/workerPool.ts
|
|
13493
|
-
var
|
|
13519
|
+
var import_progress7, import_child_process, import_chalk13, import_node_crypto3, DEFAULT_PG_POOL_MAX, FAST_AI_PG_CONNECTION_BUDGET, MIN_FAST_AI_WORKER_PG_POOL_MAX, resolveFastAiWorkerPgPoolMax, executeBacktestWorkerPool;
|
|
13494
13520
|
var init_workerPool = __esm({
|
|
13495
13521
|
"src/lib/backtest/workerPool.ts"() {
|
|
13496
13522
|
"use strict";
|
|
13497
|
-
|
|
13523
|
+
import_progress7 = __toESM(require("progress"));
|
|
13498
13524
|
import_child_process = require("child_process");
|
|
13499
13525
|
import_chalk13 = __toESM(require("chalk"));
|
|
13500
13526
|
import_node_crypto3 = require("crypto");
|
|
13527
|
+
DEFAULT_PG_POOL_MAX = 10;
|
|
13528
|
+
FAST_AI_PG_CONNECTION_BUDGET = 18;
|
|
13529
|
+
MIN_FAST_AI_WORKER_PG_POOL_MAX = 3;
|
|
13530
|
+
resolveFastAiWorkerPgPoolMax = (testSuite, workerCount, configuredPoolMax) => {
|
|
13531
|
+
if (configuredPoolMax?.trim() || workerCount <= 1 || testSuite.length === 0 || testSuite.some((test) => !test.fast || !test.ai)) {
|
|
13532
|
+
return void 0;
|
|
13533
|
+
}
|
|
13534
|
+
return String(
|
|
13535
|
+
Math.min(
|
|
13536
|
+
DEFAULT_PG_POOL_MAX,
|
|
13537
|
+
Math.max(
|
|
13538
|
+
MIN_FAST_AI_WORKER_PG_POOL_MAX,
|
|
13539
|
+
Math.floor(FAST_AI_PG_CONNECTION_BUDGET / workerCount)
|
|
13540
|
+
)
|
|
13541
|
+
)
|
|
13542
|
+
);
|
|
13543
|
+
};
|
|
13501
13544
|
executeBacktestWorkerPool = async ({
|
|
13502
13545
|
testSuite,
|
|
13503
13546
|
userName: userName2,
|
|
@@ -13516,6 +13559,12 @@ var init_workerPool = __esm({
|
|
|
13516
13559
|
totalTests
|
|
13517
13560
|
}) => {
|
|
13518
13561
|
const chunks = chunkTestSuite(testSuite);
|
|
13562
|
+
const fastAiWorkerPgPoolMax = resolveFastAiWorkerPgPoolMax(
|
|
13563
|
+
testSuite,
|
|
13564
|
+
chunks.length,
|
|
13565
|
+
process.env.PG_POOL_MAX
|
|
13566
|
+
);
|
|
13567
|
+
const workerEnv = fastAiWorkerPgPoolMax ? { ...process.env, PG_POOL_MAX: fastAiWorkerPgPoolMax } : void 0;
|
|
13519
13568
|
const totalExpectedTests = Math.max(
|
|
13520
13569
|
testSuite.length,
|
|
13521
13570
|
totalTests ?? testSuite.length,
|
|
@@ -13573,7 +13622,7 @@ var init_workerPool = __esm({
|
|
|
13573
13622
|
console.log(line);
|
|
13574
13623
|
}
|
|
13575
13624
|
console.log("");
|
|
13576
|
-
const bar = new
|
|
13625
|
+
const bar = new import_progress7.default(
|
|
13577
13626
|
":current/:total [:bar][:percent] avg :amount win :winRate trades :trades :eta(s)",
|
|
13578
13627
|
{
|
|
13579
13628
|
total: totalExpectedTests,
|
|
@@ -13601,6 +13650,7 @@ var init_workerPool = __esm({
|
|
|
13601
13650
|
const chunkId = runId ? `${runId}-${attemptId}` : attemptId;
|
|
13602
13651
|
const chunkWithId = chunk.map((test) => ({ ...test, chunkId }));
|
|
13603
13652
|
const tester = (0, import_child_process.fork)(testerWorkerPath, [], {
|
|
13653
|
+
...workerEnv ? { env: workerEnv } : {},
|
|
13604
13654
|
execArgv: testerNeedsTsRuntime ? [
|
|
13605
13655
|
`--max-old-space-size=${workerHeapMb2}`,
|
|
13606
13656
|
"-r",
|
|
@@ -16728,15 +16778,15 @@ var require_pg_connection_string = __commonJS({
|
|
|
16728
16778
|
if (config.sslnegotiation === "direct" && config.ssl === void 0) {
|
|
16729
16779
|
config.ssl = true;
|
|
16730
16780
|
}
|
|
16731
|
-
const
|
|
16781
|
+
const fs24 = config.sslcert || config.sslkey || config.sslrootcert ? require("fs") : null;
|
|
16732
16782
|
if (config.sslcert) {
|
|
16733
|
-
config.ssl.cert =
|
|
16783
|
+
config.ssl.cert = fs24.readFileSync(config.sslcert).toString();
|
|
16734
16784
|
}
|
|
16735
16785
|
if (config.sslkey) {
|
|
16736
|
-
config.ssl.key =
|
|
16786
|
+
config.ssl.key = fs24.readFileSync(config.sslkey).toString();
|
|
16737
16787
|
}
|
|
16738
16788
|
if (config.sslrootcert) {
|
|
16739
|
-
config.ssl.ca =
|
|
16789
|
+
config.ssl.ca = fs24.readFileSync(config.sslrootcert).toString();
|
|
16740
16790
|
}
|
|
16741
16791
|
if (options.useLibpqCompat && config.uselibpqcompat) {
|
|
16742
16792
|
throw new Error("Both useLibpqCompat and uselibpqcompat are set. Please use only one of them.");
|
|
@@ -18556,7 +18606,7 @@ var require_split2 = __commonJS({
|
|
|
18556
18606
|
var require_helper = __commonJS({
|
|
18557
18607
|
"../../node_modules/pgpass/lib/helper.js"(exports2, module2) {
|
|
18558
18608
|
"use strict";
|
|
18559
|
-
var
|
|
18609
|
+
var path25 = require("path");
|
|
18560
18610
|
var Stream = require("stream").Stream;
|
|
18561
18611
|
var split = require_split2();
|
|
18562
18612
|
var util = require("util");
|
|
@@ -18595,7 +18645,7 @@ var require_helper = __commonJS({
|
|
|
18595
18645
|
};
|
|
18596
18646
|
module2.exports.getFileName = function(rawEnv) {
|
|
18597
18647
|
var env = rawEnv || process.env;
|
|
18598
|
-
var file = env.PGPASSFILE || (isWin ?
|
|
18648
|
+
var file = env.PGPASSFILE || (isWin ? path25.join(env.APPDATA || "./", "postgresql", "pgpass.conf") : path25.join(env.HOME || "./", ".pgpass"));
|
|
18599
18649
|
return file;
|
|
18600
18650
|
};
|
|
18601
18651
|
module2.exports.usePgPass = function(stats, fname) {
|
|
@@ -18727,16 +18777,16 @@ var require_helper = __commonJS({
|
|
|
18727
18777
|
var require_lib = __commonJS({
|
|
18728
18778
|
"../../node_modules/pgpass/lib/index.js"(exports2, module2) {
|
|
18729
18779
|
"use strict";
|
|
18730
|
-
var
|
|
18731
|
-
var
|
|
18780
|
+
var path25 = require("path");
|
|
18781
|
+
var fs24 = require("fs");
|
|
18732
18782
|
var helper = require_helper();
|
|
18733
18783
|
module2.exports = function(connInfo, cb) {
|
|
18734
18784
|
var file = helper.getFileName();
|
|
18735
|
-
|
|
18785
|
+
fs24.stat(file, function(err, stat) {
|
|
18736
18786
|
if (err || !helper.usePgPass(stat, file)) {
|
|
18737
18787
|
return cb(void 0);
|
|
18738
18788
|
}
|
|
18739
|
-
var st =
|
|
18789
|
+
var st = fs24.createReadStream(file);
|
|
18740
18790
|
helper.getPassword(connInfo, st, cb);
|
|
18741
18791
|
});
|
|
18742
18792
|
};
|
|
@@ -20833,12 +20883,12 @@ var continuity_exports = {};
|
|
|
20833
20883
|
__export(continuity_exports, {
|
|
20834
20884
|
main: () => main13
|
|
20835
20885
|
});
|
|
20836
|
-
var import_args12,
|
|
20886
|
+
var import_args12, import_progress8, import_chalk20, import_connectors10, import_cli8, import_constants11, import_time5, import_logger2, import_timescale7, flags12, interval2, intervalKey, projectRoot5, parseProviders, runContinuity, main13;
|
|
20837
20887
|
var init_continuity2 = __esm({
|
|
20838
20888
|
"src/scripts/continuity.ts"() {
|
|
20839
20889
|
"use strict";
|
|
20840
20890
|
import_args12 = __toESM(require("args"));
|
|
20841
|
-
|
|
20891
|
+
import_progress8 = __toESM(require("progress"));
|
|
20842
20892
|
import_chalk20 = __toESM(require("chalk"));
|
|
20843
20893
|
import_connectors10 = require("@tradejs/node/connectors");
|
|
20844
20894
|
import_cli8 = require("@tradejs/node/cli");
|
|
@@ -20895,7 +20945,7 @@ var init_continuity2 = __esm({
|
|
|
20895
20945
|
void 0,
|
|
20896
20946
|
{ universe }
|
|
20897
20947
|
);
|
|
20898
|
-
const bar = new
|
|
20948
|
+
const bar = new import_progress8.default(
|
|
20899
20949
|
":current/:total [:bar][:percent] broken::broken fixed::fixed :eta(s) :symbol",
|
|
20900
20950
|
{
|
|
20901
20951
|
total: tickers.length,
|
|
@@ -21149,14 +21199,14 @@ var derivativesIngestCoinalyzeAll_exports = {};
|
|
|
21149
21199
|
__export(derivativesIngestCoinalyzeAll_exports, {
|
|
21150
21200
|
main: () => main15
|
|
21151
21201
|
});
|
|
21152
|
-
var import_config5, import_args14, import_chalk22,
|
|
21202
|
+
var import_config5, import_args14, import_chalk22, import_progress9, import_lodash2, import_connectors12, import_indicators3, import_async4, import_userSettings5, import_cli9, import_timescale9, coinalyzeIntervalMap2, flags14, asInt6, parseList2, coinalyzeBaseUrl, coinalyzeMaxRetries, lastRequestTs3, fetchJsonWithRateLimit2, fetchCoinalyzeMarkets2, selectBestMarket2, buildMatches2, normalizeMetricPoint2, toSeriesMap2, fetchMetricBatch2, main15;
|
|
21153
21203
|
var init_derivativesIngestCoinalyzeAll = __esm({
|
|
21154
21204
|
"src/scripts/derivativesIngestCoinalyzeAll.ts"() {
|
|
21155
21205
|
"use strict";
|
|
21156
21206
|
import_config5 = require("dotenv/config");
|
|
21157
21207
|
import_args14 = __toESM(require("args"));
|
|
21158
21208
|
import_chalk22 = __toESM(require("chalk"));
|
|
21159
|
-
|
|
21209
|
+
import_progress9 = __toESM(require("progress"));
|
|
21160
21210
|
import_lodash2 = __toESM(require("lodash"));
|
|
21161
21211
|
import_connectors12 = require("@tradejs/connectors");
|
|
21162
21212
|
import_indicators3 = require("@tradejs/core/indicators");
|
|
@@ -21433,7 +21483,7 @@ var init_derivativesIngestCoinalyzeAll = __esm({
|
|
|
21433
21483
|
const symbolBatches = import_lodash2.default.chunk(matches, symbolBatchSize);
|
|
21434
21484
|
const windowsPerPair = Math.ceil(days / batchDays);
|
|
21435
21485
|
const totalWindows = symbolBatches.length * intervals.length * windowsPerPair;
|
|
21436
|
-
const bar = new
|
|
21486
|
+
const bar = new import_progress9.default(
|
|
21437
21487
|
":current/:total [:bar][:percent] :eta(s) :batch rows=:rows fail=:fail",
|
|
21438
21488
|
{
|
|
21439
21489
|
total: Math.max(1, totalWindows),
|
|
@@ -22731,11 +22781,11 @@ var migration_exports = {};
|
|
|
22731
22781
|
__export(migration_exports, {
|
|
22732
22782
|
main: () => main22
|
|
22733
22783
|
});
|
|
22734
|
-
var
|
|
22784
|
+
var import_progress10, import_chalk30, import_logger3, import_files, import_timescale11, DIR, re, BATCH, projectRoot7, migrateFile, main22;
|
|
22735
22785
|
var init_migration = __esm({
|
|
22736
22786
|
"src/scripts/migration.ts"() {
|
|
22737
22787
|
"use strict";
|
|
22738
|
-
|
|
22788
|
+
import_progress10 = __toESM(require("progress"));
|
|
22739
22789
|
import_chalk30 = __toESM(require("chalk"));
|
|
22740
22790
|
import_logger3 = require("@tradejs/infra/logger");
|
|
22741
22791
|
import_files = require("@tradejs/infra/files");
|
|
@@ -22762,7 +22812,7 @@ var init_migration = __esm({
|
|
|
22762
22812
|
};
|
|
22763
22813
|
main22 = async () => {
|
|
22764
22814
|
const files = await (0, import_files.getFiles)(DIR, projectRoot7);
|
|
22765
|
-
const bar = new
|
|
22815
|
+
const bar = new import_progress10.default(
|
|
22766
22816
|
":current/:total [:bar][:percent] :eta(s) :file",
|
|
22767
22817
|
{
|
|
22768
22818
|
total: files.length,
|
|
@@ -27365,7 +27415,7 @@ var init_replayRuntimeEvidence = __esm({
|
|
|
27365
27415
|
});
|
|
27366
27416
|
|
|
27367
27417
|
// src/lib/runtimeEvidenceArtifacts.ts
|
|
27368
|
-
var import_node_crypto5, import_promises15, import_node_path8, RUNTIME_EVIDENCE_MANIFEST_FILE, RUNTIME_EVIDENCE_PAYLOAD_FILE, RUNTIME_EVIDENCE_COMPLETE_FILE, asRecord4, sha256, isExistingDestinationError, safeSegment, compactTimestamp, dateParts, assertFiniteTimestamp, parseManifest, publishRuntimeEvidenceBundle, verifyRuntimeEvidenceBundle, discoverRuntimeEvidenceBundles;
|
|
27418
|
+
var import_node_crypto5, import_promises15, import_node_path8, RUNTIME_EVIDENCE_MANIFEST_FILE, RUNTIME_EVIDENCE_PAYLOAD_FILE, RUNTIME_EVIDENCE_COMPLETE_FILE, asRecord4, sha256, runtimeEvidenceIdentitySha256, isExistingDestinationError, safeSegment, compactTimestamp, dateParts, assertFiniteTimestamp, parseManifest, publishRuntimeEvidenceBundle, verifyRuntimeEvidenceBundle, discoverRuntimeEvidenceBundles;
|
|
27369
27419
|
var init_runtimeEvidenceArtifacts = __esm({
|
|
27370
27420
|
"src/lib/runtimeEvidenceArtifacts.ts"() {
|
|
27371
27421
|
"use strict";
|
|
@@ -27377,6 +27427,17 @@ var init_runtimeEvidenceArtifacts = __esm({
|
|
|
27377
27427
|
RUNTIME_EVIDENCE_COMPLETE_FILE = ".complete";
|
|
27378
27428
|
asRecord4 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
27379
27429
|
sha256 = (value) => (0, import_node_crypto5.createHash)("sha256").update(value).digest("hex");
|
|
27430
|
+
runtimeEvidenceIdentitySha256 = (artifact) => {
|
|
27431
|
+
const identityArtifact = { ...artifact };
|
|
27432
|
+
delete identityArtifact.generatedAt;
|
|
27433
|
+
const runtime = asRecord4(identityArtifact.runtime);
|
|
27434
|
+
if (runtime) {
|
|
27435
|
+
const identityRuntime = { ...runtime };
|
|
27436
|
+
delete identityRuntime.generatedAt;
|
|
27437
|
+
identityArtifact.runtime = identityRuntime;
|
|
27438
|
+
}
|
|
27439
|
+
return sha256(JSON.stringify(identityArtifact));
|
|
27440
|
+
};
|
|
27380
27441
|
isExistingDestinationError = (error) => {
|
|
27381
27442
|
const code = error.code;
|
|
27382
27443
|
return code === "EEXIST" || code === "ENOTEMPTY";
|
|
@@ -27447,11 +27508,12 @@ var init_runtimeEvidenceArtifacts = __esm({
|
|
|
27447
27508
|
const payload = `${JSON.stringify(artifact, null, 2)}
|
|
27448
27509
|
`;
|
|
27449
27510
|
const payloadSha256 = sha256(payload);
|
|
27511
|
+
const identitySha256 = runtimeEvidenceIdentitySha256(artifact);
|
|
27450
27512
|
const safeDeploymentId = safeSegment(deploymentId, "default");
|
|
27451
27513
|
const artifactId = [
|
|
27452
27514
|
compactTimestamp(startTime),
|
|
27453
27515
|
compactTimestamp(endTime),
|
|
27454
|
-
|
|
27516
|
+
identitySha256.slice(0, 16)
|
|
27455
27517
|
].join("_");
|
|
27456
27518
|
const createdAt = Date.now();
|
|
27457
27519
|
const manifest = {
|
|
@@ -28858,21 +28920,21 @@ var init_serverHealth = __esm({
|
|
|
28858
28920
|
}
|
|
28859
28921
|
return `${minutes}m`;
|
|
28860
28922
|
};
|
|
28861
|
-
readDiskUsage = (
|
|
28923
|
+
readDiskUsage = (path25) => {
|
|
28862
28924
|
try {
|
|
28863
|
-
const stats = (0, import_node_fs2.statfsSync)(
|
|
28925
|
+
const stats = (0, import_node_fs2.statfsSync)(path25);
|
|
28864
28926
|
const totalBlocks = Number(stats.blocks ?? 0);
|
|
28865
28927
|
const availableBlocks = Number(stats.bavail ?? 0);
|
|
28866
28928
|
if (totalBlocks <= 0) {
|
|
28867
|
-
return { path:
|
|
28929
|
+
return { path: path25, usedPct: null };
|
|
28868
28930
|
}
|
|
28869
28931
|
const usedPct = (totalBlocks - Math.max(0, availableBlocks)) / totalBlocks * 100;
|
|
28870
28932
|
return {
|
|
28871
|
-
path:
|
|
28933
|
+
path: path25,
|
|
28872
28934
|
usedPct: Number.isFinite(usedPct) ? usedPct : null
|
|
28873
28935
|
};
|
|
28874
28936
|
} catch {
|
|
28875
|
-
return { path:
|
|
28937
|
+
return { path: path25, usedPct: null };
|
|
28876
28938
|
}
|
|
28877
28939
|
};
|
|
28878
28940
|
parseMeminfoBytes = (value) => {
|
|
@@ -32232,13 +32294,13 @@ __export(signals_exports, {
|
|
|
32232
32294
|
signalsConfiguredScopesOnce: () => signalsConfiguredScopesOnce,
|
|
32233
32295
|
signalsDaemon: () => signalsDaemon
|
|
32234
32296
|
});
|
|
32235
|
-
var import_config11, import_args31,
|
|
32297
|
+
var import_config11, import_args31, import_progress11, import_chalk43, import_connectors16, import_cli12, import_async5, import_strategies13, import_constants16, import_strategies14, import_time8, import_logger10, import_tradingAccounts3, SLOW_SIGNALS_WARNING_MS, projectRoot14, flags30, interval4, intervalMs, formatDuration3, resolvePositiveInteger2, resolveNonNegativeInteger, resolveSignalsDaemonMaxLiveBars, isSignalsKlineWsEnabled, resolveSignalsKlineWsWaitMs, createDefaultSignalsLifecycle, timeOperation3, formatSlowSignalsWarning, resolveSignalsConnectorName, createSignalsSession, findSignals, signals, loadConfiguredSignalsScopes, hasExplicitSignalsScope, signalsConfiguredScopesOnce, signalsDaemon, main38;
|
|
32236
32298
|
var init_signals = __esm({
|
|
32237
32299
|
"src/scripts/signals.ts"() {
|
|
32238
32300
|
"use strict";
|
|
32239
32301
|
import_config11 = require("dotenv/config");
|
|
32240
32302
|
import_args31 = __toESM(require("args"));
|
|
32241
|
-
|
|
32303
|
+
import_progress11 = __toESM(require("progress"));
|
|
32242
32304
|
import_chalk43 = __toESM(require("chalk"));
|
|
32243
32305
|
import_connectors16 = require("@tradejs/node/connectors");
|
|
32244
32306
|
import_cli12 = require("@tradejs/node/cli");
|
|
@@ -32885,7 +32947,7 @@ var init_signals = __esm({
|
|
|
32885
32947
|
return;
|
|
32886
32948
|
}
|
|
32887
32949
|
const strategyStats = createStrategySkipStats(runtimeStrategies);
|
|
32888
|
-
const bar = new
|
|
32950
|
+
const bar = new import_progress11.default(
|
|
32889
32951
|
":current/:total [:bar][:percent] :found :eta(s) :symbol",
|
|
32890
32952
|
{
|
|
32891
32953
|
total: tickers.length,
|
|
@@ -33223,7 +33285,7 @@ var init_signalsDaemon = __esm({
|
|
|
33223
33285
|
});
|
|
33224
33286
|
|
|
33225
33287
|
// src/lib/replay/cliConfig.ts
|
|
33226
|
-
var import_args32, REPLAY_UNSUPPORTED_FLAGS, hasCliFlag2, assertNoUnsupportedReplayFlags, replayNormalizedArgv, replayFlags, replayInterval, replayUserName, replayProjectRoot, isReplayUpdateOnlyRun;
|
|
33288
|
+
var import_args32, REPLAY_UNSUPPORTED_FLAGS, hasCliFlag2, assertNoUnsupportedReplayFlags, replayNormalizedArgv, replayFlags, replayInterval, replayUserName, replayProjectRoot, replayRuntimeEvidencePath, isReplayUpdateOnlyRun;
|
|
33227
33289
|
var init_cliConfig2 = __esm({
|
|
33228
33290
|
"src/lib/replay/cliConfig.ts"() {
|
|
33229
33291
|
"use strict";
|
|
@@ -33272,6 +33334,10 @@ var init_cliConfig2 = __esm({
|
|
|
33272
33334
|
import_args32.default.option(["d", "days"], "Run replay only for the last N days");
|
|
33273
33335
|
import_args32.default.option("startTime", "Explicit replay start timestamp (ms or seconds)");
|
|
33274
33336
|
import_args32.default.option("endTime", "Explicit replay end timestamp (ms or seconds)");
|
|
33337
|
+
import_args32.default.option(
|
|
33338
|
+
"runtimeEvidence",
|
|
33339
|
+
"Immutable runtime evidence JSON used for offline runtime comparison"
|
|
33340
|
+
);
|
|
33275
33341
|
import_args32.default.option(["u", "updateOnly"], "Only update tickers history", false);
|
|
33276
33342
|
import_args32.default.option(["C", "cacheOnly"], "Do not update tickers history", false);
|
|
33277
33343
|
import_args32.default.option(
|
|
@@ -33297,6 +33363,7 @@ var init_cliConfig2 = __esm({
|
|
|
33297
33363
|
replayInterval = String(replayFlags.timeframe ?? 15);
|
|
33298
33364
|
replayUserName = String(replayFlags.user ?? "root");
|
|
33299
33365
|
replayProjectRoot = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
33366
|
+
replayRuntimeEvidencePath = typeof replayFlags.runtimeEvidence === "string" && replayFlags.runtimeEvidence.trim() ? replayFlags.runtimeEvidence.trim() : null;
|
|
33300
33367
|
isReplayUpdateOnlyRun = Boolean(replayFlags.updateOnly);
|
|
33301
33368
|
}
|
|
33302
33369
|
});
|
|
@@ -33712,12 +33779,12 @@ var init_portfolioReplayConnector = __esm({
|
|
|
33712
33779
|
});
|
|
33713
33780
|
|
|
33714
33781
|
// src/lib/replay/historicalSignalsReplay.ts
|
|
33715
|
-
var import_chalk44,
|
|
33782
|
+
var import_chalk44, import_progress12, import_backtest4, import_strategies15, import_time9, import_logger11, import_redis20, import_connectors17, import_cli13, import_strategies16, loadRuntimeStrategies2, loadReferenceConnector, buildPreparedData, buildAfterSignalsContext, buildSymbolSharedReplayKey, runHistoricalSignalsReplay;
|
|
33716
33783
|
var init_historicalSignalsReplay = __esm({
|
|
33717
33784
|
"src/lib/replay/historicalSignalsReplay.ts"() {
|
|
33718
33785
|
"use strict";
|
|
33719
33786
|
import_chalk44 = __toESM(require("chalk"));
|
|
33720
|
-
|
|
33787
|
+
import_progress12 = __toESM(require("progress"));
|
|
33721
33788
|
import_backtest4 = require("@tradejs/core/backtest");
|
|
33722
33789
|
import_strategies15 = require("@tradejs/core/strategies");
|
|
33723
33790
|
import_time9 = require("@tradejs/core/time");
|
|
@@ -33897,7 +33964,7 @@ var init_historicalSignalsReplay = __esm({
|
|
|
33897
33964
|
const sharedReplayKeyPrefixes = [];
|
|
33898
33965
|
let preparedSymbols = 0;
|
|
33899
33966
|
let skippedSymbols = 0;
|
|
33900
|
-
const prepareBar = new
|
|
33967
|
+
const prepareBar = new import_progress12.default(
|
|
33901
33968
|
"prepare :current/:total [:bar][:percent] skipped=:skipped :etas(s) :symbol",
|
|
33902
33969
|
{
|
|
33903
33970
|
total: preparedRun.tickers.length,
|
|
@@ -34019,7 +34086,7 @@ var init_historicalSignalsReplay = __esm({
|
|
|
34019
34086
|
interval: interval5
|
|
34020
34087
|
});
|
|
34021
34088
|
let abortedCycles = 0;
|
|
34022
|
-
const cycleBar = new
|
|
34089
|
+
const cycleBar = new import_progress12.default(
|
|
34023
34090
|
"cycles :current/:total [:bar][:percent] sig=:signals abort=:aborted :etas(s) :ts",
|
|
34024
34091
|
{
|
|
34025
34092
|
total: orderedTimestamps.length,
|
|
@@ -35324,6 +35391,121 @@ var init_runtimeParityDetails = __esm({
|
|
|
35324
35391
|
}
|
|
35325
35392
|
});
|
|
35326
35393
|
|
|
35394
|
+
// src/lib/replay/runtimeEvidenceSource.ts
|
|
35395
|
+
var import_promises20, import_node_path14, asRecord6, asFiniteNumber, unwrapRows2, buildRuntimeEvidenceLineageScopes, loadReplayRuntimeEvidenceSource;
|
|
35396
|
+
var init_runtimeEvidenceSource = __esm({
|
|
35397
|
+
"src/lib/replay/runtimeEvidenceSource.ts"() {
|
|
35398
|
+
"use strict";
|
|
35399
|
+
import_promises20 = __toESM(require("fs/promises"));
|
|
35400
|
+
import_node_path14 = __toESM(require("path"));
|
|
35401
|
+
init_runtimeLineage();
|
|
35402
|
+
asRecord6 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
35403
|
+
asFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
35404
|
+
unwrapRows2 = (value, field) => (Array.isArray(value) ? value : []).map((item) => {
|
|
35405
|
+
const row = asRecord6(item);
|
|
35406
|
+
return asRecord6(row?.[field]) ?? row;
|
|
35407
|
+
}).filter((item) => item != null);
|
|
35408
|
+
buildRuntimeEvidenceLineageScopes = ({
|
|
35409
|
+
signals: signals2,
|
|
35410
|
+
evaluations
|
|
35411
|
+
}) => {
|
|
35412
|
+
const scopes = /* @__PURE__ */ new Map();
|
|
35413
|
+
const add = ({
|
|
35414
|
+
strategy,
|
|
35415
|
+
symbol,
|
|
35416
|
+
runtimeConfigId,
|
|
35417
|
+
timestamp,
|
|
35418
|
+
lineage
|
|
35419
|
+
}) => {
|
|
35420
|
+
if (!lineage || !Number.isFinite(timestamp)) {
|
|
35421
|
+
return;
|
|
35422
|
+
}
|
|
35423
|
+
const key = `${strategy}::${symbol}::${runtimeLineageKey(lineage)}`;
|
|
35424
|
+
const existing = scopes.get(key);
|
|
35425
|
+
scopes.set(key, {
|
|
35426
|
+
strategy,
|
|
35427
|
+
symbol,
|
|
35428
|
+
...runtimeConfigId ? { runtimeConfigId } : {},
|
|
35429
|
+
lineage,
|
|
35430
|
+
firstTimestamp: existing ? Math.min(existing.firstTimestamp, timestamp) : timestamp,
|
|
35431
|
+
lastTimestamp: existing ? Math.max(existing.lastTimestamp, timestamp) : timestamp
|
|
35432
|
+
});
|
|
35433
|
+
};
|
|
35434
|
+
for (const signal of signals2) {
|
|
35435
|
+
add({
|
|
35436
|
+
strategy: signal.strategy,
|
|
35437
|
+
symbol: signal.symbol,
|
|
35438
|
+
runtimeConfigId: signal.runtimeConfigId,
|
|
35439
|
+
timestamp: signal.timestamp,
|
|
35440
|
+
lineage: signal.runtimeLineage
|
|
35441
|
+
});
|
|
35442
|
+
}
|
|
35443
|
+
for (const evaluation of evaluations) {
|
|
35444
|
+
add({
|
|
35445
|
+
strategy: evaluation.strategy,
|
|
35446
|
+
symbol: evaluation.symbol,
|
|
35447
|
+
runtimeConfigId: evaluation.runtimeConfigId,
|
|
35448
|
+
timestamp: evaluation.timestamp,
|
|
35449
|
+
lineage: evaluation.runtimeLineage
|
|
35450
|
+
});
|
|
35451
|
+
}
|
|
35452
|
+
return [...scopes.values()].sort(
|
|
35453
|
+
(left, right) => left.strategy.localeCompare(right.strategy) || left.symbol.localeCompare(right.symbol) || left.firstTimestamp - right.firstTimestamp
|
|
35454
|
+
);
|
|
35455
|
+
};
|
|
35456
|
+
loadReplayRuntimeEvidenceSource = async ({
|
|
35457
|
+
filePath,
|
|
35458
|
+
projectRoot: projectRoot16,
|
|
35459
|
+
expectedUserName,
|
|
35460
|
+
expectedWindow
|
|
35461
|
+
}) => {
|
|
35462
|
+
const resolvedPath = import_node_path14.default.resolve(projectRoot16, filePath);
|
|
35463
|
+
const root = asRecord6(
|
|
35464
|
+
JSON.parse(await import_promises20.default.readFile(resolvedPath, "utf8"))
|
|
35465
|
+
);
|
|
35466
|
+
const runtime = asRecord6(root?.runtime) ?? root;
|
|
35467
|
+
if (!root || !runtime) {
|
|
35468
|
+
throw new Error(`Invalid runtime evidence JSON: ${resolvedPath}`);
|
|
35469
|
+
}
|
|
35470
|
+
const rootWindow = asRecord6(root.window);
|
|
35471
|
+
const runtimeWindow2 = asRecord6(runtime.window);
|
|
35472
|
+
const startTime = asFiniteNumber(rootWindow?.startTime) ?? asFiniteNumber(runtimeWindow2?.startTime);
|
|
35473
|
+
const endTime = asFiniteNumber(rootWindow?.endTime) ?? asFiniteNumber(runtimeWindow2?.endTime);
|
|
35474
|
+
const userName2 = String(root.userName ?? runtime.userName ?? "").trim();
|
|
35475
|
+
if (!userName2 || userName2 !== expectedUserName) {
|
|
35476
|
+
throw new Error(
|
|
35477
|
+
`Runtime evidence user mismatch: expected=${expectedUserName}, actual=${userName2 || "missing"}`
|
|
35478
|
+
);
|
|
35479
|
+
}
|
|
35480
|
+
const endTimeMatches = endTime === expectedWindow.end || endTime === expectedWindow.end + 1;
|
|
35481
|
+
if (startTime !== expectedWindow.start || !endTimeMatches) {
|
|
35482
|
+
throw new Error(
|
|
35483
|
+
`Runtime evidence window mismatch: expected=${expectedWindow.start}..${expectedWindow.end}, actual=${startTime ?? "missing"}..${endTime ?? "missing"}`
|
|
35484
|
+
);
|
|
35485
|
+
}
|
|
35486
|
+
const trades = unwrapRows2(runtime.trades, "trade");
|
|
35487
|
+
const signals2 = unwrapRows2(runtime.signals, "signal");
|
|
35488
|
+
const evaluations = unwrapRows2(
|
|
35489
|
+
runtime.evaluations,
|
|
35490
|
+
"evaluation"
|
|
35491
|
+
);
|
|
35492
|
+
return {
|
|
35493
|
+
path: resolvedPath,
|
|
35494
|
+
userName: userName2,
|
|
35495
|
+
startTime,
|
|
35496
|
+
endTime,
|
|
35497
|
+
trades,
|
|
35498
|
+
signals: signals2,
|
|
35499
|
+
evaluations,
|
|
35500
|
+
lineageScopes: buildRuntimeEvidenceLineageScopes({
|
|
35501
|
+
signals: signals2,
|
|
35502
|
+
evaluations
|
|
35503
|
+
})
|
|
35504
|
+
};
|
|
35505
|
+
};
|
|
35506
|
+
}
|
|
35507
|
+
});
|
|
35508
|
+
|
|
35327
35509
|
// src/lib/replay/runtimeComparison.ts
|
|
35328
35510
|
var import_chalk46, import_time11, getReplayEntryTimestampCompareOffsetMs, buildReplaySignalEvaluations, lineageScopeKey, buildExpectedLineageByScope, hasExpectedLineage, filterReplayComparisonByLineage, formatDrilldownSummary, toFiniteNumberOrNull4, sumOptionalNumbers, firstFiniteNumber, firstString, summarizeBacktestPnlByStrategy, getExchangeExecutionMergeKey, mergeExchangeExecutionGroup, mergeExchangeEntryExecutions, loadExchangeEntryRows, buildPriceDeltaPct3, loadExchangeEntriesForComparison, compareExchangeEntriesToBacktest, findExchangeRuntimeOutcome, splitExchangeMatchesByRuntimeOrderStatus, saveAndPrintReplayExchangeComparison, saveAndPrintReplayRuntimeComparison;
|
|
35329
35511
|
var init_runtimeComparison = __esm({
|
|
@@ -35340,6 +35522,7 @@ var init_runtimeComparison = __esm({
|
|
|
35340
35522
|
init_runtimeParityDetails();
|
|
35341
35523
|
init_runState();
|
|
35342
35524
|
init_cliConfig2();
|
|
35525
|
+
init_runtimeEvidenceSource();
|
|
35343
35526
|
init_support();
|
|
35344
35527
|
init_runtimeLineage();
|
|
35345
35528
|
getReplayEntryTimestampCompareOffsetMs = () => {
|
|
@@ -36110,7 +36293,8 @@ var init_runtimeComparison = __esm({
|
|
|
36110
36293
|
liveStrategySummaries,
|
|
36111
36294
|
backtestEntries,
|
|
36112
36295
|
replaySignals,
|
|
36113
|
-
replayLineages
|
|
36296
|
+
replayLineages,
|
|
36297
|
+
runtimeEvidencePath
|
|
36114
36298
|
}) => {
|
|
36115
36299
|
const { connector, connectorName, window: window2 } = getRuntimeCompareContext();
|
|
36116
36300
|
if (!connector || !window2) {
|
|
@@ -36120,12 +36304,23 @@ var init_runtimeComparison = __esm({
|
|
|
36120
36304
|
liveStrategySummaries.map((summary) => summary.strategyName)
|
|
36121
36305
|
);
|
|
36122
36306
|
const replaySignalEvaluations = buildReplaySignalEvaluations(replaySignals);
|
|
36307
|
+
const runtimeEvidence2 = runtimeEvidencePath ? await loadReplayRuntimeEvidenceSource({
|
|
36308
|
+
filePath: runtimeEvidencePath,
|
|
36309
|
+
projectRoot: replayProjectRoot,
|
|
36310
|
+
expectedUserName: replayUserName,
|
|
36311
|
+
expectedWindow: window2
|
|
36312
|
+
}) : null;
|
|
36123
36313
|
const [
|
|
36124
36314
|
rawRuntimeTrades,
|
|
36125
36315
|
runtimeSignals,
|
|
36126
36316
|
runtimeSignalEvaluations,
|
|
36127
36317
|
runtimeLineageScopes
|
|
36128
|
-
] =
|
|
36318
|
+
] = runtimeEvidence2 ? [
|
|
36319
|
+
runtimeEvidence2.trades,
|
|
36320
|
+
runtimeEvidence2.signals,
|
|
36321
|
+
runtimeEvidence2.evaluations,
|
|
36322
|
+
runtimeEvidence2.lineageScopes
|
|
36323
|
+
] : await Promise.all([
|
|
36129
36324
|
loadRuntimeTrades(replayUserName, {
|
|
36130
36325
|
startTime: window2.start,
|
|
36131
36326
|
endTime: window2.end
|
|
@@ -36143,7 +36338,14 @@ var init_runtimeComparison = __esm({
|
|
|
36143
36338
|
endTime: window2.end
|
|
36144
36339
|
})
|
|
36145
36340
|
]);
|
|
36146
|
-
|
|
36341
|
+
if (runtimeEvidence2) {
|
|
36342
|
+
console.log(
|
|
36343
|
+
import_chalk46.default.gray(
|
|
36344
|
+
`runtime compare: using immutable evidence ${runtimeEvidence2.path}`
|
|
36345
|
+
)
|
|
36346
|
+
);
|
|
36347
|
+
}
|
|
36348
|
+
const syncedRuntimeTrades = runtimeEvidence2 ? rawRuntimeTrades : await syncRuntimeTrades({
|
|
36147
36349
|
userName: replayUserName,
|
|
36148
36350
|
connector,
|
|
36149
36351
|
trades: rawRuntimeTrades,
|
|
@@ -36194,7 +36396,7 @@ var init_runtimeComparison = __esm({
|
|
|
36194
36396
|
const windowRuntimeTrades = comparable.runtimeTrades.filter(
|
|
36195
36397
|
(trade) => trade.entryTimestamp >= window2.start && trade.entryTimestamp < window2.end && relevantStrategies.has(trade.strategy)
|
|
36196
36398
|
);
|
|
36197
|
-
if (!windowRuntimeTrades.length) {
|
|
36399
|
+
if (!windowRuntimeTrades.length && !runtimeEvidence2) {
|
|
36198
36400
|
console.log("");
|
|
36199
36401
|
console.log(
|
|
36200
36402
|
import_chalk46.default.yellow(
|
|
@@ -36328,12 +36530,12 @@ var init_runtimeComparison = __esm({
|
|
|
36328
36530
|
});
|
|
36329
36531
|
|
|
36330
36532
|
// src/lib/replay/outputReport.ts
|
|
36331
|
-
var
|
|
36533
|
+
var import_promises21, import_node_path15, import_data4, formatMsk, formatNumber5, formatMoney2, formatPct, tableCell, createMarkdownTable2, entryStrategy, entryKey, buildDrilldownMap, buildPerTradeAnalysis, renderMatchedRows, renderRuntimeOnlyRows, renderOrderFailedRows, renderBacktestOnlyRows, renderStrategyRows, renderLineageRows, writeReplayOutputReport;
|
|
36332
36534
|
var init_outputReport = __esm({
|
|
36333
36535
|
"src/lib/replay/outputReport.ts"() {
|
|
36334
36536
|
"use strict";
|
|
36335
|
-
|
|
36336
|
-
|
|
36537
|
+
import_promises21 = __toESM(require("fs/promises"));
|
|
36538
|
+
import_node_path15 = __toESM(require("path"));
|
|
36337
36539
|
import_data4 = require("@tradejs/core/data");
|
|
36338
36540
|
init_support();
|
|
36339
36541
|
formatMsk = (timestamp) => typeof timestamp === "number" && Number.isFinite(timestamp) ? new Intl.DateTimeFormat("ru-RU", {
|
|
@@ -36638,8 +36840,8 @@ var init_outputReport = __esm({
|
|
|
36638
36840
|
strategySnapshot,
|
|
36639
36841
|
runtimeComparison
|
|
36640
36842
|
}) => {
|
|
36641
|
-
const outputDir =
|
|
36642
|
-
await
|
|
36843
|
+
const outputDir = import_node_path15.default.resolve(projectRoot16, "data/replay/output");
|
|
36844
|
+
await import_promises21.default.mkdir(outputDir, { recursive: true });
|
|
36643
36845
|
const perTradeAnalysis = buildPerTradeAnalysis(runtimeComparison);
|
|
36644
36846
|
const report = {
|
|
36645
36847
|
reportType: "replay-output",
|
|
@@ -36674,8 +36876,8 @@ var init_outputReport = __esm({
|
|
|
36674
36876
|
runtimeComparison,
|
|
36675
36877
|
perTradeAnalysis
|
|
36676
36878
|
};
|
|
36677
|
-
const markdownPath =
|
|
36678
|
-
const jsonPath =
|
|
36879
|
+
const markdownPath = import_node_path15.default.join(outputDir, `${timestamp}-replay-report.md`);
|
|
36880
|
+
const jsonPath = import_node_path15.default.join(outputDir, `${timestamp}-replay-report.json`);
|
|
36679
36881
|
const lines = [
|
|
36680
36882
|
"# Replay Report",
|
|
36681
36883
|
"",
|
|
@@ -36741,8 +36943,8 @@ var init_outputReport = __esm({
|
|
|
36741
36943
|
""
|
|
36742
36944
|
];
|
|
36743
36945
|
await Promise.all([
|
|
36744
|
-
|
|
36745
|
-
|
|
36946
|
+
import_promises21.default.writeFile(markdownPath, lines.join("\n"), "utf8"),
|
|
36947
|
+
import_promises21.default.writeFile(jsonPath, `${(0, import_data4.toJson)(report, true)}
|
|
36746
36948
|
`, "utf8")
|
|
36747
36949
|
]);
|
|
36748
36950
|
return {
|
|
@@ -36807,7 +37009,8 @@ var init_replayRunner = __esm({
|
|
|
36807
37009
|
liveStrategySummaries: replayStrategySnapshot.summaries,
|
|
36808
37010
|
backtestEntries: replayStrategySnapshot.backtestEntries,
|
|
36809
37011
|
replaySignals: replayResult.signals,
|
|
36810
|
-
replayLineages: replayResult.runtimeLineages
|
|
37012
|
+
replayLineages: replayResult.runtimeLineages,
|
|
37013
|
+
runtimeEvidencePath: replayRuntimeEvidencePath
|
|
36811
37014
|
});
|
|
36812
37015
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
36813
37016
|
const durationSeconds = Number(
|