@tradejs/cli 3.1.29-beta.292 → 3.1.29-beta.296
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 +563 -485
- package/dist/lib/binanceMarketContextBackfill.js +2 -2
- package/dist/lib/coinMarketCapContextBackfill.js +1 -1
- package/dist/lib/marketContextPrepare.js +3 -3
- package/dist/lib/strategyResearch.js +33 -79
- package/dist/scripts/backtest.js +192 -69
- package/dist/scripts/binanceMarketIngest.js +3 -3
- package/dist/scripts/replay.js +3 -3
- package/dist/scripts/replayRunner.js +3 -3
- package/dist/scripts/runtimeParity.js +3 -3
- package/dist/scripts/signals.js +3 -3
- package/dist/scripts/signalsDaemon.js +3 -3
- 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
package/dist/cli.js
CHANGED
|
@@ -3086,10 +3086,10 @@ var init_io = __esm({
|
|
|
3086
3086
|
sha256Text = (value) => (0, import_node_crypto4.createHash)("sha256").update(value).digest("hex");
|
|
3087
3087
|
sha256Json = (value) => sha256Text(canonicalJson(value));
|
|
3088
3088
|
sha256File = async (filePath) => {
|
|
3089
|
-
const
|
|
3089
|
+
const hash2 = (0, import_node_crypto4.createHash)("sha256");
|
|
3090
3090
|
const input = (0, import_node_fs2.createReadStream)(filePath);
|
|
3091
|
-
for await (const chunk of input)
|
|
3092
|
-
return
|
|
3091
|
+
for await (const chunk of input) hash2.update(chunk);
|
|
3092
|
+
return hash2.digest("hex");
|
|
3093
3093
|
};
|
|
3094
3094
|
assertFinite = (value, name) => {
|
|
3095
3095
|
assert(typeof value === "number" && Number.isFinite(value), name);
|
|
@@ -5436,15 +5436,15 @@ var init_searchEngine = __esm({
|
|
|
5436
5436
|
};
|
|
5437
5437
|
};
|
|
5438
5438
|
hashMask = (mask) => {
|
|
5439
|
-
let
|
|
5439
|
+
let hash2 = 2166136261;
|
|
5440
5440
|
for (let index = 0; index < mask.length; index += 1) {
|
|
5441
5441
|
if (mask[index] !== 1) {
|
|
5442
5442
|
continue;
|
|
5443
5443
|
}
|
|
5444
|
-
|
|
5445
|
-
|
|
5444
|
+
hash2 ^= index + 1;
|
|
5445
|
+
hash2 = Math.imul(hash2, 16777619);
|
|
5446
5446
|
}
|
|
5447
|
-
return (
|
|
5447
|
+
return (hash2 >>> 0).toString(36);
|
|
5448
5448
|
};
|
|
5449
5449
|
isBetterRepresentativePocket = (candidate, existing, compare2) => candidate.depth < existing.depth || candidate.depth === existing.depth && candidate.condition.length < existing.condition.length || candidate.depth === existing.depth && candidate.condition.length === existing.condition.length && compare2(candidate, existing) < 0;
|
|
5450
5450
|
estimateCombinationCount = (poolSize, maxDepth, maxCombinations) => {
|
|
@@ -9483,18 +9483,18 @@ var init_strategyGateFingerprint = __esm({
|
|
|
9483
9483
|
const sourceEntries = candidates.filter(
|
|
9484
9484
|
(entry) => entry != null
|
|
9485
9485
|
);
|
|
9486
|
-
const
|
|
9487
|
-
|
|
9486
|
+
const hash2 = (0, import_node_crypto5.createHash)("sha256");
|
|
9487
|
+
hash2.update(strategyName);
|
|
9488
9488
|
if (sourceEntries.length) {
|
|
9489
9489
|
for (const entry of sourceEntries) {
|
|
9490
|
-
|
|
9491
|
-
|
|
9490
|
+
hash2.update(entry.specifier);
|
|
9491
|
+
hash2.update(entry.content);
|
|
9492
9492
|
}
|
|
9493
9493
|
} else {
|
|
9494
|
-
|
|
9494
|
+
hash2.update(gitSha ?? "unknown-git-sha");
|
|
9495
9495
|
}
|
|
9496
9496
|
return {
|
|
9497
|
-
gateFingerprint:
|
|
9497
|
+
gateFingerprint: hash2.digest("hex").slice(0, 16),
|
|
9498
9498
|
gateFingerprintFiles: sourceEntries.map((entry) => entry.specifier)
|
|
9499
9499
|
};
|
|
9500
9500
|
};
|
|
@@ -11907,13 +11907,12 @@ var init_binanceMarketContextBackfill = __esm({
|
|
|
11907
11907
|
};
|
|
11908
11908
|
intervalToMarketFeatureInterval = (interval4) => {
|
|
11909
11909
|
const normalized = String(interval4).trim().toLowerCase();
|
|
11910
|
-
if (normalized === "1" || normalized === "1m") return
|
|
11910
|
+
if (normalized === "1" || normalized === "1m") return null;
|
|
11911
11911
|
if (normalized === "5" || normalized === "5m") return "5m";
|
|
11912
11912
|
if (normalized === "60" || normalized === "1h") return "1h";
|
|
11913
11913
|
return "15m";
|
|
11914
11914
|
};
|
|
11915
11915
|
marketIntervalToConnectorInterval = (interval4) => {
|
|
11916
|
-
if (interval4 === "1m") return "1";
|
|
11917
11916
|
if (interval4 === "5m") return "5";
|
|
11918
11917
|
if (interval4 === "1h") return "60";
|
|
11919
11918
|
return "15";
|
|
@@ -12078,6 +12077,7 @@ var init_binanceMarketContextBackfill = __esm({
|
|
|
12078
12077
|
return skippedBackfillResult();
|
|
12079
12078
|
}
|
|
12080
12079
|
const interval4 = intervalToMarketFeatureInterval(params.interval);
|
|
12080
|
+
if (interval4 === null) return skippedBackfillResult();
|
|
12081
12081
|
const intervalMs = MARKET_FEATURE_INTERVAL_MS[interval4];
|
|
12082
12082
|
const { breadthStartMs, tradeFlowStartMs, endMs } = resolveBinanceMarketContextBackfillWindow(params);
|
|
12083
12083
|
if (endMs <= Math.min(breadthStartMs, tradeFlowStartMs)) {
|
|
@@ -13670,7 +13670,7 @@ var init_coinMarketCapContextBackfill = __esm({
|
|
|
13670
13670
|
};
|
|
13671
13671
|
fetchCoinMarketCapIndexRows = async (params) => {
|
|
13672
13672
|
const rows = [];
|
|
13673
|
-
const maxChunkDays =
|
|
13673
|
+
const maxChunkDays = 4;
|
|
13674
13674
|
const totalChunks = Math.max(
|
|
13675
13675
|
1,
|
|
13676
13676
|
Math.ceil(
|
|
@@ -16343,7 +16343,9 @@ var init_workerPool = __esm({
|
|
|
16343
16343
|
chunkTestSuite,
|
|
16344
16344
|
getProgressSnapshot,
|
|
16345
16345
|
initialCompletedTests = 0,
|
|
16346
|
-
totalTests
|
|
16346
|
+
totalTests,
|
|
16347
|
+
onProgress,
|
|
16348
|
+
onIncomplete
|
|
16347
16349
|
}) => {
|
|
16348
16350
|
const chunks = chunkTestSuite(testSuite);
|
|
16349
16351
|
const fastAiWorkerPgPoolMax = resolveFastAiWorkerPgPoolMax(
|
|
@@ -16359,7 +16361,9 @@ var init_workerPool = __esm({
|
|
|
16359
16361
|
);
|
|
16360
16362
|
let completedTests = initialCompletedTests;
|
|
16361
16363
|
let renderedTests = 0;
|
|
16364
|
+
let pendingResults = 0;
|
|
16362
16365
|
let isFinishing = false;
|
|
16366
|
+
let isInterrupted = false;
|
|
16363
16367
|
let signalHandlersRemoved = false;
|
|
16364
16368
|
const workers = /* @__PURE__ */ new Set();
|
|
16365
16369
|
const stopWorkers = () => {
|
|
@@ -16370,6 +16374,7 @@ var init_workerPool = __esm({
|
|
|
16370
16374
|
}
|
|
16371
16375
|
};
|
|
16372
16376
|
const handleInterrupt = (signal, exitCode) => {
|
|
16377
|
+
isInterrupted = true;
|
|
16373
16378
|
stopWorkers();
|
|
16374
16379
|
void Promise.resolve(onInterrupt?.(signal)).catch((error) => {
|
|
16375
16380
|
console.error(
|
|
@@ -16390,15 +16395,16 @@ var init_workerPool = __esm({
|
|
|
16390
16395
|
process.removeListener("SIGTERM", handleSigterm);
|
|
16391
16396
|
};
|
|
16392
16397
|
const maybeFinish = async () => {
|
|
16393
|
-
if (isFinishing) {
|
|
16394
|
-
return;
|
|
16395
|
-
}
|
|
16396
|
-
if (completedTests !== totalExpectedTests || workers.size > 0) {
|
|
16398
|
+
if (isFinishing || isInterrupted || workers.size > 0 || pendingResults > 0) {
|
|
16397
16399
|
return;
|
|
16398
16400
|
}
|
|
16399
16401
|
isFinishing = true;
|
|
16400
16402
|
try {
|
|
16401
|
-
|
|
16403
|
+
if (completedTests === totalExpectedTests) {
|
|
16404
|
+
await onFinish();
|
|
16405
|
+
} else {
|
|
16406
|
+
await onIncomplete?.();
|
|
16407
|
+
}
|
|
16402
16408
|
} finally {
|
|
16403
16409
|
cleanupSignalHandlers();
|
|
16404
16410
|
}
|
|
@@ -16457,14 +16463,22 @@ var init_workerPool = __esm({
|
|
|
16457
16463
|
return;
|
|
16458
16464
|
}
|
|
16459
16465
|
completedTests++;
|
|
16460
|
-
|
|
16461
|
-
|
|
16462
|
-
|
|
16466
|
+
onProgress?.(completedTests);
|
|
16467
|
+
pendingResults++;
|
|
16468
|
+
try {
|
|
16469
|
+
await onMessage(msg);
|
|
16470
|
+
if (completedTests % progressStep2 === 0 || completedTests === totalExpectedTests) {
|
|
16471
|
+
tickProgress();
|
|
16472
|
+
}
|
|
16473
|
+
} finally {
|
|
16474
|
+
pendingResults--;
|
|
16463
16475
|
}
|
|
16476
|
+
await maybeFinish();
|
|
16464
16477
|
});
|
|
16465
16478
|
tester.on("error", (err) => {
|
|
16466
16479
|
workers.delete(tester);
|
|
16467
16480
|
onWorkerError(err?.message ?? String(err));
|
|
16481
|
+
void maybeFinish();
|
|
16468
16482
|
});
|
|
16469
16483
|
tester.on("exit", (code) => {
|
|
16470
16484
|
workers.delete(tester);
|
|
@@ -16876,7 +16890,9 @@ var init_runnerCore = __esm({
|
|
|
16876
16890
|
onFinish,
|
|
16877
16891
|
initialCompletedTests = 0,
|
|
16878
16892
|
totalTests,
|
|
16879
|
-
backtestRunId
|
|
16893
|
+
backtestRunId,
|
|
16894
|
+
onProgress,
|
|
16895
|
+
onIncomplete
|
|
16880
16896
|
}) => {
|
|
16881
16897
|
markTestsStarted();
|
|
16882
16898
|
const { testerWorkerPath, testerNeedsTsRuntime } = resolveTesterWorker();
|
|
@@ -16900,6 +16916,8 @@ var init_runnerCore = __esm({
|
|
|
16900
16916
|
chunkTestSuite: (suite) => chunkTestSuiteBySymbol(suite, effectiveParallel),
|
|
16901
16917
|
initialCompletedTests,
|
|
16902
16918
|
totalTests,
|
|
16919
|
+
onProgress,
|
|
16920
|
+
onIncomplete,
|
|
16903
16921
|
onInterrupt,
|
|
16904
16922
|
onMessage: async (msg) => {
|
|
16905
16923
|
if (msg.error) {
|
|
@@ -16955,10 +16973,116 @@ var init_runnerCore = __esm({
|
|
|
16955
16973
|
}
|
|
16956
16974
|
});
|
|
16957
16975
|
|
|
16976
|
+
// src/lib/backtest/observeRun.ts
|
|
16977
|
+
var import_constants9, import_redis7, import_logger, HEARTBEAT_MS, ACTIVE_TTL_SECONDS, LINKED_RUN_TTL_SECONDS, RESEARCH_STUDY, MAX_VALUES_PER_PARAMETER, MAX_VALUE_LENGTH, summarizeBacktestParameters, observeBacktestRun;
|
|
16978
|
+
var init_observeRun = __esm({
|
|
16979
|
+
"src/lib/backtest/observeRun.ts"() {
|
|
16980
|
+
"use strict";
|
|
16981
|
+
import_constants9 = require("@tradejs/core/constants");
|
|
16982
|
+
import_redis7 = require("@tradejs/infra/redis");
|
|
16983
|
+
import_logger = require("@tradejs/infra/logger");
|
|
16984
|
+
HEARTBEAT_MS = 2e3;
|
|
16985
|
+
ACTIVE_TTL_SECONDS = 30;
|
|
16986
|
+
LINKED_RUN_TTL_SECONDS = 30 * 24 * import_constants9.TTL_1H;
|
|
16987
|
+
RESEARCH_STUDY = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}\/\d{4}-\d{2}-\d{2}-[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/;
|
|
16988
|
+
MAX_VALUES_PER_PARAMETER = 12;
|
|
16989
|
+
MAX_VALUE_LENGTH = 500;
|
|
16990
|
+
summarizeBacktestParameters = (tests) => {
|
|
16991
|
+
const parameters = /* @__PURE__ */ new Map();
|
|
16992
|
+
for (const test of tests) {
|
|
16993
|
+
for (const [name, value] of Object.entries(test.strategyConfig)) {
|
|
16994
|
+
const serialized = JSON.stringify(value);
|
|
16995
|
+
if (serialized === void 0) continue;
|
|
16996
|
+
const parameter = parameters.get(name) ?? {
|
|
16997
|
+
values: /* @__PURE__ */ new Set(),
|
|
16998
|
+
truncated: false
|
|
16999
|
+
};
|
|
17000
|
+
parameters.set(name, parameter);
|
|
17001
|
+
if (parameter.values.has(serialized)) continue;
|
|
17002
|
+
if (parameter.values.size === MAX_VALUES_PER_PARAMETER || serialized.length > MAX_VALUE_LENGTH) {
|
|
17003
|
+
parameter.truncated = true;
|
|
17004
|
+
} else {
|
|
17005
|
+
parameter.values.add(serialized);
|
|
17006
|
+
}
|
|
17007
|
+
}
|
|
17008
|
+
}
|
|
17009
|
+
return [...parameters].map(([name, { values, truncated }]) => ({
|
|
17010
|
+
name,
|
|
17011
|
+
values: [...values],
|
|
17012
|
+
truncated
|
|
17013
|
+
}));
|
|
17014
|
+
};
|
|
17015
|
+
observeBacktestRun = async (manifest, initialCompleted, parallel) => {
|
|
17016
|
+
if (process.env.TRADEJS_BACKTEST_WEB_JOB === "1") return;
|
|
17017
|
+
const researchStudy = process.env.TRADEJS_RESEARCH_STUDY?.trim();
|
|
17018
|
+
const linkedStudy = researchStudy && RESEARCH_STUDY.test(researchStudy) ? researchStudy : void 0;
|
|
17019
|
+
if (researchStudy && !linkedStudy) {
|
|
17020
|
+
import_logger.logger.warn(
|
|
17021
|
+
"invalid TRADEJS_RESEARCH_STUDY; expected Strategy/YYYY-MM-DD-slug"
|
|
17022
|
+
);
|
|
17023
|
+
}
|
|
17024
|
+
const { testSuite } = manifest;
|
|
17025
|
+
const firstTest = testSuite[0];
|
|
17026
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
17027
|
+
const run = {
|
|
17028
|
+
id: manifest.runId,
|
|
17029
|
+
...linkedStudy && { researchStudy: linkedStudy },
|
|
17030
|
+
userName: manifest.userName,
|
|
17031
|
+
strategyName: firstTest.strategyName,
|
|
17032
|
+
configId: manifest.config,
|
|
17033
|
+
connector: manifest.connectorName,
|
|
17034
|
+
interval: manifest.interval,
|
|
17035
|
+
startTime: manifest.window.start,
|
|
17036
|
+
endTime: manifest.window.end,
|
|
17037
|
+
symbols: [...new Set(testSuite.map((test) => test.symbol))],
|
|
17038
|
+
settings: {
|
|
17039
|
+
...manifest.flags,
|
|
17040
|
+
parallel,
|
|
17041
|
+
...firstTest.executionCosts && {
|
|
17042
|
+
executionCosts: JSON.stringify(firstTest.executionCosts)
|
|
17043
|
+
}
|
|
17044
|
+
},
|
|
17045
|
+
parameters: summarizeBacktestParameters(testSuite),
|
|
17046
|
+
status: "running",
|
|
17047
|
+
completed: initialCompleted,
|
|
17048
|
+
total: testSuite.length,
|
|
17049
|
+
startedAt,
|
|
17050
|
+
updatedAt: startedAt
|
|
17051
|
+
};
|
|
17052
|
+
const save = async (expire) => {
|
|
17053
|
+
run.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
17054
|
+
try {
|
|
17055
|
+
await import_redis7.cliBacktestRunStorage.put(run, expire);
|
|
17056
|
+
} catch (error) {
|
|
17057
|
+
import_logger.logger.warn("failed to publish CLI backtest progress: %s", String(error));
|
|
17058
|
+
}
|
|
17059
|
+
};
|
|
17060
|
+
await save(ACTIVE_TTL_SECONDS);
|
|
17061
|
+
let pending;
|
|
17062
|
+
const timer = setInterval(() => {
|
|
17063
|
+
pending ??= save(ACTIVE_TTL_SECONDS).finally(() => {
|
|
17064
|
+
pending = void 0;
|
|
17065
|
+
});
|
|
17066
|
+
}, HEARTBEAT_MS).unref();
|
|
17067
|
+
return {
|
|
17068
|
+
progress: (completed) => {
|
|
17069
|
+
run.completed = completed;
|
|
17070
|
+
},
|
|
17071
|
+
finish: async (status) => {
|
|
17072
|
+
clearInterval(timer);
|
|
17073
|
+
await pending;
|
|
17074
|
+
run.status = status;
|
|
17075
|
+
await save(linkedStudy ? LINKED_RUN_TTL_SECONDS : import_constants9.TTL_1H);
|
|
17076
|
+
}
|
|
17077
|
+
};
|
|
17078
|
+
};
|
|
17079
|
+
}
|
|
17080
|
+
});
|
|
17081
|
+
|
|
16958
17082
|
// src/scripts/backtest.ts
|
|
16959
17083
|
var backtest_exports = {};
|
|
16960
17084
|
__export(backtest_exports, {
|
|
16961
|
-
BACKTEST_PRELOAD_DAYS: () =>
|
|
17085
|
+
BACKTEST_PRELOAD_DAYS: () => import_constants10.BACKTEST_PRELOAD_DAYS,
|
|
16962
17086
|
backtest: () => backtest,
|
|
16963
17087
|
chunkTestSuiteBySymbol: () => chunkTestSuiteBySymbol,
|
|
16964
17088
|
interval: () => interval,
|
|
@@ -16983,7 +17107,7 @@ __export(backtest_exports, {
|
|
|
16983
17107
|
toStrategyConfigGrid: () => toStrategyConfigGrid,
|
|
16984
17108
|
userName: () => userName
|
|
16985
17109
|
});
|
|
16986
|
-
var import_fs2, import_path6, import_chalk15, import_backtest4, import_grid, import_data,
|
|
17110
|
+
var import_fs2, import_path6, import_chalk15, import_backtest4, import_grid, import_data, import_redis8, import_constants10, toPersistedBacktestResultEntry, toPersistedBacktestResultEntries, resolveRenderableStat, toFiniteNumber2, toReportRow, collectReportRows, escapeMdCell, formatMoney, formatPercent2, formatRatio4, createMarkdownTable, renderReportRowsTable, safeFileToken, isStrategyConfigGrid, loadBacktestConfig, hasSingleSymbol, writeBacktestMarkdownReport, finishBacktest, restoreCompletedBacktestResults, loadBacktestRunForContinue, prepareContinuedBacktestMarketContext, runBacktestSuite, backtest, main8;
|
|
16987
17111
|
var init_backtest = __esm({
|
|
16988
17112
|
"src/scripts/backtest.ts"() {
|
|
16989
17113
|
"use strict";
|
|
@@ -16993,12 +17117,13 @@ var init_backtest = __esm({
|
|
|
16993
17117
|
import_backtest4 = require("@tradejs/core/backtest");
|
|
16994
17118
|
import_grid = require("@tradejs/core/grid");
|
|
16995
17119
|
import_data = require("@tradejs/core/data");
|
|
16996
|
-
|
|
16997
|
-
|
|
17120
|
+
import_redis8 = require("@tradejs/infra/redis");
|
|
17121
|
+
import_constants10 = require("@tradejs/core/constants");
|
|
16998
17122
|
init_runnerCore();
|
|
16999
17123
|
init_cliConfig();
|
|
17000
17124
|
init_runState();
|
|
17001
17125
|
init_checkpoint();
|
|
17126
|
+
init_observeRun();
|
|
17002
17127
|
init_marketContextPrepare();
|
|
17003
17128
|
if (process.argv.some(
|
|
17004
17129
|
(arg) => arg === "--live" || String(arg).startsWith("--live=")
|
|
@@ -17134,8 +17259,8 @@ var init_backtest = __esm({
|
|
|
17134
17259
|
if (!strategyName) {
|
|
17135
17260
|
throw new Error("Strategy name not found");
|
|
17136
17261
|
}
|
|
17137
|
-
const backtestConfig = await (0,
|
|
17138
|
-
|
|
17262
|
+
const backtestConfig = await (0, import_redis8.getData)(
|
|
17263
|
+
import_redis8.redisKeys.backtestConfig(userName, flags5.config),
|
|
17139
17264
|
null
|
|
17140
17265
|
);
|
|
17141
17266
|
if (!backtestConfig) {
|
|
@@ -17282,8 +17407,8 @@ var init_backtest = __esm({
|
|
|
17282
17407
|
console.log(import_chalk15.default.gray(`full report: ${markdownReportPath}`));
|
|
17283
17408
|
console.log("");
|
|
17284
17409
|
if (!isFastMode || flags5.persistResults) {
|
|
17285
|
-
await (0,
|
|
17286
|
-
|
|
17410
|
+
await (0, import_redis8.setData)(
|
|
17411
|
+
import_redis8.redisKeys.backtestResults(userName, flags5.config, timestamp),
|
|
17287
17412
|
{
|
|
17288
17413
|
config: flags5.config,
|
|
17289
17414
|
mode: "config",
|
|
@@ -17303,11 +17428,10 @@ var init_backtest = __esm({
|
|
|
17303
17428
|
errorTests: errorTests2
|
|
17304
17429
|
},
|
|
17305
17430
|
{
|
|
17306
|
-
expire:
|
|
17431
|
+
expire: import_constants10.TTL_1M
|
|
17307
17432
|
}
|
|
17308
17433
|
);
|
|
17309
17434
|
}
|
|
17310
|
-
process.exit();
|
|
17311
17435
|
};
|
|
17312
17436
|
restoreCompletedBacktestResults = (completed) => {
|
|
17313
17437
|
for (const { result } of completed) {
|
|
@@ -17388,6 +17512,56 @@ var init_backtest = __esm({
|
|
|
17388
17512
|
log: (message) => console.log(import_chalk15.default.gray(message))
|
|
17389
17513
|
});
|
|
17390
17514
|
};
|
|
17515
|
+
runBacktestSuite = async (manifest, testSuite, initialCompletedTests = 0) => {
|
|
17516
|
+
const observation = await observeBacktestRun(
|
|
17517
|
+
manifest,
|
|
17518
|
+
initialCompletedTests,
|
|
17519
|
+
effectiveParallel
|
|
17520
|
+
);
|
|
17521
|
+
try {
|
|
17522
|
+
await executeTestSuite({
|
|
17523
|
+
testSuite,
|
|
17524
|
+
window: manifest.window,
|
|
17525
|
+
preloadStart: manifest.preloadStart,
|
|
17526
|
+
backtestRunId: manifest.runId,
|
|
17527
|
+
initialCompletedTests,
|
|
17528
|
+
totalTests: manifest.testSuite.length,
|
|
17529
|
+
onProgress: observation?.progress,
|
|
17530
|
+
onIncomplete: async () => {
|
|
17531
|
+
await observation?.finish("failed");
|
|
17532
|
+
await markBacktestRunStatus({ run: manifest, status: "interrupted" });
|
|
17533
|
+
process.exit(1);
|
|
17534
|
+
},
|
|
17535
|
+
onResult: async (result) => {
|
|
17536
|
+
await saveBacktestCheckpointResult({
|
|
17537
|
+
result,
|
|
17538
|
+
runId: manifest.runId,
|
|
17539
|
+
userName
|
|
17540
|
+
});
|
|
17541
|
+
trackTopResult(result);
|
|
17542
|
+
updateBestTickerResult(result);
|
|
17543
|
+
},
|
|
17544
|
+
onInterrupt: async () => {
|
|
17545
|
+
await observation?.finish("cancelled");
|
|
17546
|
+
await markBacktestRunStatus({ run: manifest, status: "interrupted" });
|
|
17547
|
+
},
|
|
17548
|
+
onFinish: async () => {
|
|
17549
|
+
try {
|
|
17550
|
+
await markBacktestRunStatus({ run: manifest, status: "completed" });
|
|
17551
|
+
await finishBacktest(manifest.testSuite);
|
|
17552
|
+
await observation?.finish("completed");
|
|
17553
|
+
process.exit();
|
|
17554
|
+
} catch (error) {
|
|
17555
|
+
await observation?.finish("failed");
|
|
17556
|
+
throw error;
|
|
17557
|
+
}
|
|
17558
|
+
}
|
|
17559
|
+
});
|
|
17560
|
+
} catch (error) {
|
|
17561
|
+
await observation?.finish("failed");
|
|
17562
|
+
throw error;
|
|
17563
|
+
}
|
|
17564
|
+
};
|
|
17391
17565
|
backtest = async () => {
|
|
17392
17566
|
resetRunState();
|
|
17393
17567
|
const config2 = await loadBacktestConfig();
|
|
@@ -17402,33 +17576,10 @@ var init_backtest = __esm({
|
|
|
17402
17576
|
if (!remainingSuite.length) {
|
|
17403
17577
|
await markBacktestRunStatus({ run: manifest2, status: "completed" });
|
|
17404
17578
|
await finishBacktest(manifest2.testSuite);
|
|
17405
|
-
|
|
17579
|
+
process.exit();
|
|
17406
17580
|
}
|
|
17407
17581
|
await prepareContinuedBacktestMarketContext({ manifest: manifest2, remainingSuite });
|
|
17408
|
-
await
|
|
17409
|
-
testSuite: remainingSuite,
|
|
17410
|
-
window: manifest2.window,
|
|
17411
|
-
preloadStart: manifest2.preloadStart,
|
|
17412
|
-
backtestRunId: manifest2.runId,
|
|
17413
|
-
initialCompletedTests: completed.length,
|
|
17414
|
-
totalTests: manifest2.testSuite.length,
|
|
17415
|
-
onResult: async (result) => {
|
|
17416
|
-
await saveBacktestCheckpointResult({
|
|
17417
|
-
result,
|
|
17418
|
-
runId: manifest2.runId,
|
|
17419
|
-
userName
|
|
17420
|
-
});
|
|
17421
|
-
trackTopResult(result);
|
|
17422
|
-
updateBestTickerResult(result);
|
|
17423
|
-
},
|
|
17424
|
-
onInterrupt: async () => {
|
|
17425
|
-
await markBacktestRunStatus({ run: manifest2, status: "interrupted" });
|
|
17426
|
-
},
|
|
17427
|
-
onFinish: async () => {
|
|
17428
|
-
await markBacktestRunStatus({ run: manifest2, status: "completed" });
|
|
17429
|
-
await finishBacktest(manifest2.testSuite);
|
|
17430
|
-
}
|
|
17431
|
-
});
|
|
17582
|
+
await runBacktestSuite(manifest2, remainingSuite, completed.length);
|
|
17432
17583
|
return;
|
|
17433
17584
|
}
|
|
17434
17585
|
const preparedRun = await prepareRunEnvironment2(config2.strategyName);
|
|
@@ -17489,28 +17640,7 @@ var init_backtest = __esm({
|
|
|
17489
17640
|
testSuite
|
|
17490
17641
|
});
|
|
17491
17642
|
console.log(import_chalk15.default.gray(`backtest run id: ${manifest.runId}`));
|
|
17492
|
-
await
|
|
17493
|
-
testSuite,
|
|
17494
|
-
window: preparedRun.window,
|
|
17495
|
-
preloadStart: preparedRun.preloadStart,
|
|
17496
|
-
backtestRunId: manifest.runId,
|
|
17497
|
-
onResult: async (result) => {
|
|
17498
|
-
await saveBacktestCheckpointResult({
|
|
17499
|
-
result,
|
|
17500
|
-
runId: manifest.runId,
|
|
17501
|
-
userName
|
|
17502
|
-
});
|
|
17503
|
-
trackTopResult(result);
|
|
17504
|
-
updateBestTickerResult(result);
|
|
17505
|
-
},
|
|
17506
|
-
onInterrupt: async () => {
|
|
17507
|
-
await markBacktestRunStatus({ run: manifest, status: "interrupted" });
|
|
17508
|
-
},
|
|
17509
|
-
onFinish: async () => {
|
|
17510
|
-
await markBacktestRunStatus({ run: manifest, status: "completed" });
|
|
17511
|
-
await finishBacktest(testSuite);
|
|
17512
|
-
}
|
|
17513
|
-
});
|
|
17643
|
+
await runBacktestSuite(manifest, testSuite);
|
|
17514
17644
|
};
|
|
17515
17645
|
main8 = backtest;
|
|
17516
17646
|
}
|
|
@@ -18461,11 +18591,11 @@ var init_memoryProfile = __esm({
|
|
|
18461
18591
|
});
|
|
18462
18592
|
|
|
18463
18593
|
// src/lib/replay/portfolioReplayConnector.ts
|
|
18464
|
-
var
|
|
18594
|
+
var import_constants11, import_math, import_trade, UNKNOWN_STRATEGY, getStrategyName, getPositionPnlSnapshot, createPortfolioReplayConnector;
|
|
18465
18595
|
var init_portfolioReplayConnector = __esm({
|
|
18466
18596
|
"src/lib/replay/portfolioReplayConnector.ts"() {
|
|
18467
18597
|
"use strict";
|
|
18468
|
-
|
|
18598
|
+
import_constants11 = require("@tradejs/core/constants");
|
|
18469
18599
|
import_math = require("@tradejs/core/math");
|
|
18470
18600
|
import_trade = require("@tradejs/core/trade");
|
|
18471
18601
|
init_support2();
|
|
@@ -18493,7 +18623,7 @@ var init_portfolioReplayConnector = __esm({
|
|
|
18493
18623
|
};
|
|
18494
18624
|
createPortfolioReplayConnector = (connector, observeEquity = false) => {
|
|
18495
18625
|
let state = {};
|
|
18496
|
-
let amount =
|
|
18626
|
+
let amount = import_constants11.INITIAL_BACKTEST_AMOUNT;
|
|
18497
18627
|
let executionTimestamp = null;
|
|
18498
18628
|
const positionsBySymbol = /* @__PURE__ */ new Map();
|
|
18499
18629
|
const currentPriceBySymbol = /* @__PURE__ */ new Map();
|
|
@@ -18559,7 +18689,7 @@ var init_portfolioReplayConnector = __esm({
|
|
|
18559
18689
|
price,
|
|
18560
18690
|
qty
|
|
18561
18691
|
}) => {
|
|
18562
|
-
const fee = price * qty *
|
|
18692
|
+
const fee = price * qty * import_constants11.FEE_PERCENT;
|
|
18563
18693
|
return {
|
|
18564
18694
|
fee,
|
|
18565
18695
|
profit: grossProfit - fee
|
|
@@ -18926,7 +19056,7 @@ var init_portfolioReplayConnector = __esm({
|
|
|
18926
19056
|
},
|
|
18927
19057
|
getMarkedEquity: () => {
|
|
18928
19058
|
if (!equityMarks) return null;
|
|
18929
|
-
let equity = amount -
|
|
19059
|
+
let equity = amount - import_constants11.INITIAL_BACKTEST_AMOUNT;
|
|
18930
19060
|
for (const { position } of positionsBySymbol.values()) {
|
|
18931
19061
|
const mark = equityMarks.get(position.symbol);
|
|
18932
19062
|
if (mark == null || !Number.isFinite(mark)) return null;
|
|
@@ -19328,12 +19458,12 @@ var init_historicalSignalsReplayExecution = __esm({
|
|
|
19328
19458
|
});
|
|
19329
19459
|
|
|
19330
19460
|
// src/lib/replay/historicalSignalsReplayResults.ts
|
|
19331
|
-
var import_backtest5,
|
|
19461
|
+
var import_backtest5, import_constants12, emptyStat, positionLogForStats, calculateReplayStat, byTimestamp, byPositionClose, collectHistoricalReplayResult, compactHistoricalReplayResultForPortfolio, mergeHistoricalReplayResults;
|
|
19332
19462
|
var init_historicalSignalsReplayResults = __esm({
|
|
19333
19463
|
"src/lib/replay/historicalSignalsReplayResults.ts"() {
|
|
19334
19464
|
"use strict";
|
|
19335
19465
|
import_backtest5 = require("@tradejs/core/backtest");
|
|
19336
|
-
|
|
19466
|
+
import_constants12 = require("@tradejs/core/constants");
|
|
19337
19467
|
emptyStat = () => ({
|
|
19338
19468
|
orders: 0,
|
|
19339
19469
|
wins: 0,
|
|
@@ -19342,7 +19472,7 @@ var init_historicalSignalsReplayResults = __esm({
|
|
|
19342
19472
|
amount: 0
|
|
19343
19473
|
});
|
|
19344
19474
|
positionLogForStats = (positionLog) => {
|
|
19345
|
-
let amount =
|
|
19475
|
+
let amount = import_constants12.INITIAL_BACKTEST_AMOUNT;
|
|
19346
19476
|
return [...positionLog].sort(
|
|
19347
19477
|
(left, right) => left.close.timestamp - right.close.timestamp || left.open.timestamp - right.open.timestamp
|
|
19348
19478
|
).map((position) => {
|
|
@@ -19436,7 +19566,7 @@ var init_historicalSignalsReplayResults = __esm({
|
|
|
19436
19566
|
});
|
|
19437
19567
|
|
|
19438
19568
|
// src/lib/replay/historicalSignalsReplay.ts
|
|
19439
|
-
var import_chalk17, import_progress8, import_node_path12, import_node_module2, import_strategies5, import_time4,
|
|
19569
|
+
var import_chalk17, import_progress8, import_node_path12, import_node_module2, import_strategies5, import_time4, import_logger2, import_redis9, import_connectors6, import_cli5, import_strategies6, import_runtimeStrategies3, projectReplayCacheReleasers, getProjectReplayCacheReleasers, releaseReplayCacheCopies, loadRuntimeStrategies, loadReferenceConnector, buildAfterSignalsContext, getConnectorName, loadHistoricalReplayReferences, runHistoricalSignalsReplay;
|
|
19440
19570
|
var init_historicalSignalsReplay = __esm({
|
|
19441
19571
|
"src/lib/replay/historicalSignalsReplay.ts"() {
|
|
19442
19572
|
"use strict";
|
|
@@ -19447,8 +19577,8 @@ var init_historicalSignalsReplay = __esm({
|
|
|
19447
19577
|
import_node_module2 = require("module");
|
|
19448
19578
|
import_strategies5 = require("@tradejs/core/strategies");
|
|
19449
19579
|
import_time4 = require("@tradejs/core/time");
|
|
19450
|
-
|
|
19451
|
-
|
|
19580
|
+
import_logger2 = require("@tradejs/infra/logger");
|
|
19581
|
+
import_redis9 = require("@tradejs/infra/redis");
|
|
19452
19582
|
import_connectors6 = require("@tradejs/node/connectors");
|
|
19453
19583
|
import_cli5 = require("@tradejs/node/cli");
|
|
19454
19584
|
import_strategies6 = require("@tradejs/node/strategies");
|
|
@@ -19515,8 +19645,8 @@ var init_historicalSignalsReplay = __esm({
|
|
|
19515
19645
|
`Runtime evidence package mismatch for ${strategyName}: expected=${strategyPackage}@${strategyPackageVersion}/@tradejs/node@${runtimePackageVersion}, installed=${installed.strategyPackage ?? "missing"}@${installed.strategyPackageVersion ?? "missing"}/@tradejs/node@${installed.runtimePackageVersion ?? "missing"}`
|
|
19516
19646
|
);
|
|
19517
19647
|
}
|
|
19518
|
-
const strategyResults = await (0,
|
|
19519
|
-
|
|
19648
|
+
const strategyResults = await (0, import_redis9.getData)(
|
|
19649
|
+
import_redis9.redisKeys.strategyResults(replayUserName, strategyName),
|
|
19520
19650
|
{}
|
|
19521
19651
|
);
|
|
19522
19652
|
return {
|
|
@@ -19721,7 +19851,7 @@ var init_historicalSignalsReplay = __esm({
|
|
|
19721
19851
|
releaseHistoricalReplayPlan(plan);
|
|
19722
19852
|
memory?.("execution:released");
|
|
19723
19853
|
const artifacts = replayConnector.getReplayArtifacts();
|
|
19724
|
-
|
|
19854
|
+
import_logger2.logger.info(
|
|
19725
19855
|
import_chalk17.default.gray(
|
|
19726
19856
|
`signals replay historical cycles: ${plan.orderedTimestamps.length} (aborted=${execution.abortedCycles}) done in ${((Date.now() - startedAt) / 1e3).toFixed(1)}s`
|
|
19727
19857
|
)
|
|
@@ -20297,11 +20427,11 @@ var init_paritySummary = __esm({
|
|
|
20297
20427
|
});
|
|
20298
20428
|
|
|
20299
20429
|
// src/lib/runtimeSignalsStorage.ts
|
|
20300
|
-
var
|
|
20430
|
+
var import_constants13, import_data4, import_time5, appendRuntimeSignalEvaluationRun, SECONDS_PER_DAY, RUNTIME_SIGNAL_RETENTION_DAYS_ENV, DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS, RUNTIME_LINEAGE_SCOPE_RETENTION_TTL_SECONDS, parsePositiveNumber, getRuntimeSignalRetentionTtlSeconds, toRuntimeSignalBucketRef, shouldStoreRuntimeSignalDiagnostics, toStoredRuntimeSignal, isRuntimeSignalBucketRef, normalizeRuntimeSignalSkipReason, buildStatsReasonField, buildRuntimeSignalStatsIncrements, shouldStoreDetailedRuntimeSignalEvaluation, toCount, parseRuntimeSignalStatsBucket;
|
|
20301
20431
|
var init_runtimeSignalsStorage = __esm({
|
|
20302
20432
|
"src/lib/runtimeSignalsStorage.ts"() {
|
|
20303
20433
|
"use strict";
|
|
20304
|
-
|
|
20434
|
+
import_constants13 = require("@tradejs/core/constants");
|
|
20305
20435
|
import_data4 = require("@tradejs/core/data");
|
|
20306
20436
|
import_time5 = require("@tradejs/core/time");
|
|
20307
20437
|
appendRuntimeSignalEvaluationRun = (runs = [], evaluation) => {
|
|
@@ -20336,8 +20466,8 @@ var init_runtimeSignalsStorage = __esm({
|
|
|
20336
20466
|
};
|
|
20337
20467
|
SECONDS_PER_DAY = 86400;
|
|
20338
20468
|
RUNTIME_SIGNAL_RETENTION_DAYS_ENV = "RUNTIME_SIGNAL_RETENTION_DAYS";
|
|
20339
|
-
DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS =
|
|
20340
|
-
RUNTIME_LINEAGE_SCOPE_RETENTION_TTL_SECONDS =
|
|
20469
|
+
DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS = import_constants13.TTL_3D;
|
|
20470
|
+
RUNTIME_LINEAGE_SCOPE_RETENTION_TTL_SECONDS = import_constants13.TTL_1M;
|
|
20341
20471
|
parsePositiveNumber = (value) => {
|
|
20342
20472
|
if (value == null || value === "") {
|
|
20343
20473
|
return null;
|
|
@@ -20470,11 +20600,11 @@ var init_runtimeSignalsStorage = __esm({
|
|
|
20470
20600
|
});
|
|
20471
20601
|
|
|
20472
20602
|
// src/lib/runtimeSignalsLoader.ts
|
|
20473
|
-
var
|
|
20603
|
+
var import_redis10, isSignalRecord, isRuntimeSignalEvaluationRecord, sortByTimestamp, filterBucketKeysByWindow, loadRuntimeSignals, loadRuntimeSignalEvaluations, loadRuntimeLineageScopes, parseBucketKey, loadRuntimeSignalEvaluationStatsBuckets;
|
|
20474
20604
|
var init_runtimeSignalsLoader = __esm({
|
|
20475
20605
|
"src/lib/runtimeSignalsLoader.ts"() {
|
|
20476
20606
|
"use strict";
|
|
20477
|
-
|
|
20607
|
+
import_redis10 = require("@tradejs/infra/redis");
|
|
20478
20608
|
init_runtimeSignalsStorage();
|
|
20479
20609
|
isSignalRecord = (value) => {
|
|
20480
20610
|
if (!value || typeof value !== "object") {
|
|
@@ -20512,14 +20642,14 @@ var init_runtimeSignalsLoader = __esm({
|
|
|
20512
20642
|
startTime,
|
|
20513
20643
|
endTime
|
|
20514
20644
|
} = {}) => {
|
|
20515
|
-
const bucketPrefix =
|
|
20645
|
+
const bucketPrefix = import_redis10.redisKeys.runtimeSignalBuckets(userName3);
|
|
20516
20646
|
const bucketKeys = filterBucketKeysByWindow(
|
|
20517
|
-
await (0,
|
|
20647
|
+
await (0, import_redis10.getKeys)(bucketPrefix),
|
|
20518
20648
|
bucketPrefix,
|
|
20519
20649
|
startTime,
|
|
20520
20650
|
endTime
|
|
20521
20651
|
);
|
|
20522
|
-
const refs = (await Promise.all(bucketKeys.map((key2) => (0,
|
|
20652
|
+
const refs = (await Promise.all(bucketKeys.map((key2) => (0, import_redis10.getHashJsonValues)(key2)))).flat().filter(isRuntimeSignalBucketRef);
|
|
20523
20653
|
const seen = /* @__PURE__ */ new Set();
|
|
20524
20654
|
const payloads = await Promise.all(
|
|
20525
20655
|
refs.map(async (ref) => {
|
|
@@ -20528,8 +20658,8 @@ var init_runtimeSignalsLoader = __esm({
|
|
|
20528
20658
|
return null;
|
|
20529
20659
|
}
|
|
20530
20660
|
seen.add(dedupeKey);
|
|
20531
|
-
const signal = await (0,
|
|
20532
|
-
|
|
20661
|
+
const signal = await (0, import_redis10.getData)(
|
|
20662
|
+
import_redis10.redisKeys.storeSignal(ref.symbol, ref.signalId),
|
|
20533
20663
|
null
|
|
20534
20664
|
);
|
|
20535
20665
|
return isSignalRecord(signal) ? signal : null;
|
|
@@ -20541,14 +20671,14 @@ var init_runtimeSignalsLoader = __esm({
|
|
|
20541
20671
|
startTime,
|
|
20542
20672
|
endTime
|
|
20543
20673
|
} = {}) => {
|
|
20544
|
-
const bucketPrefix =
|
|
20674
|
+
const bucketPrefix = import_redis10.redisKeys.runtimeSignalEvaluationBuckets(userName3);
|
|
20545
20675
|
const bucketKeys = filterBucketKeysByWindow(
|
|
20546
|
-
await (0,
|
|
20676
|
+
await (0, import_redis10.getKeys)(bucketPrefix),
|
|
20547
20677
|
bucketPrefix,
|
|
20548
20678
|
startTime,
|
|
20549
20679
|
endTime
|
|
20550
20680
|
);
|
|
20551
|
-
const evaluations = (await Promise.all(bucketKeys.map((key2) => (0,
|
|
20681
|
+
const evaluations = (await Promise.all(bucketKeys.map((key2) => (0, import_redis10.getHashJsonValues)(key2)))).flat().filter(isRuntimeSignalEvaluationRecord);
|
|
20552
20682
|
const deduped = /* @__PURE__ */ new Map();
|
|
20553
20683
|
for (const evaluation of evaluations) {
|
|
20554
20684
|
deduped.set(evaluation.evaluationId, evaluation);
|
|
@@ -20561,8 +20691,8 @@ var init_runtimeSignalsLoader = __esm({
|
|
|
20561
20691
|
}) => {
|
|
20562
20692
|
const records = (await Promise.all(
|
|
20563
20693
|
(0, import_time5.getRuntimeStorageDayKeys)(startTime, endTime).map(
|
|
20564
|
-
(dayKey) => (0,
|
|
20565
|
-
|
|
20694
|
+
(dayKey) => (0, import_redis10.getHashJsonValues)(
|
|
20695
|
+
import_redis10.redisKeys.runtimeLineageScopeBucket(userName3, dayKey)
|
|
20566
20696
|
)
|
|
20567
20697
|
)
|
|
20568
20698
|
)).flat().filter(
|
|
@@ -20591,8 +20721,8 @@ var init_runtimeSignalsLoader = __esm({
|
|
|
20591
20721
|
};
|
|
20592
20722
|
};
|
|
20593
20723
|
loadRuntimeSignalEvaluationStatsBuckets = async (userName3) => {
|
|
20594
|
-
const prefix =
|
|
20595
|
-
const keys = await (0,
|
|
20724
|
+
const prefix = import_redis10.redisKeys.runtimeSignalEvaluationStatsBuckets(userName3);
|
|
20725
|
+
const keys = await (0, import_redis10.getKeys)(prefix);
|
|
20596
20726
|
const entries = await Promise.all(
|
|
20597
20727
|
keys.map(async (key2) => {
|
|
20598
20728
|
const parsedKey = parseBucketKey(prefix, key2);
|
|
@@ -20602,7 +20732,7 @@ var init_runtimeSignalsLoader = __esm({
|
|
|
20602
20732
|
return {
|
|
20603
20733
|
key: key2,
|
|
20604
20734
|
...parsedKey,
|
|
20605
|
-
stats: parseRuntimeSignalStatsBucket(await (0,
|
|
20735
|
+
stats: parseRuntimeSignalStatsBucket(await (0, import_redis10.getHashData)(key2))
|
|
20606
20736
|
};
|
|
20607
20737
|
})
|
|
20608
20738
|
);
|
|
@@ -20612,13 +20742,13 @@ var init_runtimeSignalsLoader = __esm({
|
|
|
20612
20742
|
});
|
|
20613
20743
|
|
|
20614
20744
|
// src/lib/runtimeTradeSync.ts
|
|
20615
|
-
var
|
|
20745
|
+
var import_constants14, import_time6, import_redis11, CLOSED_PNL_LIMIT, CLOSED_PNL_RECONCILIATION_LOOKBACK_MS, EXCHANGE_HISTORY_MAX_RANGE_MS, isRuntimeTradeSyncFallbackClose, splitExchangeHistoryTimeRange, formatRuntimeTradeSyncError, loadClosedPnlRows, consumeClosedPnlMatch, isRuntimeTradeInConnectorScope, syncRuntimeTrades;
|
|
20616
20746
|
var init_runtimeTradeSync = __esm({
|
|
20617
20747
|
"src/lib/runtimeTradeSync.ts"() {
|
|
20618
20748
|
"use strict";
|
|
20619
|
-
|
|
20749
|
+
import_constants14 = require("@tradejs/core/constants");
|
|
20620
20750
|
import_time6 = require("@tradejs/core/time");
|
|
20621
|
-
|
|
20751
|
+
import_redis11 = require("@tradejs/infra/redis");
|
|
20622
20752
|
CLOSED_PNL_LIMIT = 100;
|
|
20623
20753
|
CLOSED_PNL_RECONCILIATION_LOOKBACK_MS = 24 * 60 * 60 * 1e3;
|
|
20624
20754
|
EXCHANGE_HISTORY_MAX_RANGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
@@ -20751,7 +20881,7 @@ var init_runtimeTradeSync = __esm({
|
|
|
20751
20881
|
const activeTradeKeys = [
|
|
20752
20882
|
...new Set(
|
|
20753
20883
|
trades.filter((trade) => isRuntimeTradeInConnectorScope(trade, connector)).map(
|
|
20754
|
-
(trade) =>
|
|
20884
|
+
(trade) => import_redis11.redisKeys.runtimeActiveTrade(
|
|
20755
20885
|
userName3,
|
|
20756
20886
|
trade.symbol,
|
|
20757
20887
|
trade.deploymentId ?? trade.accountId
|
|
@@ -20761,7 +20891,7 @@ var init_runtimeTradeSync = __esm({
|
|
|
20761
20891
|
];
|
|
20762
20892
|
await Promise.all(
|
|
20763
20893
|
activeTradeKeys.map(async (key2) => {
|
|
20764
|
-
const activeRef = await (0,
|
|
20894
|
+
const activeRef = await (0, import_redis11.getData)(key2, null);
|
|
20765
20895
|
activeOrderIdByKey.set(
|
|
20766
20896
|
key2,
|
|
20767
20897
|
typeof activeRef?.orderId === "string" ? activeRef.orderId : null
|
|
@@ -20790,7 +20920,7 @@ var init_runtimeTradeSync = __esm({
|
|
|
20790
20920
|
syncedTrades.push(trade);
|
|
20791
20921
|
continue;
|
|
20792
20922
|
}
|
|
20793
|
-
const activeTradeKey =
|
|
20923
|
+
const activeTradeKey = import_redis11.redisKeys.runtimeActiveTrade(
|
|
20794
20924
|
userName3,
|
|
20795
20925
|
trade.symbol,
|
|
20796
20926
|
trade.deploymentId ?? trade.accountId
|
|
@@ -20814,15 +20944,15 @@ var init_runtimeTradeSync = __esm({
|
|
|
20814
20944
|
currentPnl: openPosition.unrealizedPnl,
|
|
20815
20945
|
lastSyncedAt: endTime
|
|
20816
20946
|
};
|
|
20817
|
-
await (0,
|
|
20818
|
-
|
|
20947
|
+
await (0, import_redis11.setData)(
|
|
20948
|
+
import_redis11.redisKeys.runtimeTrade(userName3, trade.orderId),
|
|
20819
20949
|
nextTrade2,
|
|
20820
20950
|
{
|
|
20821
20951
|
expire: 0
|
|
20822
20952
|
}
|
|
20823
20953
|
);
|
|
20824
|
-
await (0,
|
|
20825
|
-
|
|
20954
|
+
await (0, import_redis11.setHashJsonField)(
|
|
20955
|
+
import_redis11.redisKeys.runtimeTradeBucket(
|
|
20826
20956
|
userName3,
|
|
20827
20957
|
(0, import_time6.getRuntimeStorageDayKey)(trade.entryTimestamp)
|
|
20828
20958
|
),
|
|
@@ -20856,28 +20986,28 @@ var init_runtimeTradeSync = __esm({
|
|
|
20856
20986
|
lastSyncedAt: endTime
|
|
20857
20987
|
};
|
|
20858
20988
|
await Promise.all([
|
|
20859
|
-
(0,
|
|
20860
|
-
expire:
|
|
20989
|
+
(0, import_redis11.setData)(import_redis11.redisKeys.runtimeTrade(userName3, trade.orderId), nextTrade, {
|
|
20990
|
+
expire: import_constants14.TTL_1M
|
|
20861
20991
|
}),
|
|
20862
|
-
(0,
|
|
20863
|
-
|
|
20992
|
+
(0, import_redis11.setHashJsonField)(
|
|
20993
|
+
import_redis11.redisKeys.runtimeTradeBucket(
|
|
20864
20994
|
userName3,
|
|
20865
20995
|
(0, import_time6.getRuntimeStorageDayKey)(trade.entryTimestamp)
|
|
20866
20996
|
),
|
|
20867
20997
|
trade.orderId,
|
|
20868
20998
|
nextTrade,
|
|
20869
|
-
{ expire:
|
|
20999
|
+
{ expire: import_constants14.TTL_1M }
|
|
20870
21000
|
),
|
|
20871
|
-
(0,
|
|
20872
|
-
|
|
21001
|
+
(0, import_redis11.setHashJsonField)(
|
|
21002
|
+
import_redis11.redisKeys.runtimeClosedTradeBucket(
|
|
20873
21003
|
userName3,
|
|
20874
21004
|
(0, import_time6.getRuntimeStorageDayKey)(nextTrade.exitTimestamp)
|
|
20875
21005
|
),
|
|
20876
21006
|
trade.orderId,
|
|
20877
21007
|
nextTrade,
|
|
20878
|
-
{ expire:
|
|
21008
|
+
{ expire: import_constants14.TTL_1M }
|
|
20879
21009
|
),
|
|
20880
|
-
...isCurrentActiveTrade ? [(0,
|
|
21010
|
+
...isCurrentActiveTrade ? [(0, import_redis11.delKey)(activeTradeKey)] : []
|
|
20881
21011
|
]);
|
|
20882
21012
|
syncedTrades.push(nextTrade);
|
|
20883
21013
|
}
|
|
@@ -24412,16 +24542,16 @@ ${comparison.limitations.join(" ")}
|
|
|
24412
24542
|
});
|
|
24413
24543
|
|
|
24414
24544
|
// src/scripts/replayRunner.ts
|
|
24415
|
-
var import_chalk21,
|
|
24545
|
+
var import_chalk21, import_constants15, import_data6, import_time8, import_redis12, import_candles2, import_runtimeStrategies4, import_strategies7, prepareReplayBinanceMarketContext, replayMarketContextInterval, cachedTickerSymbols, finishReplay, replayBacktest;
|
|
24416
24546
|
var init_replayRunner = __esm({
|
|
24417
24547
|
"src/scripts/replayRunner.ts"() {
|
|
24418
24548
|
"use strict";
|
|
24419
24549
|
init_historicalSignalsReplayPreparation();
|
|
24420
24550
|
import_chalk21 = __toESM(require("chalk"));
|
|
24421
|
-
|
|
24551
|
+
import_constants15 = require("@tradejs/core/constants");
|
|
24422
24552
|
import_data6 = require("@tradejs/core/data");
|
|
24423
24553
|
import_time8 = require("@tradejs/core/time");
|
|
24424
|
-
|
|
24554
|
+
import_redis12 = require("@tradejs/infra/redis");
|
|
24425
24555
|
import_candles2 = require("@tradejs/infra/timescale/candles");
|
|
24426
24556
|
import_runtimeStrategies4 = require("@tradejs/node/runtimeStrategies");
|
|
24427
24557
|
import_strategies7 = require("@tradejs/node/strategies");
|
|
@@ -24475,12 +24605,12 @@ var init_replayRunner = __esm({
|
|
|
24475
24605
|
...connectorName.toLowerCase() === "bybit" ? ["ByBit"] : []
|
|
24476
24606
|
];
|
|
24477
24607
|
const keys = connectorNames.flatMap((name) => [
|
|
24478
|
-
|
|
24479
|
-
|
|
24480
|
-
|
|
24608
|
+
import_redis12.redisKeys.tickerUniverse(replayUserName, name, universe, accountId),
|
|
24609
|
+
import_redis12.redisKeys.tickerUniverse(replayUserName, name, universe, "default"),
|
|
24610
|
+
import_redis12.redisKeys.tickerUniverse(replayUserName, name)
|
|
24481
24611
|
]);
|
|
24482
24612
|
for (const key2 of [...new Set(keys)]) {
|
|
24483
|
-
const cached = await (0,
|
|
24613
|
+
const cached = await (0, import_redis12.getData)(key2, null);
|
|
24484
24614
|
const symbols = (cached?.tickers ?? []).map(
|
|
24485
24615
|
(ticker) => String(ticker.symbol ?? "").trim().toUpperCase()
|
|
24486
24616
|
).filter(Boolean);
|
|
@@ -24522,7 +24652,7 @@ var init_replayRunner = __esm({
|
|
|
24522
24652
|
replayResult.orderLog[replayResult.orderLog.length - 1]?.timestamp ?? finishedAt.getTime()
|
|
24523
24653
|
)}`
|
|
24524
24654
|
}) : null;
|
|
24525
|
-
const replayKey =
|
|
24655
|
+
const replayKey = import_redis12.redisKeys.backtestResults(
|
|
24526
24656
|
replayUserName,
|
|
24527
24657
|
REPLAY_RESULTS_CONFIG,
|
|
24528
24658
|
timestamp
|
|
@@ -24556,7 +24686,7 @@ var init_replayRunner = __esm({
|
|
|
24556
24686
|
console.log(import_chalk21.default.green(`Portfolio report: ${portfolioReport.html}`));
|
|
24557
24687
|
console.log(import_chalk21.default.green(`Portfolio report JSON: ${portfolioReport.json}`));
|
|
24558
24688
|
}
|
|
24559
|
-
await (0,
|
|
24689
|
+
await (0, import_redis12.setData)(
|
|
24560
24690
|
replayKey,
|
|
24561
24691
|
{
|
|
24562
24692
|
config: REPLAY_RESULTS_CONFIG,
|
|
@@ -24583,17 +24713,17 @@ var init_replayRunner = __esm({
|
|
|
24583
24713
|
...portfolioReport ? { portfolioReport } : {}
|
|
24584
24714
|
},
|
|
24585
24715
|
{
|
|
24586
|
-
expire:
|
|
24716
|
+
expire: import_constants15.TTL_1M
|
|
24587
24717
|
}
|
|
24588
24718
|
);
|
|
24589
24719
|
if (replayChartSnapshot) {
|
|
24590
24720
|
await Promise.all(
|
|
24591
24721
|
replayChartSnapshot.strategies.map(
|
|
24592
|
-
(card) => (0,
|
|
24593
|
-
|
|
24722
|
+
(card) => (0, import_redis12.setData)(
|
|
24723
|
+
import_redis12.redisKeys.strategyChartCard(replayUserName, "replay", card.cardId),
|
|
24594
24724
|
card,
|
|
24595
24725
|
{
|
|
24596
|
-
expire:
|
|
24726
|
+
expire: import_constants15.TTL_1M
|
|
24597
24727
|
}
|
|
24598
24728
|
)
|
|
24599
24729
|
)
|
|
@@ -25045,7 +25175,7 @@ var init_binanceMarketIngest = __esm({
|
|
|
25045
25175
|
import_client4 = require("@tradejs/infra/timescale/client");
|
|
25046
25176
|
init_binanceMarketData();
|
|
25047
25177
|
import_args9.default.example(
|
|
25048
|
-
"yarn cli:node8g binance:market-ingest --all --symbols BTCUSDT,ETHUSDT --days 0.05 --interval
|
|
25178
|
+
"yarn cli:node8g binance:market-ingest --all --symbols BTCUSDT,ETHUSDT --days 0.05 --interval 15m --write",
|
|
25049
25179
|
"Ingest Binance public market breadth and historical aggTrades buckets"
|
|
25050
25180
|
);
|
|
25051
25181
|
import_args9.default.option(
|
|
@@ -25053,7 +25183,7 @@ var init_binanceMarketIngest = __esm({
|
|
|
25053
25183
|
"Comma-separated target symbols",
|
|
25054
25184
|
"BTCUSDT,ETHUSDT"
|
|
25055
25185
|
);
|
|
25056
|
-
import_args9.default.option(["i", "interval"], "Aggregation interval:
|
|
25186
|
+
import_args9.default.option(["i", "interval"], "Aggregation interval: 5m,15m,1h", "15m");
|
|
25057
25187
|
import_args9.default.option(["d", "days"], "Lookback window in days", "1");
|
|
25058
25188
|
import_args9.default.option(["h", "hours"], "Lookback window in hours; overrides --days");
|
|
25059
25189
|
import_args9.default.option(["a", "aggTrades"], "Fetch and bucket Binance aggTrades");
|
|
@@ -25087,7 +25217,6 @@ var init_binanceMarketIngest = __esm({
|
|
|
25087
25217
|
};
|
|
25088
25218
|
sleep4 = (ms) => ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();
|
|
25089
25219
|
intervalToConnectorInterval = (interval4) => {
|
|
25090
|
-
if (interval4 === "1m") return "1";
|
|
25091
25220
|
if (interval4 === "5m") return "5";
|
|
25092
25221
|
if (interval4 === "15m") return "15";
|
|
25093
25222
|
return "60";
|
|
@@ -25143,6 +25272,7 @@ var init_binanceMarketIngest = __esm({
|
|
|
25143
25272
|
main11 = async () => {
|
|
25144
25273
|
const symbols = normalizeBinanceSymbols(flags7.symbols);
|
|
25145
25274
|
const interval4 = normalizeMarketFeatureInterval(flags7.interval);
|
|
25275
|
+
if (interval4 === "1m") throw new Error("Use interval 5m, 15m, or 1h");
|
|
25146
25276
|
const hours = flags7.hours == null ? null : asFloat2(flags7.hours, 0);
|
|
25147
25277
|
const days = hours != null && hours > 0 ? hours / 24 : asFloat2(flags7.days, 1);
|
|
25148
25278
|
const breadthUniverses = (0, import_strategies9.getBinanceBreadthUniverses)();
|
|
@@ -25256,7 +25386,7 @@ var init_binanceMarketIngest = __esm({
|
|
|
25256
25386
|
});
|
|
25257
25387
|
|
|
25258
25388
|
// src/lib/runBot.ts
|
|
25259
|
-
var import_lodash, import_connectors10, import_data7, import_strategies10, import_async3,
|
|
25389
|
+
var import_lodash, import_connectors10, import_data7, import_strategies10, import_async3, import_constants16, import_time9, import_logger3, import_redis13, projectRoot4, runBot;
|
|
25260
25390
|
var init_runBot = __esm({
|
|
25261
25391
|
"src/lib/runBot.ts"() {
|
|
25262
25392
|
"use strict";
|
|
@@ -25265,33 +25395,33 @@ var init_runBot = __esm({
|
|
|
25265
25395
|
import_data7 = require("@tradejs/core/data");
|
|
25266
25396
|
import_strategies10 = require("@tradejs/node/strategies");
|
|
25267
25397
|
import_async3 = require("@tradejs/core/async");
|
|
25268
|
-
|
|
25398
|
+
import_constants16 = require("@tradejs/core/constants");
|
|
25269
25399
|
import_time9 = require("@tradejs/core/time");
|
|
25270
|
-
|
|
25271
|
-
|
|
25400
|
+
import_logger3 = require("@tradejs/infra/logger");
|
|
25401
|
+
import_redis13 = require("@tradejs/infra/redis");
|
|
25272
25402
|
projectRoot4 = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
25273
25403
|
runBot = async () => {
|
|
25274
25404
|
const botResults = [];
|
|
25275
|
-
const preloadStart = (0, import_time9.getTimestamp)(
|
|
25405
|
+
const preloadStart = (0, import_time9.getTimestamp)(import_constants16.BOT_PRELOAD_DAYS);
|
|
25276
25406
|
const end = (0, import_time9.getTimestamp)();
|
|
25277
|
-
const keys = await (0,
|
|
25407
|
+
const keys = await (0, import_redis13.getKeys)(import_redis13.redisKeys.botsPrefix());
|
|
25278
25408
|
const botKeys = keys.filter((key2) => key2.endsWith(":bots"));
|
|
25279
25409
|
await (0, import_async3.delay)(5e3);
|
|
25280
|
-
|
|
25410
|
+
import_logger3.logger.log("info", "files count: %s", botKeys.length);
|
|
25281
25411
|
for await (const key2 of botKeys) {
|
|
25282
25412
|
const userName3 = key2.split(":")[1];
|
|
25283
|
-
|
|
25284
|
-
const botConfig = await (0,
|
|
25413
|
+
import_logger3.logger.log("info", "user: %s", userName3);
|
|
25414
|
+
const botConfig = await (0, import_redis13.getData)(import_redis13.redisKeys.bots(userName3));
|
|
25285
25415
|
if (import_lodash.default.isEmpty(botConfig)) {
|
|
25286
|
-
|
|
25416
|
+
import_logger3.logger.log("error", "botConfig is empty: %s", userName3);
|
|
25287
25417
|
continue;
|
|
25288
25418
|
}
|
|
25289
|
-
|
|
25419
|
+
import_logger3.logger.log("info", "bots count: %s", botConfig.length);
|
|
25290
25420
|
for await (const bot of botConfig) {
|
|
25291
25421
|
const { symbol, strategyName, strategyConfig, connectorName, disabled } = bot;
|
|
25292
|
-
|
|
25422
|
+
import_logger3.logger.log("info", "bot %s", symbol);
|
|
25293
25423
|
if (disabled) {
|
|
25294
|
-
|
|
25424
|
+
import_logger3.logger.log("error", "bot %s disabled", symbol);
|
|
25295
25425
|
continue;
|
|
25296
25426
|
}
|
|
25297
25427
|
try {
|
|
@@ -25371,7 +25501,7 @@ var init_runBot = __esm({
|
|
|
25371
25501
|
btcCoinbaseData,
|
|
25372
25502
|
connector
|
|
25373
25503
|
});
|
|
25374
|
-
|
|
25504
|
+
import_logger3.logger.log("info", "strategy created");
|
|
25375
25505
|
if (!candle || !btcCandle) {
|
|
25376
25506
|
throw new Error("Candle is empty");
|
|
25377
25507
|
}
|
|
@@ -25381,11 +25511,11 @@ var init_runBot = __esm({
|
|
|
25381
25511
|
status: JSON.stringify(status)
|
|
25382
25512
|
});
|
|
25383
25513
|
} catch (err) {
|
|
25384
|
-
|
|
25514
|
+
import_logger3.logger.log("error", "bot %s error: %s", bot.symbol, (0, import_data7.toJson)(err, false));
|
|
25385
25515
|
}
|
|
25386
25516
|
}
|
|
25387
25517
|
}
|
|
25388
|
-
|
|
25518
|
+
import_logger3.logger.log("info", "botResults: %s", (0, import_data7.toJson)(botResults, true));
|
|
25389
25519
|
return botResults;
|
|
25390
25520
|
};
|
|
25391
25521
|
}
|
|
@@ -25809,7 +25939,7 @@ var cleanTests_exports = {};
|
|
|
25809
25939
|
__export(cleanTests_exports, {
|
|
25810
25940
|
main: () => main16
|
|
25811
25941
|
});
|
|
25812
|
-
var import_args13, import_promises20, import_path7, import_chalk25, import_cli8, import_backtestArtifacts2,
|
|
25942
|
+
var import_args13, import_promises20, import_path7, import_chalk25, import_cli8, import_backtestArtifacts2, import_redis14, flags11, extractUsers, getUsersToClean, cleanUserTests, main16;
|
|
25813
25943
|
var init_cleanTests = __esm({
|
|
25814
25944
|
"src/scripts/cleanTests.ts"() {
|
|
25815
25945
|
"use strict";
|
|
@@ -25819,7 +25949,7 @@ var init_cleanTests = __esm({
|
|
|
25819
25949
|
import_chalk25 = __toESM(require("chalk"));
|
|
25820
25950
|
import_cli8 = require("@tradejs/node/cli");
|
|
25821
25951
|
import_backtestArtifacts2 = require("@tradejs/infra/backtestArtifacts");
|
|
25822
|
-
|
|
25952
|
+
import_redis14 = require("@tradejs/infra/redis");
|
|
25823
25953
|
import_args13.default.option(["U", "user"], "Clean tests for user", "");
|
|
25824
25954
|
import_args13.default.option(["C", "cache"], "Clean only cache keys", false);
|
|
25825
25955
|
flags11 = import_args13.default.parse(process.argv);
|
|
@@ -25845,7 +25975,7 @@ var init_cleanTests = __esm({
|
|
|
25845
25975
|
if (userName3) {
|
|
25846
25976
|
return [userName3];
|
|
25847
25977
|
}
|
|
25848
|
-
const keys = await (0,
|
|
25978
|
+
const keys = await (0, import_redis14.getKeys)(import_redis14.redisKeys.users());
|
|
25849
25979
|
return extractUsers(keys);
|
|
25850
25980
|
};
|
|
25851
25981
|
cleanUserTests = async (userName3) => {
|
|
@@ -25934,7 +26064,7 @@ var continuity_exports = {};
|
|
|
25934
26064
|
__export(continuity_exports, {
|
|
25935
26065
|
main: () => main17
|
|
25936
26066
|
});
|
|
25937
|
-
var import_args14, import_progress9, import_chalk26, import_connectors11, import_cli9,
|
|
26067
|
+
var import_args14, import_progress9, import_chalk26, import_connectors11, import_cli9, import_constants17, import_time10, import_logger4, import_candles3, import_client5, flags12, interval2, intervalKey, projectRoot5, parseProviders, runContinuity, main17;
|
|
25938
26068
|
var init_continuity2 = __esm({
|
|
25939
26069
|
"src/scripts/continuity.ts"() {
|
|
25940
26070
|
"use strict";
|
|
@@ -25943,9 +26073,9 @@ var init_continuity2 = __esm({
|
|
|
25943
26073
|
import_chalk26 = __toESM(require("chalk"));
|
|
25944
26074
|
import_connectors11 = require("@tradejs/node/connectors");
|
|
25945
26075
|
import_cli9 = require("@tradejs/node/cli");
|
|
25946
|
-
|
|
26076
|
+
import_constants17 = require("@tradejs/core/constants");
|
|
25947
26077
|
import_time10 = require("@tradejs/core/time");
|
|
25948
|
-
|
|
26078
|
+
import_logger4 = require("@tradejs/infra/logger");
|
|
25949
26079
|
import_candles3 = require("@tradejs/infra/timescale/candles");
|
|
25950
26080
|
import_client5 = require("@tradejs/infra/timescale/client");
|
|
25951
26081
|
init_continuity();
|
|
@@ -25972,7 +26102,7 @@ var init_continuity2 = __esm({
|
|
|
25972
26102
|
const uniqueSelected = [...new Set(selected)];
|
|
25973
26103
|
const invalid = uniqueSelected.filter((item) => !allProviders.includes(item));
|
|
25974
26104
|
if (invalid.length) {
|
|
25975
|
-
|
|
26105
|
+
import_logger4.logger.error(
|
|
25976
26106
|
"Unknown provider(s): %s. Supported: %s",
|
|
25977
26107
|
invalid.join(", "),
|
|
25978
26108
|
allProviders.join(", ")
|
|
@@ -26007,7 +26137,7 @@ var init_continuity2 = __esm({
|
|
|
26007
26137
|
let broken = 0;
|
|
26008
26138
|
let fixed = 0;
|
|
26009
26139
|
const expectedMs = interval2 * 60 * 1e3;
|
|
26010
|
-
|
|
26140
|
+
import_logger4.logger.info(
|
|
26011
26141
|
import_chalk26.default.yellow(`continuity ${connectorName}:${universe}: ${tickers.length}`)
|
|
26012
26142
|
);
|
|
26013
26143
|
for await (const symbol of tickers) {
|
|
@@ -26021,7 +26151,7 @@ var init_continuity2 = __esm({
|
|
|
26021
26151
|
let gap = findRepairableContinuityGap(data, expectedMs, universe);
|
|
26022
26152
|
if (gap) {
|
|
26023
26153
|
broken++;
|
|
26024
|
-
|
|
26154
|
+
import_logger4.logger.warn(
|
|
26025
26155
|
"[%s:%s] gap %s %s: %s -> %s (%ss)",
|
|
26026
26156
|
provider,
|
|
26027
26157
|
universe,
|
|
@@ -26050,7 +26180,7 @@ var init_continuity2 = __esm({
|
|
|
26050
26180
|
symbol: import_chalk26.default.gray(symbol)
|
|
26051
26181
|
});
|
|
26052
26182
|
}
|
|
26053
|
-
|
|
26183
|
+
import_logger4.logger.info(
|
|
26054
26184
|
import_chalk26.default.yellow(
|
|
26055
26185
|
`[${provider}:${universe}] broken: ${broken}/${tickers.length}, fixed: ${fixed}`
|
|
26056
26186
|
)
|
|
@@ -26058,17 +26188,17 @@ var init_continuity2 = __esm({
|
|
|
26058
26188
|
};
|
|
26059
26189
|
main17 = async () => {
|
|
26060
26190
|
if (!Number.isFinite(interval2) || interval2 <= 0) {
|
|
26061
|
-
|
|
26191
|
+
import_logger4.logger.error("Invalid timeframe: %s", flags12.timeframe);
|
|
26062
26192
|
process.exit(1);
|
|
26063
26193
|
}
|
|
26064
26194
|
await (0, import_client5.waitForDbReady)();
|
|
26065
|
-
const reloadStart = (0, import_time10.getTimestamp)(
|
|
26195
|
+
const reloadStart = (0, import_time10.getTimestamp)(import_constants17.PRELOAD_DAYS);
|
|
26066
26196
|
const reloadEnd = (0, import_time10.getTimestamp)();
|
|
26067
26197
|
let requestedUniverse;
|
|
26068
26198
|
try {
|
|
26069
26199
|
requestedUniverse = parseContinuityUniverse(flags12.universe);
|
|
26070
26200
|
} catch (error) {
|
|
26071
|
-
|
|
26201
|
+
import_logger4.logger.error(error.message);
|
|
26072
26202
|
process.exit(1);
|
|
26073
26203
|
}
|
|
26074
26204
|
const providerIds = await parseProviders(flags12.provider);
|
|
@@ -26079,7 +26209,7 @@ var init_continuity2 = __esm({
|
|
|
26079
26209
|
projectRoot5
|
|
26080
26210
|
);
|
|
26081
26211
|
if (!connectorName) {
|
|
26082
|
-
|
|
26212
|
+
import_logger4.logger.warn(
|
|
26083
26213
|
'Skip provider "%s": connector mapping is missing',
|
|
26084
26214
|
providerId
|
|
26085
26215
|
);
|
|
@@ -26090,7 +26220,7 @@ var init_continuity2 = __esm({
|
|
|
26090
26220
|
projectRoot5
|
|
26091
26221
|
);
|
|
26092
26222
|
if (!creator) {
|
|
26093
|
-
|
|
26223
|
+
import_logger4.logger.warn(
|
|
26094
26224
|
'Skip provider "%s": connector "%s" is not registered',
|
|
26095
26225
|
providerId,
|
|
26096
26226
|
connectorName
|
|
@@ -26106,7 +26236,7 @@ var init_continuity2 = __esm({
|
|
|
26106
26236
|
);
|
|
26107
26237
|
const activeProviders = providers.filter(Boolean);
|
|
26108
26238
|
if (!activeProviders.length) {
|
|
26109
|
-
|
|
26239
|
+
import_logger4.logger.error("No connector providers available");
|
|
26110
26240
|
process.exit(1);
|
|
26111
26241
|
}
|
|
26112
26242
|
for await (const provider of activeProviders) {
|
|
@@ -26118,7 +26248,7 @@ var init_continuity2 = __esm({
|
|
|
26118
26248
|
defaultConnector.capabilities.supportedUniverses
|
|
26119
26249
|
);
|
|
26120
26250
|
if (!universes.length) {
|
|
26121
|
-
|
|
26251
|
+
import_logger4.logger.warn(
|
|
26122
26252
|
'Skip provider "%s": universe "%s" is not supported',
|
|
26123
26253
|
provider.id,
|
|
26124
26254
|
requestedUniverse
|
|
@@ -26844,11 +26974,11 @@ var init_doctor = __esm({
|
|
|
26844
26974
|
});
|
|
26845
26975
|
|
|
26846
26976
|
// src/lib/executionCalibration.ts
|
|
26847
|
-
var
|
|
26977
|
+
var import_constants18, import_data8, import_trade3, roundMetric, asRecord3, asArray, finiteNumber2, finiteString, finiteDirection, metricValues, quantile2, summarizeNumbers, getIntervalMs, getSignalKey, addSignalToMap, getRuntimePayload, extractRuntimeTradeRows, normalizeReplayMatch, extractReplayMatches, buildReplayMatchMaps, getSignalCandles, adverseEntryBps, feeBps, latencyDelta, resolveTelemetryQuality, finiteTelemetryQuality, countBy, toLatencyBucket, toSpreadBucket, buildSample, buildReplayOnlySample, hasTelemetry, hasFullTelemetry, buildGroupSummary, groupSamples, positiveMetricValues, buildRecommendation, buildExecutionCalibrationReport;
|
|
26848
26978
|
var init_executionCalibration = __esm({
|
|
26849
26979
|
"src/lib/executionCalibration.ts"() {
|
|
26850
26980
|
"use strict";
|
|
26851
|
-
|
|
26981
|
+
import_constants18 = require("@tradejs/core/constants");
|
|
26852
26982
|
import_data8 = require("@tradejs/core/data");
|
|
26853
26983
|
import_trade3 = require("@tradejs/core/trade");
|
|
26854
26984
|
roundMetric = (value, decimals = 6) => typeof value === "number" && Number.isFinite(value) ? Number(value.toFixed(decimals)) : null;
|
|
@@ -27233,7 +27363,7 @@ var init_executionCalibration = __esm({
|
|
|
27233
27363
|
actualPrice: fillAvgPrice
|
|
27234
27364
|
});
|
|
27235
27365
|
const currentModelEntrySlippageBps = signalToFillAdverseBps != null ? roundMetric(
|
|
27236
|
-
|
|
27366
|
+
import_constants18.BACKTEST_BASE_SLIPPAGE_BPS + (spreadBps ?? 0) * import_constants18.BACKTEST_SPREAD_SLIPPAGE_MULTIPLIER + import_constants18.BACKTEST_MARKET_IMPACT_BPS + (currentDelayRiskBps ?? 0)
|
|
27237
27367
|
) : null;
|
|
27238
27368
|
const residualVsCurrentModelBps = signalToFillAdverseBps != null && currentModelEntrySlippageBps != null ? roundMetric(signalToFillAdverseBps - currentModelEntrySlippageBps) : null;
|
|
27239
27369
|
return {
|
|
@@ -27428,7 +27558,7 @@ var init_executionCalibration = __esm({
|
|
|
27428
27558
|
}
|
|
27429
27559
|
return Math.max(
|
|
27430
27560
|
0,
|
|
27431
|
-
sample.arrivalToFillAdverseBps - (sample.spreadBps ?? 0) * (spreadMultiplier ??
|
|
27561
|
+
sample.arrivalToFillAdverseBps - (sample.spreadBps ?? 0) * (spreadMultiplier ?? import_constants18.BACKTEST_SPREAD_SLIPPAGE_MULTIPLIER)
|
|
27432
27562
|
);
|
|
27433
27563
|
}).filter(
|
|
27434
27564
|
(value) => value != null && Number.isFinite(value)
|
|
@@ -27491,9 +27621,9 @@ var init_executionCalibration = __esm({
|
|
|
27491
27621
|
generatedAt: nowMs,
|
|
27492
27622
|
sources: sourcePaths,
|
|
27493
27623
|
currentModel: {
|
|
27494
|
-
baseSlippageBps:
|
|
27495
|
-
spreadMultiplier:
|
|
27496
|
-
marketImpactBps:
|
|
27624
|
+
baseSlippageBps: import_constants18.BACKTEST_BASE_SLIPPAGE_BPS,
|
|
27625
|
+
spreadMultiplier: import_constants18.BACKTEST_SPREAD_SLIPPAGE_MULTIPLIER,
|
|
27626
|
+
marketImpactBps: import_constants18.BACKTEST_MARKET_IMPACT_BPS
|
|
27497
27627
|
},
|
|
27498
27628
|
counts: {
|
|
27499
27629
|
runtimeTrades: runtimeRows.length,
|
|
@@ -27840,13 +27970,13 @@ var migration_exports = {};
|
|
|
27840
27970
|
__export(migration_exports, {
|
|
27841
27971
|
main: () => main26
|
|
27842
27972
|
});
|
|
27843
|
-
var import_progress11, import_chalk36,
|
|
27973
|
+
var import_progress11, import_chalk36, import_logger5, import_files, import_candles4, DIR, re, BATCH, projectRoot7, migrateFile, main26;
|
|
27844
27974
|
var init_migration = __esm({
|
|
27845
27975
|
"src/scripts/migration.ts"() {
|
|
27846
27976
|
"use strict";
|
|
27847
27977
|
import_progress11 = __toESM(require("progress"));
|
|
27848
27978
|
import_chalk36 = __toESM(require("chalk"));
|
|
27849
|
-
|
|
27979
|
+
import_logger5 = require("@tradejs/infra/logger");
|
|
27850
27980
|
import_files = require("@tradejs/infra/files");
|
|
27851
27981
|
import_candles4 = require("@tradejs/infra/timescale/candles");
|
|
27852
27982
|
DIR = "data/history";
|
|
@@ -27882,7 +28012,7 @@ var init_migration = __esm({
|
|
|
27882
28012
|
try {
|
|
27883
28013
|
await migrateFile(file);
|
|
27884
28014
|
} catch (e) {
|
|
27885
|
-
|
|
28015
|
+
import_logger5.logger.error("Failed: %s %s", file, e);
|
|
27886
28016
|
} finally {
|
|
27887
28017
|
bar.tick(1, {
|
|
27888
28018
|
file: import_chalk36.default.gray(file)
|
|
@@ -27895,12 +28025,12 @@ var init_migration = __esm({
|
|
|
27895
28025
|
});
|
|
27896
28026
|
|
|
27897
28027
|
// src/lib/marketData/klineEvents.ts
|
|
27898
|
-
var import_ioredis2,
|
|
28028
|
+
var import_ioredis2, import_redis15, MARKET_KLINE_CHANNEL, positiveInt2, redisOptions, buildMarketKlineTopic, publishMarketKlineEvent, createMarketKlineSubscriber, parseMarketKlineEvent;
|
|
27899
28029
|
var init_klineEvents = __esm({
|
|
27900
28030
|
"src/lib/marketData/klineEvents.ts"() {
|
|
27901
28031
|
"use strict";
|
|
27902
28032
|
import_ioredis2 = __toESM(require("ioredis"));
|
|
27903
|
-
|
|
28033
|
+
import_redis15 = require("@tradejs/infra/redis");
|
|
27904
28034
|
MARKET_KLINE_CHANNEL = "tradejs:market:kline";
|
|
27905
28035
|
positiveInt2 = (value, fallback) => {
|
|
27906
28036
|
const parsed = Number(value);
|
|
@@ -27919,7 +28049,7 @@ var init_klineEvents = __esm({
|
|
|
27919
28049
|
event.symbol.trim().toUpperCase(),
|
|
27920
28050
|
event.interval
|
|
27921
28051
|
].join(":");
|
|
27922
|
-
publishMarketKlineEvent = (event) => (0,
|
|
28052
|
+
publishMarketKlineEvent = (event) => (0, import_redis15.publishData)(MARKET_KLINE_CHANNEL, event);
|
|
27923
28053
|
createMarketKlineSubscriber = () => new import_ioredis2.default(redisOptions());
|
|
27924
28054
|
parseMarketKlineEvent = (payload) => {
|
|
27925
28055
|
try {
|
|
@@ -27936,13 +28066,13 @@ var init_klineEvents = __esm({
|
|
|
27936
28066
|
});
|
|
27937
28067
|
|
|
27938
28068
|
// src/lib/marketData/marketWsGateway.ts
|
|
27939
|
-
var import_http, import_ws,
|
|
28069
|
+
var import_http, import_ws, import_logger6, MAX_TOPICS_PER_CLIENT, TOPIC_PATTERN, parseSubscriptionCommand, applySubscriptionCommand, startMarketWsGateway;
|
|
27940
28070
|
var init_marketWsGateway = __esm({
|
|
27941
28071
|
"src/lib/marketData/marketWsGateway.ts"() {
|
|
27942
28072
|
"use strict";
|
|
27943
28073
|
import_http = __toESM(require("http"));
|
|
27944
28074
|
import_ws = require("ws");
|
|
27945
|
-
|
|
28075
|
+
import_logger6 = require("@tradejs/infra/logger");
|
|
27946
28076
|
init_klineEvents();
|
|
27947
28077
|
MAX_TOPICS_PER_CLIENT = 20;
|
|
27948
28078
|
TOPIC_PATTERN = /^(bybit|binance|coinbase):(crypto|tradfi):[A-Z0-9._-]+:(1|3|5|15|30|60|120|240|360|720|D|W|M)$/;
|
|
@@ -28056,7 +28186,7 @@ var init_marketWsGateway = __esm({
|
|
|
28056
28186
|
resolve();
|
|
28057
28187
|
});
|
|
28058
28188
|
});
|
|
28059
|
-
|
|
28189
|
+
import_logger6.logger.info("market websocket gateway listening on %s:%s", host, port);
|
|
28060
28190
|
return {
|
|
28061
28191
|
close: async () => {
|
|
28062
28192
|
clearInterval(heartbeat);
|
|
@@ -28198,14 +28328,14 @@ var mcpWorker_exports = {};
|
|
|
28198
28328
|
__export(mcpWorker_exports, {
|
|
28199
28329
|
main: () => main28
|
|
28200
28330
|
});
|
|
28201
|
-
var import_node_child_process4, import_node_crypto15, import_promises23,
|
|
28331
|
+
var import_node_child_process4, import_node_crypto15, import_promises23, import_redis16, import_mcp, pause, leaseKey, LEASE_SECONDS, JOB_TIMEOUT_MS, main28;
|
|
28202
28332
|
var init_mcpWorker = __esm({
|
|
28203
28333
|
"src/scripts/mcpWorker.ts"() {
|
|
28204
28334
|
"use strict";
|
|
28205
28335
|
import_node_child_process4 = require("child_process");
|
|
28206
28336
|
import_node_crypto15 = require("crypto");
|
|
28207
28337
|
import_promises23 = require("fs/promises");
|
|
28208
|
-
|
|
28338
|
+
import_redis16 = require("@tradejs/infra/redis");
|
|
28209
28339
|
import_mcp = require("@tradejs/node/mcp");
|
|
28210
28340
|
init_mcpReplayProcess();
|
|
28211
28341
|
pause = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -28214,7 +28344,7 @@ var init_mcpWorker = __esm({
|
|
|
28214
28344
|
JOB_TIMEOUT_MS = 60 * 60 * 1e3;
|
|
28215
28345
|
main28 = async (options = {}) => {
|
|
28216
28346
|
const owner = (0, import_node_crypto15.randomUUID)();
|
|
28217
|
-
if (!await
|
|
28347
|
+
if (!await import_redis16.mcpStorage.put(leaseKey, owner, LEASE_SECONDS, true))
|
|
28218
28348
|
throw new Error("Another MCP worker owns this storage");
|
|
28219
28349
|
let stopping = false;
|
|
28220
28350
|
let child;
|
|
@@ -28278,10 +28408,10 @@ var init_mcpWorker = __esm({
|
|
|
28278
28408
|
if (renewing || leaseLost) return;
|
|
28279
28409
|
renewing = true;
|
|
28280
28410
|
try {
|
|
28281
|
-
if (!await
|
|
28411
|
+
if (!await import_redis16.mcpStorage.compare(leaseKey, owner, owner, LEASE_SECONDS))
|
|
28282
28412
|
throw new Error("Worker lease lost");
|
|
28283
28413
|
await updateReplayReady();
|
|
28284
|
-
await
|
|
28414
|
+
await import_redis16.mcpStorage.put("worker:heartbeat", heartbeatValue(), LEASE_SECONDS);
|
|
28285
28415
|
} catch {
|
|
28286
28416
|
leaseLost = true;
|
|
28287
28417
|
stop();
|
|
@@ -28292,15 +28422,15 @@ var init_mcpWorker = __esm({
|
|
|
28292
28422
|
try {
|
|
28293
28423
|
manifestHash = await (0, import_mcp.mcpPackageManifestHash)();
|
|
28294
28424
|
await updateReplayReady();
|
|
28295
|
-
await
|
|
28425
|
+
await import_redis16.mcpStorage.put("worker:heartbeat", heartbeatValue(), LEASE_SECONDS);
|
|
28296
28426
|
let cursor = "0";
|
|
28297
28427
|
do {
|
|
28298
|
-
const page = await
|
|
28428
|
+
const page = await import_redis16.mcpStorage.scan("jobs:", cursor);
|
|
28299
28429
|
cursor = page.cursor;
|
|
28300
28430
|
for (const key2 of page.ids) {
|
|
28301
|
-
const job = await
|
|
28431
|
+
const job = await import_redis16.mcpStorage.get(key2);
|
|
28302
28432
|
if (job?.status === "running")
|
|
28303
|
-
await
|
|
28433
|
+
await import_redis16.mcpStorage.compare(
|
|
28304
28434
|
key2,
|
|
28305
28435
|
job,
|
|
28306
28436
|
{
|
|
@@ -28321,10 +28451,10 @@ var init_mcpWorker = __esm({
|
|
|
28321
28451
|
let queued;
|
|
28322
28452
|
cursor = "0";
|
|
28323
28453
|
do {
|
|
28324
|
-
const page = await
|
|
28454
|
+
const page = await import_redis16.mcpStorage.scan("jobs:", cursor);
|
|
28325
28455
|
cursor = page.cursor;
|
|
28326
28456
|
for (const key2 of page.ids) {
|
|
28327
|
-
const job = await
|
|
28457
|
+
const job = await import_redis16.mcpStorage.get(key2);
|
|
28328
28458
|
if (job && ["queued", "waiting_resources", "waiting_executor"].includes(
|
|
28329
28459
|
job.status
|
|
28330
28460
|
) && (!queued || job.createdAt < queued.createdAt))
|
|
@@ -28342,10 +28472,10 @@ var init_mcpWorker = __esm({
|
|
|
28342
28472
|
...queued.kind === "runtime-feedback-replay" ? {} : { startedAt: Date.now() },
|
|
28343
28473
|
updatedAt: Date.now()
|
|
28344
28474
|
};
|
|
28345
|
-
if (!await
|
|
28475
|
+
if (!await import_redis16.mcpStorage.compare(jobKey, queued, started, import_mcp.MCP_JOB_TTL))
|
|
28346
28476
|
continue;
|
|
28347
28477
|
if (started.kind !== "runtime-feedback-replay" && started.packageManifestSha256 !== manifestHash) {
|
|
28348
|
-
await
|
|
28478
|
+
await import_redis16.mcpStorage.compare(
|
|
28349
28479
|
jobKey,
|
|
28350
28480
|
started,
|
|
28351
28481
|
{
|
|
@@ -28360,8 +28490,8 @@ var init_mcpWorker = __esm({
|
|
|
28360
28490
|
}
|
|
28361
28491
|
await (0, import_promises23.mkdir)((0, import_mcp.mcpJobDirectory)(started), { recursive: true });
|
|
28362
28492
|
if (started.kind === "backtest")
|
|
28363
|
-
await (0,
|
|
28364
|
-
|
|
28493
|
+
await (0, import_redis16.setDataStrict)(
|
|
28494
|
+
import_redis16.redisKeys.backtestConfig(
|
|
28365
28495
|
started.userName,
|
|
28366
28496
|
String(started.request.frozenConfigId)
|
|
28367
28497
|
),
|
|
@@ -28410,7 +28540,7 @@ var init_mcpWorker = __esm({
|
|
|
28410
28540
|
env: process.env
|
|
28411
28541
|
});
|
|
28412
28542
|
} catch (error) {
|
|
28413
|
-
await
|
|
28543
|
+
await import_redis16.mcpStorage.compare(
|
|
28414
28544
|
jobKey,
|
|
28415
28545
|
started,
|
|
28416
28546
|
{
|
|
@@ -28448,7 +28578,7 @@ var init_mcpWorker = __esm({
|
|
|
28448
28578
|
let killAt;
|
|
28449
28579
|
const monitor = setInterval(async () => {
|
|
28450
28580
|
try {
|
|
28451
|
-
const latest = await
|
|
28581
|
+
const latest = await import_redis16.mcpStorage.get(jobKey);
|
|
28452
28582
|
if (!latest || latest.cancelRequested || stopping || timedOut) {
|
|
28453
28583
|
killAt ??= Date.now();
|
|
28454
28584
|
signalChild(Date.now() - killAt > 8e3 ? "SIGKILL" : "SIGTERM");
|
|
@@ -28473,7 +28603,7 @@ var init_mcpWorker = __esm({
|
|
|
28473
28603
|
}
|
|
28474
28604
|
}
|
|
28475
28605
|
if (latest && !leaseLost)
|
|
28476
|
-
await
|
|
28606
|
+
await import_redis16.mcpStorage.compare(
|
|
28477
28607
|
jobKey,
|
|
28478
28608
|
latest,
|
|
28479
28609
|
{
|
|
@@ -28504,7 +28634,7 @@ var init_mcpWorker = __esm({
|
|
|
28504
28634
|
child = void 0;
|
|
28505
28635
|
if (!leaseLost) {
|
|
28506
28636
|
for (let attempt = 0; attempt < 4; attempt++) {
|
|
28507
|
-
const latest = await
|
|
28637
|
+
const latest = await import_redis16.mcpStorage.get(jobKey);
|
|
28508
28638
|
if (!latest) break;
|
|
28509
28639
|
const cancelled = latest.cancelRequested;
|
|
28510
28640
|
const next = {
|
|
@@ -28520,7 +28650,7 @@ var init_mcpWorker = __esm({
|
|
|
28520
28650
|
) || logs.at(-1) : void 0) || "Research process failed"
|
|
28521
28651
|
} : {}
|
|
28522
28652
|
};
|
|
28523
|
-
if (await
|
|
28653
|
+
if (await import_redis16.mcpStorage.compare(jobKey, latest, next, import_mcp.MCP_JOB_TTL))
|
|
28524
28654
|
break;
|
|
28525
28655
|
}
|
|
28526
28656
|
}
|
|
@@ -28530,8 +28660,8 @@ var init_mcpWorker = __esm({
|
|
|
28530
28660
|
options.signal?.removeEventListener("abort", stop);
|
|
28531
28661
|
process.removeListener("SIGINT", stop);
|
|
28532
28662
|
process.removeListener("SIGTERM", stop);
|
|
28533
|
-
if (await
|
|
28534
|
-
await
|
|
28663
|
+
if (await import_redis16.mcpStorage.release(leaseKey, owner))
|
|
28664
|
+
await import_redis16.mcpStorage.remove("worker:heartbeat");
|
|
28535
28665
|
}
|
|
28536
28666
|
if (leaseLost)
|
|
28537
28667
|
throw new Error("Worker lease lost; active computation was stopped");
|
|
@@ -30677,7 +30807,7 @@ __export(researchAuto_exports, {
|
|
|
30677
30807
|
toStrategyConfigGrid: () => toStrategyConfigGrid2,
|
|
30678
30808
|
trimTextTail: () => trimTextTail2
|
|
30679
30809
|
});
|
|
30680
|
-
var import_args25, import_chalk40, import_node_child_process5, import_promises27, import_node_os2, import_node_path20,
|
|
30810
|
+
var import_args25, import_chalk40, import_node_child_process5, import_promises27, import_node_os2, import_node_path20, import_constants19, import_ai8, import_logger7, import_redis17, import_registry4, flags23, projectRoot8, dotenvPath, getResearchAutoLockPath, readResearchAutoLock, isProcessAlive, acquireResearchAutoLock, releaseResearchAutoLock, resolvePositiveInteger, resolveHeapMbFromEnv, buildNodeOptions, RESEARCH_AUTO_PARENT_HEAP_MB, RESEARCH_AUTO_BACKTEST_PARENT_HEAP_MB, RESEARCH_AUTO_AI_TRAIN_PARENT_HEAP_MB, RESEARCH_AUTO_AGENT_PARENT_HEAP_MB, trimTextTail2, escapeHtml3, createEmptySteps, saveRun, listMergedFiles3, getBacktestResultsPrefix, listRuntimeStrategyNames, toStrategyConfigGrid2, formatMskDateTime, buildTelegramReport, runCliCommand, resolveTarget, parseJsonOutput, logResearch, executeNonBlockingStep, main35;
|
|
30681
30811
|
var init_researchAuto = __esm({
|
|
30682
30812
|
"src/scripts/researchAuto.ts"() {
|
|
30683
30813
|
"use strict";
|
|
@@ -30687,10 +30817,10 @@ var init_researchAuto = __esm({
|
|
|
30687
30817
|
import_promises27 = __toESM(require("fs/promises"));
|
|
30688
30818
|
import_node_os2 = __toESM(require("os"));
|
|
30689
30819
|
import_node_path20 = __toESM(require("path"));
|
|
30690
|
-
|
|
30820
|
+
import_constants19 = require("@tradejs/core/constants");
|
|
30691
30821
|
import_ai8 = require("@tradejs/infra/ai");
|
|
30692
|
-
|
|
30693
|
-
|
|
30822
|
+
import_logger7 = require("@tradejs/infra/logger");
|
|
30823
|
+
import_redis17 = require("@tradejs/infra/redis");
|
|
30694
30824
|
import_registry4 = require("@tradejs/node/registry");
|
|
30695
30825
|
init_runtimeRedis();
|
|
30696
30826
|
init_runtimeStrategyBacktest();
|
|
@@ -30892,11 +31022,11 @@ var init_researchAuto = __esm({
|
|
|
30892
31022
|
}
|
|
30893
31023
|
});
|
|
30894
31024
|
saveRun = async (run) => {
|
|
30895
|
-
await (0,
|
|
30896
|
-
expire:
|
|
31025
|
+
await (0, import_redis17.setData)(import_redis17.redisKeys.researchRun(run.userName, run.runId), run, {
|
|
31026
|
+
expire: import_constants19.TTL_1M
|
|
30897
31027
|
});
|
|
30898
|
-
await (0,
|
|
30899
|
-
expire:
|
|
31028
|
+
await (0, import_redis17.setData)(import_redis17.redisKeys.researchLatestRun(run.userName, run.strategy), run, {
|
|
31029
|
+
expire: import_constants19.TTL_1M
|
|
30900
31030
|
});
|
|
30901
31031
|
};
|
|
30902
31032
|
listMergedFiles3 = async (outDir, strategyName) => {
|
|
@@ -31057,13 +31187,13 @@ var init_researchAuto = __esm({
|
|
|
31057
31187
|
const emitLines = (source, text3) => {
|
|
31058
31188
|
const prefix = params.liveLogPrefix ? `[research:auto:${params.liveLogPrefix}:${source}] ` : `[research:auto:${source}] `;
|
|
31059
31189
|
for (const line of text3.split(/\r?\n/).map((value) => value.trimEnd()).filter(Boolean)) {
|
|
31060
|
-
|
|
31190
|
+
import_logger7.logger.info(import_chalk40.default.gray(`${prefix}${line}`));
|
|
31061
31191
|
}
|
|
31062
31192
|
};
|
|
31063
31193
|
if (params.heartbeatMs && params.heartbeatMs > 0) {
|
|
31064
31194
|
heartbeatTimer = setInterval(() => {
|
|
31065
31195
|
const elapsedMs = Date.now() - startedAt;
|
|
31066
|
-
|
|
31196
|
+
import_logger7.logger.info(
|
|
31067
31197
|
import_chalk40.default.gray(
|
|
31068
31198
|
`[research:auto:${params.liveLogPrefix || params.command}] still running after ${Math.round(elapsedMs / 1e3)}s`
|
|
31069
31199
|
)
|
|
@@ -31125,8 +31255,8 @@ var init_researchAuto = __esm({
|
|
|
31125
31255
|
const candidates = [];
|
|
31126
31256
|
for (const strategy of availableStrategies) {
|
|
31127
31257
|
const config2 = `${strategy}:research`;
|
|
31128
|
-
const latestRun = await (0,
|
|
31129
|
-
|
|
31258
|
+
const latestRun = await (0, import_redis17.getData)(
|
|
31259
|
+
import_redis17.redisKeys.researchLatestRun(userName3, strategy),
|
|
31130
31260
|
null
|
|
31131
31261
|
);
|
|
31132
31262
|
const lastFinishedAt = latestRun?.finishedAt ? Date.parse(latestRun.finishedAt) : 0;
|
|
@@ -31163,7 +31293,7 @@ var init_researchAuto = __esm({
|
|
|
31163
31293
|
return JSON.parse(trimmed);
|
|
31164
31294
|
};
|
|
31165
31295
|
logResearch = (message) => {
|
|
31166
|
-
|
|
31296
|
+
import_logger7.logger.info(import_chalk40.default.cyan(`[research:auto] ${message}`));
|
|
31167
31297
|
};
|
|
31168
31298
|
executeNonBlockingStep = async (run, stepName, command, commandArgs, options = {}) => {
|
|
31169
31299
|
logResearch(
|
|
@@ -31305,13 +31435,13 @@ var init_researchAuto = __esm({
|
|
|
31305
31435
|
startedAt
|
|
31306
31436
|
};
|
|
31307
31437
|
await saveRun(run);
|
|
31308
|
-
const strategyConfigKey =
|
|
31438
|
+
const strategyConfigKey = import_redis17.redisKeys.strategyConfig(
|
|
31309
31439
|
userName3,
|
|
31310
31440
|
target.strategy
|
|
31311
31441
|
);
|
|
31312
|
-
const backtestConfigKey =
|
|
31442
|
+
const backtestConfigKey = import_redis17.redisKeys.backtestConfig(userName3, target.config);
|
|
31313
31443
|
const defaults = await (0, import_registry4.getStrategyDefaults)(target.strategy, projectRoot8) || {};
|
|
31314
|
-
const userStrategyConfig = await (0,
|
|
31444
|
+
const userStrategyConfig = await (0, import_redis17.getData)(
|
|
31315
31445
|
strategyConfigKey,
|
|
31316
31446
|
{}
|
|
31317
31447
|
);
|
|
@@ -31325,7 +31455,7 @@ var init_researchAuto = __esm({
|
|
|
31325
31455
|
);
|
|
31326
31456
|
}
|
|
31327
31457
|
const backtestConfig = toStrategyConfigGrid2(strategyConfig);
|
|
31328
|
-
await (0,
|
|
31458
|
+
await (0, import_redis17.setData)(backtestConfigKey, backtestConfig, { expire: 0 });
|
|
31329
31459
|
logResearch(
|
|
31330
31460
|
`stored backtest config at ${backtestConfigKey} with ${Object.keys(strategyConfig).length} top-level fields`
|
|
31331
31461
|
);
|
|
@@ -31365,7 +31495,7 @@ var init_researchAuto = __esm({
|
|
|
31365
31495
|
`resource knobs: researchAutoHeapMb=${RESEARCH_AUTO_PARENT_HEAP_MB}, backtestParentHeapMb=${RESEARCH_AUTO_BACKTEST_PARENT_HEAP_MB}, aiTrainParentHeapMb=${RESEARCH_AUTO_AI_TRAIN_PARENT_HEAP_MB}, agentParentHeapMb=${RESEARCH_AUTO_AGENT_PARENT_HEAP_MB}, backtestWorkerHeapMb=${process.env.BACKTEST_WORKER_HEAP_MB || "auto"}, backtestMaxParallel=${process.env.BACKTEST_MAX_PARALLEL || "auto"}, klineConcurrency=${process.env.KLINE_CONCURRENCY_LIMIT || "default"}`
|
|
31366
31496
|
);
|
|
31367
31497
|
const backtestKeysBefore = new Set(
|
|
31368
|
-
await (0,
|
|
31498
|
+
await (0, import_redis17.getKeys)(getBacktestResultsPrefix(userName3, target.config))
|
|
31369
31499
|
);
|
|
31370
31500
|
const aiFilesBefore = new Set(
|
|
31371
31501
|
await listMergedFiles3(outDir, target.strategy)
|
|
@@ -31427,14 +31557,14 @@ var init_researchAuto = __esm({
|
|
|
31427
31557
|
captureMode: "full"
|
|
31428
31558
|
}
|
|
31429
31559
|
);
|
|
31430
|
-
const backtestKeysAfter = await (0,
|
|
31560
|
+
const backtestKeysAfter = await (0, import_redis17.getKeys)(
|
|
31431
31561
|
getBacktestResultsPrefix(userName3, target.config)
|
|
31432
31562
|
);
|
|
31433
31563
|
const newBacktestKeys = backtestKeysAfter.filter((key2) => !backtestKeysBefore.has(key2)).sort();
|
|
31434
31564
|
const backtestResultKey = newBacktestKeys[newBacktestKeys.length - 1] || backtestKeysAfter.sort().at(-1);
|
|
31435
31565
|
if (backtestResultKey) {
|
|
31436
31566
|
logResearch(`detected backtest result key ${backtestResultKey}`);
|
|
31437
|
-
const backtestResult = await (0,
|
|
31567
|
+
const backtestResult = await (0, import_redis17.getData)(backtestResultKey, null);
|
|
31438
31568
|
run.artifacts.backtestResultKey = backtestResultKey;
|
|
31439
31569
|
run.artifacts.backtestResult = backtestResult ? {
|
|
31440
31570
|
finishedAt: backtestResult.finishedAt,
|
|
@@ -32134,8 +32264,8 @@ var init_dataset2 = __esm({
|
|
|
32134
32264
|
for (const inputPath of variant.files) {
|
|
32135
32265
|
const filePath = import_node_path22.default.resolve(inputPath);
|
|
32136
32266
|
const input = (0, import_node_fs8.createReadStream)(filePath);
|
|
32137
|
-
const
|
|
32138
|
-
input.on("data", (chunk) =>
|
|
32267
|
+
const hash2 = (0, import_node_crypto17.createHash)("sha256");
|
|
32268
|
+
input.on("data", (chunk) => hash2.update(chunk));
|
|
32139
32269
|
const lines = import_node_readline3.default.createInterface({ input, crlfDelay: Infinity });
|
|
32140
32270
|
const fileTrades = [];
|
|
32141
32271
|
let lineNumber = 0;
|
|
@@ -32185,7 +32315,7 @@ var init_dataset2 = __esm({
|
|
|
32185
32315
|
trades.push(trade);
|
|
32186
32316
|
fileTrades.push(trade);
|
|
32187
32317
|
}
|
|
32188
|
-
const fileSha2562 =
|
|
32318
|
+
const fileSha2562 = hash2.digest("hex");
|
|
32189
32319
|
for (const trade of fileTrades) trade.sourceSha256 = fileSha2562;
|
|
32190
32320
|
sources.push({
|
|
32191
32321
|
path: filePath,
|
|
@@ -33744,55 +33874,6 @@ var init_specification = __esm({
|
|
|
33744
33874
|
}
|
|
33745
33875
|
});
|
|
33746
33876
|
|
|
33747
|
-
// src/lib/researchMetricSnapshot.ts
|
|
33748
|
-
var import_node_crypto19, import_node_zlib2, MAX_BYTES, hash2, validatePermanentResearchMetrics, encodeResearchMetricSnapshot, decodeResearchMetricSnapshot;
|
|
33749
|
-
var init_researchMetricSnapshot = __esm({
|
|
33750
|
-
"src/lib/researchMetricSnapshot.ts"() {
|
|
33751
|
-
"use strict";
|
|
33752
|
-
import_node_crypto19 = require("crypto");
|
|
33753
|
-
import_node_zlib2 = require("zlib");
|
|
33754
|
-
MAX_BYTES = 256 * 1024 * 1024;
|
|
33755
|
-
hash2 = (bytes) => (0, import_node_crypto19.createHash)("sha256").update(bytes).digest("hex");
|
|
33756
|
-
validatePermanentResearchMetrics = (value) => {
|
|
33757
|
-
if (!value || typeof value !== "object") return;
|
|
33758
|
-
for (const [key2, child] of Object.entries(value)) {
|
|
33759
|
-
if (["matchedPairs", "tradeRows", "allProjectedLeaves"].includes(key2) && Array.isArray(child) && child.length)
|
|
33760
|
-
throw new Error(`Temporary payload ${key2} is not a permanent metric`);
|
|
33761
|
-
if (key2 === "trades" && Array.isArray(child) && child.some(
|
|
33762
|
-
(row) => row && typeof row === "object" && ("signalId" in row || "entryTimestamp" in row)
|
|
33763
|
-
))
|
|
33764
|
-
throw new Error("Temporary trade records are not permanent metrics");
|
|
33765
|
-
validatePermanentResearchMetrics(child);
|
|
33766
|
-
}
|
|
33767
|
-
};
|
|
33768
|
-
encodeResearchMetricSnapshot = (metrics) => {
|
|
33769
|
-
validatePermanentResearchMetrics(metrics);
|
|
33770
|
-
const bytes = Buffer.from(JSON.stringify(metrics));
|
|
33771
|
-
if (bytes.length > MAX_BYTES)
|
|
33772
|
-
throw new Error("Metric snapshot exceeds decoded size limit");
|
|
33773
|
-
return {
|
|
33774
|
-
schema: "tradejs-metric-snapshot/v1",
|
|
33775
|
-
encoding: "gzip+base64",
|
|
33776
|
-
decodedBytes: bytes.length,
|
|
33777
|
-
sha256: hash2(bytes),
|
|
33778
|
-
payload: (0, import_node_zlib2.gzipSync)(bytes, { level: 9 }).toString("base64")
|
|
33779
|
-
};
|
|
33780
|
-
};
|
|
33781
|
-
decodeResearchMetricSnapshot = (snapshot) => {
|
|
33782
|
-
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")
|
|
33783
|
-
throw new Error("Invalid metric snapshot envelope");
|
|
33784
|
-
const bytes = (0, import_node_zlib2.gunzipSync)(Buffer.from(snapshot.payload, "base64"), {
|
|
33785
|
-
maxOutputLength: snapshot.decodedBytes
|
|
33786
|
-
});
|
|
33787
|
-
if (bytes.length !== snapshot.decodedBytes || hash2(bytes) !== snapshot.sha256)
|
|
33788
|
-
throw new Error("Metric snapshot checksum or size mismatch");
|
|
33789
|
-
const metrics = JSON.parse(bytes.toString("utf8"));
|
|
33790
|
-
validatePermanentResearchMetrics(metrics);
|
|
33791
|
-
return metrics;
|
|
33792
|
-
};
|
|
33793
|
-
}
|
|
33794
|
-
});
|
|
33795
|
-
|
|
33796
33877
|
// src/lib/strategyResearch/io.ts
|
|
33797
33878
|
var io_exports = {};
|
|
33798
33879
|
__export(io_exports, {
|
|
@@ -33805,14 +33886,14 @@ __export(io_exports, {
|
|
|
33805
33886
|
verifyResearchState: () => verifyResearchState,
|
|
33806
33887
|
withResearchLock: () => withResearchLock
|
|
33807
33888
|
});
|
|
33808
|
-
var import_promises31, import_node_path25, import_node_os3,
|
|
33889
|
+
var import_promises31, import_node_path25, import_node_os3, import_node_crypto19, researchDirectory, readJson, boundResearchPath, withResearchLock, verifyResearchState, verifyCompletedResearch, initializeResearchState, isRetainedDeletion;
|
|
33809
33890
|
var init_io2 = __esm({
|
|
33810
33891
|
"src/lib/strategyResearch/io.ts"() {
|
|
33811
33892
|
"use strict";
|
|
33812
33893
|
import_promises31 = __toESM(require("fs/promises"));
|
|
33813
33894
|
import_node_path25 = __toESM(require("path"));
|
|
33814
33895
|
import_node_os3 = __toESM(require("os"));
|
|
33815
|
-
|
|
33896
|
+
import_node_crypto19 = require("crypto");
|
|
33816
33897
|
init_io();
|
|
33817
33898
|
researchDirectory = (projectRoot18, spec) => import_node_path25.default.join(projectRoot18, "data/research/strategy", spec.core.researchId);
|
|
33818
33899
|
readJson = async (file) => JSON.parse(await import_promises31.default.readFile(file, "utf8"));
|
|
@@ -33841,7 +33922,7 @@ var init_io2 = __esm({
|
|
|
33841
33922
|
"data/research/strategy/.lock"
|
|
33842
33923
|
);
|
|
33843
33924
|
await import_promises31.default.mkdir(import_node_path25.default.dirname(file), { recursive: true });
|
|
33844
|
-
const token = (0,
|
|
33925
|
+
const token = (0, import_node_crypto19.randomUUID)();
|
|
33845
33926
|
const acquire = () => import_promises31.default.writeFile(
|
|
33846
33927
|
file,
|
|
33847
33928
|
JSON.stringify({ pid: process.pid, host: import_node_os3.default.hostname(), token }),
|
|
@@ -33937,15 +34018,15 @@ var init_io2 = __esm({
|
|
|
33937
34018
|
await writeJsonAtomic(file, state);
|
|
33938
34019
|
return state;
|
|
33939
34020
|
};
|
|
33940
|
-
isRetainedDeletion = async (directory, file,
|
|
34021
|
+
isRetainedDeletion = async (directory, file, hash2) => {
|
|
33941
34022
|
try {
|
|
33942
34023
|
const inventory = await readJson(import_node_path25.default.join(directory, "retention.json"));
|
|
33943
34024
|
const index = inventory.entries.findIndex(
|
|
33944
|
-
(entry) => entry.path === file && entry.sha256 ===
|
|
34025
|
+
(entry) => entry.path === file && entry.sha256 === hash2
|
|
33945
34026
|
);
|
|
33946
34027
|
if (index < 0) return false;
|
|
33947
34028
|
const receipt = await readJson(import_node_path25.default.join(directory, "retention", `${index}.json`));
|
|
33948
|
-
return ["applying", "completed"].includes(receipt.status) && receipt.files[0]?.path === file && receipt.files[0]?.sha256 ===
|
|
34029
|
+
return ["applying", "completed"].includes(receipt.status) && receipt.files[0]?.path === file && receipt.files[0]?.sha256 === hash2;
|
|
33949
34030
|
} catch (error) {
|
|
33950
34031
|
if (error.code === "ENOENT") return false;
|
|
33951
34032
|
throw error;
|
|
@@ -35168,14 +35249,14 @@ var init_evidenceRetention = __esm({
|
|
|
35168
35249
|
});
|
|
35169
35250
|
|
|
35170
35251
|
// src/lib/strategyRelease/researchRetention.ts
|
|
35171
|
-
var import_promises32, import_node_path27,
|
|
35252
|
+
var import_promises32, import_researchMetricSnapshot, import_node_path27, import_node_crypto20, import_strategyReleaseEvidence2, SHA256_RE2, mapFiles, fileSha256, inside, applyResearchRetention;
|
|
35172
35253
|
var init_researchRetention = __esm({
|
|
35173
35254
|
"src/lib/strategyRelease/researchRetention.ts"() {
|
|
35174
35255
|
"use strict";
|
|
35175
35256
|
import_promises32 = __toESM(require("fs/promises"));
|
|
35176
|
-
|
|
35257
|
+
import_researchMetricSnapshot = require("@tradejs/infra/researchMetricSnapshot");
|
|
35177
35258
|
import_node_path27 = __toESM(require("path"));
|
|
35178
|
-
|
|
35259
|
+
import_node_crypto20 = require("crypto");
|
|
35179
35260
|
import_strategyReleaseEvidence2 = require("@tradejs/infra/strategyReleaseEvidence");
|
|
35180
35261
|
init_researchFileConsumers();
|
|
35181
35262
|
init_evidenceRetention();
|
|
@@ -35195,7 +35276,7 @@ var init_researchRetention = __esm({
|
|
|
35195
35276
|
if (worker.status === "rejected") throw worker.reason;
|
|
35196
35277
|
return results2;
|
|
35197
35278
|
};
|
|
35198
|
-
fileSha256 = async (file, bytes) => bytes <= 1024 * 1024 ? (0,
|
|
35279
|
+
fileSha256 = async (file, bytes) => bytes <= 1024 * 1024 ? (0, import_node_crypto20.createHash)("sha256").update(await import_promises32.default.readFile(file)).digest("hex") : (0, import_strategyReleaseEvidence2.strategyEvidenceFileSha256)(file);
|
|
35199
35280
|
inside = (root, file) => {
|
|
35200
35281
|
const relative = import_node_path27.default.relative(root, file);
|
|
35201
35282
|
return relative !== "" && !relative.startsWith(`..${import_node_path27.default.sep}`) && relative !== ".." && !import_node_path27.default.isAbsolute(relative);
|
|
@@ -35258,7 +35339,7 @@ var init_researchRetention = __esm({
|
|
|
35258
35339
|
throw new Error(
|
|
35259
35340
|
"Complete v2 note needs one verified metric snapshot"
|
|
35260
35341
|
);
|
|
35261
|
-
decodeResearchMetricSnapshot(JSON.parse(blocks[0][1]));
|
|
35342
|
+
(0, import_researchMetricSnapshot.decodeResearchMetricSnapshot)(JSON.parse(blocks[0][1]));
|
|
35262
35343
|
}
|
|
35263
35344
|
} finally {
|
|
35264
35345
|
await handle.close();
|
|
@@ -35382,11 +35463,11 @@ var init_retention = __esm({
|
|
|
35382
35463
|
}
|
|
35383
35464
|
const files = /* @__PURE__ */ new Map();
|
|
35384
35465
|
for (const stage of Object.values(state.stages)) {
|
|
35385
|
-
for (const [relative,
|
|
35466
|
+
for (const [relative, hash2] of Object.entries(stage.artifacts)) {
|
|
35386
35467
|
const file = await boundResearchPath(directory, relative);
|
|
35387
35468
|
if (relative.endsWith("/result.json")) {
|
|
35388
35469
|
const result = await readJson(file);
|
|
35389
|
-
if (result?.dataset) files.set(file,
|
|
35470
|
+
if (result?.dataset) files.set(file, hash2);
|
|
35390
35471
|
}
|
|
35391
35472
|
if (relative.endsWith("/sources.json") || relative.endsWith("/payloads.json")) {
|
|
35392
35473
|
const sources = await readJson(file);
|
|
@@ -35403,13 +35484,13 @@ var init_retention = __esm({
|
|
|
35403
35484
|
}
|
|
35404
35485
|
}
|
|
35405
35486
|
const entries = [];
|
|
35406
|
-
for (const [file,
|
|
35487
|
+
for (const [file, hash2] of files) {
|
|
35407
35488
|
const stat = await import_promises33.default.stat(file);
|
|
35408
35489
|
entries.push({
|
|
35409
35490
|
path: file,
|
|
35410
35491
|
kind: "research_payload",
|
|
35411
35492
|
researchId: spec.core.researchId,
|
|
35412
|
-
sha256:
|
|
35493
|
+
sha256: hash2,
|
|
35413
35494
|
bytes: stat.size,
|
|
35414
35495
|
createdAt: stat.birthtimeMs,
|
|
35415
35496
|
verified: true,
|
|
@@ -35493,12 +35574,12 @@ var init_retention = __esm({
|
|
|
35493
35574
|
});
|
|
35494
35575
|
|
|
35495
35576
|
// src/lib/strategyResearch/orchestrator.ts
|
|
35496
|
-
var import_promises34, import_node_path29, runStrategyResearch;
|
|
35577
|
+
var import_promises34, import_researchMetricSnapshot2, import_node_path29, runStrategyResearch;
|
|
35497
35578
|
var init_orchestrator2 = __esm({
|
|
35498
35579
|
"src/lib/strategyResearch/orchestrator.ts"() {
|
|
35499
35580
|
"use strict";
|
|
35500
35581
|
import_promises34 = __toESM(require("fs/promises"));
|
|
35501
|
-
|
|
35582
|
+
import_researchMetricSnapshot2 = require("@tradejs/infra/researchMetricSnapshot");
|
|
35502
35583
|
import_node_path29 = __toESM(require("path"));
|
|
35503
35584
|
init_metrics();
|
|
35504
35585
|
init_io();
|
|
@@ -35689,7 +35770,7 @@ var init_orchestrator2 = __esm({
|
|
|
35689
35770
|
});
|
|
35690
35771
|
let partitionControl;
|
|
35691
35772
|
if (spec.testSince === 0) {
|
|
35692
|
-
const
|
|
35773
|
+
const control = spec.core.variants.find(
|
|
35693
35774
|
(variant) => variant.role === "control"
|
|
35694
35775
|
);
|
|
35695
35776
|
partitionControl = await stage(
|
|
@@ -35706,7 +35787,7 @@ var init_orchestrator2 = __esm({
|
|
|
35706
35787
|
}
|
|
35707
35788
|
return backend.runVariant(
|
|
35708
35789
|
spec,
|
|
35709
|
-
|
|
35790
|
+
control,
|
|
35710
35791
|
folder,
|
|
35711
35792
|
async (runId) => writeJsonAtomic(import_node_path29.default.join(folder, "native-run.json"), {
|
|
35712
35793
|
runId
|
|
@@ -35728,9 +35809,6 @@ var init_orchestrator2 = __esm({
|
|
|
35728
35809
|
let frozenSelection;
|
|
35729
35810
|
const raw = {};
|
|
35730
35811
|
const discovered = [];
|
|
35731
|
-
const control = spec.core.variants.find(
|
|
35732
|
-
(variant) => variant.role === "control"
|
|
35733
|
-
);
|
|
35734
35812
|
const currentPolicy = {
|
|
35735
35813
|
schema: "tradejs-research-entry-policy/v1",
|
|
35736
35814
|
strategy: spec.core.strategy,
|
|
@@ -36206,7 +36284,7 @@ ${JSON.stringify(spec, null, 2)}
|
|
|
36206
36284
|
## Metrics snapshot (machine-readable)
|
|
36207
36285
|
|
|
36208
36286
|
\`\`\`json
|
|
36209
|
-
${JSON.stringify(encodeResearchMetricSnapshot(compact))}
|
|
36287
|
+
${JSON.stringify((0, import_researchMetricSnapshot2.encodeResearchMetricSnapshot)(compact))}
|
|
36210
36288
|
\`\`\`
|
|
36211
36289
|
|
|
36212
36290
|
## Reported metrics
|
|
@@ -36324,7 +36402,7 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
|
|
|
36324
36402
|
});
|
|
36325
36403
|
|
|
36326
36404
|
// src/lib/strategyResearch/native.ts
|
|
36327
|
-
var import_promises35, import_node_fs9, import_node_path30, import_node_os4, import_node_readline4, import_node_child_process8, import_node_module3,
|
|
36405
|
+
var import_promises35, import_node_fs9, import_node_path30, import_node_os4, import_node_readline4, import_node_child_process8, import_node_module3, import_redis18, import_ai9, import_backtest7, import_registry5, import_connectors14, import_data9, import_coreResearch2, import_jev6, validateResearchJevTraining, nativeConfig, runResearchCommand, createNativeStrategyResearchBackend;
|
|
36328
36406
|
var init_native = __esm({
|
|
36329
36407
|
"src/lib/strategyResearch/native.ts"() {
|
|
36330
36408
|
"use strict";
|
|
@@ -36335,7 +36413,7 @@ var init_native = __esm({
|
|
|
36335
36413
|
import_node_readline4 = __toESM(require("readline"));
|
|
36336
36414
|
import_node_child_process8 = require("child_process");
|
|
36337
36415
|
import_node_module3 = require("module");
|
|
36338
|
-
|
|
36416
|
+
import_redis18 = require("@tradejs/infra/redis");
|
|
36339
36417
|
import_ai9 = require("@tradejs/node/ai");
|
|
36340
36418
|
import_backtest7 = require("@tradejs/node/backtest");
|
|
36341
36419
|
import_registry5 = require("@tradejs/node/registry");
|
|
@@ -36799,11 +36877,11 @@ var init_native = __esm({
|
|
|
36799
36877
|
const grid = Object.fromEntries(
|
|
36800
36878
|
Object.entries(config2).map(([key3, value]) => [key3, [value]])
|
|
36801
36879
|
);
|
|
36802
|
-
const key2 =
|
|
36803
|
-
const existing = await (0,
|
|
36880
|
+
const key2 = import_redis18.redisKeys.backtestConfig("root", configName);
|
|
36881
|
+
const existing = await (0, import_redis18.getData)(key2, null);
|
|
36804
36882
|
if (existing != null && sha256Json(existing) !== sha256Json(grid))
|
|
36805
36883
|
throw new Error(`Frozen research config changed: ${configName}`);
|
|
36806
|
-
if (existing == null) await (0,
|
|
36884
|
+
if (existing == null) await (0, import_redis18.setData)(key2, grid, { expire: 0 });
|
|
36807
36885
|
let runId = previousRunId ?? "";
|
|
36808
36886
|
const common = {
|
|
36809
36887
|
executable: process.execPath,
|
|
@@ -37237,7 +37315,7 @@ var strategyResearch_exports = {};
|
|
|
37237
37315
|
__export(strategyResearch_exports, {
|
|
37238
37316
|
main: () => main37
|
|
37239
37317
|
});
|
|
37240
|
-
var import_promises36, import_node_path31,
|
|
37318
|
+
var import_promises36, import_node_path31, import_redis19, usage, main37;
|
|
37241
37319
|
var init_strategyResearch2 = __esm({
|
|
37242
37320
|
"src/scripts/strategyResearch.ts"() {
|
|
37243
37321
|
"use strict";
|
|
@@ -37247,7 +37325,7 @@ var init_strategyResearch2 = __esm({
|
|
|
37247
37325
|
init_researchRoots();
|
|
37248
37326
|
init_io();
|
|
37249
37327
|
init_orchestrator();
|
|
37250
|
-
|
|
37328
|
+
import_redis19 = require("@tradejs/infra/redis");
|
|
37251
37329
|
init_io2();
|
|
37252
37330
|
usage = `Usage:
|
|
37253
37331
|
tradejs research:strategy init --coreSpec <core-spec.json> --out <workflow.json>
|
|
@@ -37335,8 +37413,8 @@ Revalidate keeps the frozen rule and evaluates a new period without fitting.
|
|
|
37335
37413
|
throw new Error(
|
|
37336
37414
|
"Every config must belong to the selected strategy"
|
|
37337
37415
|
);
|
|
37338
|
-
const grid = await (0,
|
|
37339
|
-
|
|
37416
|
+
const grid = await (0, import_redis19.getData)(
|
|
37417
|
+
import_redis19.redisKeys.backtestConfig("root", configName),
|
|
37340
37418
|
null
|
|
37341
37419
|
);
|
|
37342
37420
|
if (!grid || typeof grid !== "object" || Array.isArray(grid) || !Object.keys(grid).length)
|
|
@@ -37476,7 +37554,7 @@ __export(results_exports, {
|
|
|
37476
37554
|
main: () => main38,
|
|
37477
37555
|
results: () => results
|
|
37478
37556
|
});
|
|
37479
|
-
var import_args26, import_chalk42, import_connectors15, import_cli11,
|
|
37557
|
+
var import_args26, import_chalk42, import_connectors15, import_cli11, import_redis20, ListIt4, flags24, MIN_PROFIT, MIN_WIN_RATE, MIN_ORDERS_PER_MONTH, createListIt4, formatPercent4, getMonthlyReturn, toStrategyResultEntry, toStrategyResults, getTestConfigs, buildBestResults, getSavedProfitsBySymbol, getCoverageRow, results, main38;
|
|
37480
37558
|
var init_results = __esm({
|
|
37481
37559
|
"src/scripts/results.ts"() {
|
|
37482
37560
|
"use strict";
|
|
@@ -37484,7 +37562,7 @@ var init_results = __esm({
|
|
|
37484
37562
|
import_chalk42 = __toESM(require("chalk"));
|
|
37485
37563
|
import_connectors15 = require("@tradejs/connectors");
|
|
37486
37564
|
import_cli11 = require("@tradejs/node/cli");
|
|
37487
|
-
|
|
37565
|
+
import_redis20 = require("@tradejs/infra/redis");
|
|
37488
37566
|
ListIt4 = require("list-it");
|
|
37489
37567
|
import_args26.default.example(
|
|
37490
37568
|
"yarn results --strategy TrendLine --coverage",
|
|
@@ -37524,8 +37602,8 @@ var init_results = __esm({
|
|
|
37524
37602
|
[...rows].map((row) => [row.symbol, toStrategyResultEntry(row)])
|
|
37525
37603
|
);
|
|
37526
37604
|
getTestConfigs = async (userName3) => {
|
|
37527
|
-
const testSummariesKey = typeof
|
|
37528
|
-
const indexedItems = testSummariesKey ? await (0,
|
|
37605
|
+
const testSummariesKey = typeof import_redis20.redisKeys.testSummaries === "function" ? import_redis20.redisKeys.testSummaries(userName3) : null;
|
|
37606
|
+
const indexedItems = testSummariesKey ? await (0, import_redis20.getData)(testSummariesKey, null) : null;
|
|
37529
37607
|
if (Array.isArray(indexedItems) && indexedItems.length) {
|
|
37530
37608
|
return indexedItems.map((item) => {
|
|
37531
37609
|
const testName = typeof item?.value === "string" ? item.value : null;
|
|
@@ -37536,8 +37614,8 @@ var init_results = __esm({
|
|
|
37536
37614
|
return { strategyName, testName };
|
|
37537
37615
|
}).filter(Boolean);
|
|
37538
37616
|
}
|
|
37539
|
-
const testsPrefix =
|
|
37540
|
-
const keys = await (0,
|
|
37617
|
+
const testsPrefix = import_redis20.redisKeys.tests(userName3);
|
|
37618
|
+
const keys = await (0, import_redis20.getKeys)(testsPrefix);
|
|
37541
37619
|
const configKeys = keys.filter((key2) => key2.endsWith(":config"));
|
|
37542
37620
|
return configKeys.map((key2) => {
|
|
37543
37621
|
const parts = key2.split(":");
|
|
@@ -37556,15 +37634,15 @@ var init_results = __esm({
|
|
|
37556
37634
|
testName,
|
|
37557
37635
|
strategyName: strategyFromIndex
|
|
37558
37636
|
} of testConfigs) {
|
|
37559
|
-
const config2 = await (0,
|
|
37560
|
-
|
|
37637
|
+
const config2 = await (0, import_redis20.getData)(
|
|
37638
|
+
import_redis20.redisKeys.testConfig(userName3, strategyFromIndex, testName),
|
|
37561
37639
|
null
|
|
37562
37640
|
);
|
|
37563
37641
|
if (!config2 || config2.strategyName !== strategyName) {
|
|
37564
37642
|
continue;
|
|
37565
37643
|
}
|
|
37566
|
-
const stat = await (0,
|
|
37567
|
-
|
|
37644
|
+
const stat = await (0, import_redis20.getData)(
|
|
37645
|
+
import_redis20.redisKeys.testStat(userName3, strategyFromIndex, testName),
|
|
37568
37646
|
null
|
|
37569
37647
|
);
|
|
37570
37648
|
if (!stat) {
|
|
@@ -37609,8 +37687,8 @@ var init_results = __esm({
|
|
|
37609
37687
|
return savedProfitBySymbol;
|
|
37610
37688
|
};
|
|
37611
37689
|
getCoverageRow = async (strategyName, userName3, goodSymbols) => {
|
|
37612
|
-
const currentResults = await (0,
|
|
37613
|
-
|
|
37690
|
+
const currentResults = await (0, import_redis20.getData)(
|
|
37691
|
+
import_redis20.redisKeys.strategyResults(userName3, strategyName),
|
|
37614
37692
|
{}
|
|
37615
37693
|
);
|
|
37616
37694
|
const existingSymbols = new Set(Object.keys(currentResults));
|
|
@@ -37644,8 +37722,8 @@ var init_results = __esm({
|
|
|
37644
37722
|
const strategyName = flags24.strategy;
|
|
37645
37723
|
const userName3 = flags24.user;
|
|
37646
37724
|
if (flags24.clear) {
|
|
37647
|
-
const cleared = await (0,
|
|
37648
|
-
|
|
37725
|
+
const cleared = await (0, import_redis20.delKey)(
|
|
37726
|
+
import_redis20.redisKeys.strategyResults(userName3, strategyName)
|
|
37649
37727
|
);
|
|
37650
37728
|
console.log(
|
|
37651
37729
|
cleared ? import_chalk42.default.green(`Cleared results:${strategyName}`) : import_chalk42.default.yellow(`No results to clear for ${strategyName}`)
|
|
@@ -37693,8 +37771,8 @@ var init_results = __esm({
|
|
|
37693
37771
|
console.log(import_chalk42.default.yellow("No good results to merge."));
|
|
37694
37772
|
process.exit(0);
|
|
37695
37773
|
}
|
|
37696
|
-
const current = await (0,
|
|
37697
|
-
|
|
37774
|
+
const current = await (0, import_redis20.getData)(
|
|
37775
|
+
import_redis20.redisKeys.strategyResults(userName3, strategyName),
|
|
37698
37776
|
{}
|
|
37699
37777
|
);
|
|
37700
37778
|
const savedProfitBySymbol = await getSavedProfitsBySymbol(current);
|
|
@@ -37716,7 +37794,7 @@ var init_results = __esm({
|
|
|
37716
37794
|
...current,
|
|
37717
37795
|
...toStrategyResults(updates)
|
|
37718
37796
|
};
|
|
37719
|
-
await (0,
|
|
37797
|
+
await (0, import_redis20.setData)(import_redis20.redisKeys.strategyResults(userName3, strategyName), merged, {
|
|
37720
37798
|
expire: 0
|
|
37721
37799
|
});
|
|
37722
37800
|
if (flags24.verbose) {
|
|
@@ -37757,8 +37835,8 @@ var init_results = __esm({
|
|
|
37757
37835
|
);
|
|
37758
37836
|
process.exit(0);
|
|
37759
37837
|
}
|
|
37760
|
-
await (0,
|
|
37761
|
-
|
|
37838
|
+
await (0, import_redis20.setData)(
|
|
37839
|
+
import_redis20.redisKeys.strategyResults(userName3, strategyName),
|
|
37762
37840
|
resultsConfig,
|
|
37763
37841
|
{
|
|
37764
37842
|
expire: 0
|
|
@@ -37777,11 +37855,11 @@ var init_results = __esm({
|
|
|
37777
37855
|
});
|
|
37778
37856
|
|
|
37779
37857
|
// src/lib/runtimeDebugEvidence.ts
|
|
37780
|
-
var
|
|
37858
|
+
var import_redis21, RUNTIME_DEBUG_TIMEZONE, RUNTIME_DEBUG_TIMEZONE_LABEL, formatRuntimeDebugDateTime, getRuntimeDebugDateParts, formatRuntimeDebugIsoDayKey, buildRuntimeDebugEvaluationId, filterByStrategies, collectRuntimeDebugEvidence, buildRuntimeDebugReportPayload, buildRuntimeEvidenceReportPayload, buildRuntimeDebugReportAttachment;
|
|
37781
37859
|
var init_runtimeDebugEvidence = __esm({
|
|
37782
37860
|
"src/lib/runtimeDebugEvidence.ts"() {
|
|
37783
37861
|
"use strict";
|
|
37784
|
-
|
|
37862
|
+
import_redis21 = require("@tradejs/infra/redis");
|
|
37785
37863
|
init_runtimeRedis();
|
|
37786
37864
|
init_runtimeSignalsLoader();
|
|
37787
37865
|
init_runtimeSignalsStorage();
|
|
@@ -37888,24 +37966,24 @@ var init_runtimeDebugEvidence = __esm({
|
|
|
37888
37966
|
const tradeDayKey = (0, import_time5.getRuntimeStorageDayKey)(trade.entryTimestamp);
|
|
37889
37967
|
const signalDayKey = signal != null ? (0, import_time5.getRuntimeStorageDayKey)(signal.timestamp) : tradeDayKey;
|
|
37890
37968
|
const evaluationDayKey = knownEvaluation != null ? (0, import_time5.getRuntimeStorageDayKey)(knownEvaluation.timestamp) : signalDayKey;
|
|
37891
|
-
const tradeKey =
|
|
37892
|
-
const tradeBucketKey =
|
|
37969
|
+
const tradeKey = import_redis21.redisKeys.runtimeTrade(userName3, trade.orderId);
|
|
37970
|
+
const tradeBucketKey = import_redis21.redisKeys.runtimeTradeBucket(
|
|
37893
37971
|
userName3,
|
|
37894
37972
|
tradeDayKey
|
|
37895
37973
|
);
|
|
37896
|
-
const activeTradeKey =
|
|
37974
|
+
const activeTradeKey = import_redis21.redisKeys.runtimeActiveTrade(
|
|
37897
37975
|
userName3,
|
|
37898
37976
|
trade.symbol,
|
|
37899
37977
|
trade.deploymentId ?? trade.accountId
|
|
37900
37978
|
);
|
|
37901
|
-
const signalKey = trade.signalId != null ?
|
|
37902
|
-
const evaluationBucketKey =
|
|
37979
|
+
const signalKey = trade.signalId != null ? import_redis21.redisKeys.storeSignal(trade.symbol, trade.signalId) : null;
|
|
37980
|
+
const evaluationBucketKey = import_redis21.redisKeys.runtimeSignalEvaluationBucket(
|
|
37903
37981
|
userName3,
|
|
37904
37982
|
evaluationDayKey,
|
|
37905
37983
|
knownEvaluation?.strategy ?? trade.strategy
|
|
37906
37984
|
);
|
|
37907
37985
|
const evaluationField = knownEvaluation?.evaluationId ?? evaluationId;
|
|
37908
|
-
const evaluationKey =
|
|
37986
|
+
const evaluationKey = import_redis21.redisKeys.runtimeSignalEvaluation(
|
|
37909
37987
|
userName3,
|
|
37910
37988
|
evaluationField
|
|
37911
37989
|
);
|
|
@@ -37916,11 +37994,11 @@ var init_runtimeDebugEvidence = __esm({
|
|
|
37916
37994
|
directEvaluationValue,
|
|
37917
37995
|
bucketEvaluationValue
|
|
37918
37996
|
] = await Promise.all([
|
|
37919
|
-
(0,
|
|
37920
|
-
(0,
|
|
37921
|
-
signalKey ? (0,
|
|
37922
|
-
(0,
|
|
37923
|
-
knownEvaluation ? Promise.resolve(knownEvaluation) : (0,
|
|
37997
|
+
(0, import_redis21.getData)(tradeKey, null),
|
|
37998
|
+
(0, import_redis21.getData)(activeTradeKey, null),
|
|
37999
|
+
signalKey ? (0, import_redis21.getData)(signalKey, null) : Promise.resolve(null),
|
|
38000
|
+
(0, import_redis21.getData)(evaluationKey, null),
|
|
38001
|
+
knownEvaluation ? Promise.resolve(knownEvaluation) : (0, import_redis21.getHashJsonField)(
|
|
37924
38002
|
evaluationBucketKey,
|
|
37925
38003
|
evaluationField,
|
|
37926
38004
|
null
|
|
@@ -37977,12 +38055,12 @@ var init_runtimeDebugEvidence = __esm({
|
|
|
37977
38055
|
dayKeys
|
|
37978
38056
|
},
|
|
37979
38057
|
redisPrefixes: {
|
|
37980
|
-
runtimeTrades:
|
|
37981
|
-
runtimeTradeBuckets:
|
|
37982
|
-
runtimeActiveTrades:
|
|
37983
|
-
runtimeSignals:
|
|
37984
|
-
runtimeSignalEvaluations:
|
|
37985
|
-
runtimeSignalEvaluationStats:
|
|
38058
|
+
runtimeTrades: import_redis21.redisKeys.runtimeTrades(userName3),
|
|
38059
|
+
runtimeTradeBuckets: import_redis21.redisKeys.runtimeTradeBuckets(userName3),
|
|
38060
|
+
runtimeActiveTrades: import_redis21.redisKeys.runtimeActiveTrades(userName3),
|
|
38061
|
+
runtimeSignals: import_redis21.redisKeys.runtimeSignalBuckets(userName3),
|
|
38062
|
+
runtimeSignalEvaluations: import_redis21.redisKeys.runtimeSignalEvaluationBuckets(userName3),
|
|
38063
|
+
runtimeSignalEvaluationStats: import_redis21.redisKeys.runtimeSignalEvaluationStatsBuckets(userName3)
|
|
37986
38064
|
},
|
|
37987
38065
|
counts: {
|
|
37988
38066
|
trades: trades.length,
|
|
@@ -37993,18 +38071,18 @@ var init_runtimeDebugEvidence = __esm({
|
|
|
37993
38071
|
},
|
|
37994
38072
|
trades: debugTrades,
|
|
37995
38073
|
signals: signals2.map((signal) => ({
|
|
37996
|
-
redisKey:
|
|
38074
|
+
redisKey: import_redis21.redisKeys.storeSignal(signal.symbol, signal.signalId),
|
|
37997
38075
|
signal
|
|
37998
38076
|
})),
|
|
37999
38077
|
evaluations: reportEvaluations.map((evaluation) => ({
|
|
38000
38078
|
redisDebug: {
|
|
38001
|
-
key:
|
|
38079
|
+
key: import_redis21.redisKeys.runtimeSignalEvaluationBucket(
|
|
38002
38080
|
userName3,
|
|
38003
38081
|
(0, import_time5.getRuntimeStorageDayKey)(evaluation.timestamp),
|
|
38004
38082
|
evaluation.strategy
|
|
38005
38083
|
),
|
|
38006
38084
|
field: evaluation.evaluationId,
|
|
38007
|
-
directKey:
|
|
38085
|
+
directKey: import_redis21.redisKeys.runtimeSignalEvaluation(
|
|
38008
38086
|
userName3,
|
|
38009
38087
|
evaluation.evaluationId
|
|
38010
38088
|
)
|
|
@@ -38069,7 +38147,7 @@ __export(replayRuntimeEvidence_exports, {
|
|
|
38069
38147
|
replayRuntimeEvidence: () => replayRuntimeEvidence,
|
|
38070
38148
|
summarizeReplayComparison: () => summarizeReplayComparison
|
|
38071
38149
|
});
|
|
38072
|
-
var import_promises37, import_node_path32, import_args27, import_chalk43,
|
|
38150
|
+
var import_promises37, import_node_path32, import_args27, import_chalk43, import_redis22, toEpochMs2, resolveWindow, parseStrategyFilter, asRecord5, asArray2, sum, groupCount, compactMatched, resolveItemStrategy, summarizeReplayComparison, loadReplayResult, getReplayStrategies, loadRuntimePayload, replayRuntimeEvidence, main39;
|
|
38073
38151
|
var init_replayRuntimeEvidence = __esm({
|
|
38074
38152
|
"src/scripts/replayRuntimeEvidence.ts"() {
|
|
38075
38153
|
"use strict";
|
|
@@ -38079,7 +38157,7 @@ var init_replayRuntimeEvidence = __esm({
|
|
|
38079
38157
|
import_node_path32 = __toESM(require("path"));
|
|
38080
38158
|
import_args27 = __toESM(require("args"));
|
|
38081
38159
|
import_chalk43 = __toESM(require("chalk"));
|
|
38082
|
-
|
|
38160
|
+
import_redis22 = require("@tradejs/infra/redis");
|
|
38083
38161
|
init_runtimeDebugEvidence();
|
|
38084
38162
|
init_support2();
|
|
38085
38163
|
import_args27.default.option(["u", "user"], "Use user config", "root");
|
|
@@ -38299,18 +38377,18 @@ var init_replayRuntimeEvidence = __esm({
|
|
|
38299
38377
|
return {
|
|
38300
38378
|
key: replayKey,
|
|
38301
38379
|
availableKeys: void 0,
|
|
38302
|
-
value: await (0,
|
|
38380
|
+
value: await (0, import_redis22.getData)(replayKey, null)
|
|
38303
38381
|
};
|
|
38304
38382
|
}
|
|
38305
|
-
const prefix =
|
|
38306
|
-
const keys = (await (0,
|
|
38383
|
+
const prefix = import_redis22.redisKeys.backtestResults(userName3, REPLAY_RESULTS_CONFIG, "");
|
|
38384
|
+
const keys = (await (0, import_redis22.getKeys)(prefix)).sort(
|
|
38307
38385
|
(left, right) => left.localeCompare(right)
|
|
38308
38386
|
);
|
|
38309
38387
|
const key2 = keys[keys.length - 1] ?? null;
|
|
38310
38388
|
return {
|
|
38311
38389
|
key: key2,
|
|
38312
38390
|
availableKeys: keys.slice(-10),
|
|
38313
|
-
value: key2 ? await (0,
|
|
38391
|
+
value: key2 ? await (0, import_redis22.getData)(key2, null) : null
|
|
38314
38392
|
};
|
|
38315
38393
|
};
|
|
38316
38394
|
getReplayStrategies = (replayValue) => {
|
|
@@ -39945,13 +40023,13 @@ var init_runtimeEvidenceSync = __esm({
|
|
|
39945
40023
|
});
|
|
39946
40024
|
|
|
39947
40025
|
// src/lib/runtimeFeedbackProcess.ts
|
|
39948
|
-
var import_promises40, import_node_path37,
|
|
40026
|
+
var import_promises40, import_node_path37, import_node_crypto21, import_diagnostics2, processRuntimeFeedbackPair;
|
|
39949
40027
|
var init_runtimeFeedbackProcess = __esm({
|
|
39950
40028
|
"src/lib/runtimeFeedbackProcess.ts"() {
|
|
39951
40029
|
"use strict";
|
|
39952
40030
|
import_promises40 = __toESM(require("fs/promises"));
|
|
39953
40031
|
import_node_path37 = __toESM(require("path"));
|
|
39954
|
-
|
|
40032
|
+
import_node_crypto21 = require("crypto");
|
|
39955
40033
|
import_diagnostics2 = require("@tradejs/node/diagnostics");
|
|
39956
40034
|
init_executionCalibration();
|
|
39957
40035
|
init_runtimeScorecard();
|
|
@@ -40010,7 +40088,7 @@ var init_runtimeFeedbackProcess = __esm({
|
|
|
40010
40088
|
if (historyDir)
|
|
40011
40089
|
for (const directory of await (0, import_diagnostics2.discoverRuntimeEvidenceBundles)(historyDir))
|
|
40012
40090
|
history.push((await (0, import_diagnostics2.verifyRuntimeEvidenceBundle)(directory)).artifact);
|
|
40013
|
-
const runId = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:.]/g, "") + "-" + (0,
|
|
40091
|
+
const runId = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:.]/g, "") + "-" + (0, import_node_crypto21.randomUUID)();
|
|
40014
40092
|
const runDir = import_node_path37.default.join(outputRoot, artifactId, runId);
|
|
40015
40093
|
await import_promises40.default.mkdir(runDir, { recursive: true });
|
|
40016
40094
|
const calibration = buildExecutionCalibrationReport({
|
|
@@ -40268,11 +40346,11 @@ var init_runtimeFeedbackSync2 = __esm({
|
|
|
40268
40346
|
});
|
|
40269
40347
|
|
|
40270
40348
|
// src/lib/runtimeEvidenceCompositionSnapshots.ts
|
|
40271
|
-
var
|
|
40349
|
+
var import_node_crypto22, import_promises42, import_node_path41, SNAPSHOT_FILE, MANIFEST_FILE, COMPLETE_FILE, createRuntimeEvidenceCompositionSnapshotRecorder, isRecord2, sha256, safeSegment4, isExistingDestinationError3, parseManifest, verifyRuntimeEvidenceCompositionSnapshot, sameSnapshot, publishRuntimeEvidenceCompositionSnapshot, captureRuntimeEvidenceCompositionSnapshot, discoverRuntimeEvidenceCompositionSnapshots;
|
|
40272
40350
|
var init_runtimeEvidenceCompositionSnapshots = __esm({
|
|
40273
40351
|
"src/lib/runtimeEvidenceCompositionSnapshots.ts"() {
|
|
40274
40352
|
"use strict";
|
|
40275
|
-
|
|
40353
|
+
import_node_crypto22 = require("crypto");
|
|
40276
40354
|
import_promises42 = __toESM(require("fs/promises"));
|
|
40277
40355
|
import_node_path41 = __toESM(require("path"));
|
|
40278
40356
|
init_runtimeEvidenceDeployment();
|
|
@@ -40295,7 +40373,7 @@ var init_runtimeEvidenceCompositionSnapshots = __esm({
|
|
|
40295
40373
|
};
|
|
40296
40374
|
};
|
|
40297
40375
|
isRecord2 = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
40298
|
-
sha256 = (value) => (0,
|
|
40376
|
+
sha256 = (value) => (0, import_node_crypto22.createHash)("sha256").update(value).digest("hex");
|
|
40299
40377
|
safeSegment4 = (value, label) => {
|
|
40300
40378
|
const normalized = value.trim();
|
|
40301
40379
|
if (!normalized || !/^[a-zA-Z0-9._:-]+$/.test(normalized)) {
|
|
@@ -40387,7 +40465,7 @@ var init_runtimeEvidenceCompositionSnapshots = __esm({
|
|
|
40387
40465
|
const temporaryDir = import_node_path41.default.join(
|
|
40388
40466
|
evidenceRoot,
|
|
40389
40467
|
"incoming",
|
|
40390
|
-
`snapshot-${compositionId}.tmp-${(0,
|
|
40468
|
+
`snapshot-${compositionId}.tmp-${(0, import_node_crypto22.randomUUID)()}`
|
|
40391
40469
|
);
|
|
40392
40470
|
await import_promises42.default.mkdir(temporaryDir, { recursive: true });
|
|
40393
40471
|
try {
|
|
@@ -41354,11 +41432,11 @@ async function collectReleaseEvidenceReferences(references) {
|
|
|
41354
41432
|
})
|
|
41355
41433
|
);
|
|
41356
41434
|
}
|
|
41357
|
-
var
|
|
41435
|
+
var import_node_crypto23, import_promises44, import_node_path44, import_types9, import_strategyReleaseEvidence3, SHA256_RE3, LINEAGE_FINGERPRINT_RE, STRATEGY_REVISION_RE, DEPLOYMENT_COMPOSITION_ID_RE, REQUIRED_LONG_WINDOWS, REQUIRED_DIAGNOSTIC_TERMINAL_WINDOWS, MIN_RECENT_DIRECTION_REPAIR_EVENTS, safeSegment5, compactTimestamp, verifyFullPeriodChartArtifact, readVerifiedJsonArtifact, verifyResearchDecisionLineage, hasExactRuntimeTarget, deriveStrategyReleaseResearchDecision, canonicalStrategyReleaseJson, strategyReleaseSha256, assertFingerprint, assertLineageFingerprint, releaseReasons, deriveReleaseGates, verifyEvidenceComposition, createStrategyReleaseManifest, createStrategyReleaseEnvelope, verifyStrategyReleaseEnvelope, verifyStrategyEvidenceMarkerEnvelope, releaseMarkers, writeJsonAtomic2, publishStrategyRelease, publishStrategyLiveDiagnosis, finiteString3, finiteNumber7, finiteDirectionPolicy, uniqueStrings, incompleteEvidenceLineage, extractEvidenceLineage, verifyCompletedCoreResearchBundle;
|
|
41358
41436
|
var init_strategyRelease = __esm({
|
|
41359
41437
|
"src/lib/strategyRelease.ts"() {
|
|
41360
41438
|
"use strict";
|
|
41361
|
-
|
|
41439
|
+
import_node_crypto23 = require("crypto");
|
|
41362
41440
|
import_promises44 = __toESM(require("fs/promises"));
|
|
41363
41441
|
import_node_path44 = __toESM(require("path"));
|
|
41364
41442
|
import_types9 = require("@tradejs/types");
|
|
@@ -42376,7 +42454,7 @@ var init_strategyRelease = __esm({
|
|
|
42376
42454
|
const artifactHashes = manifest.artifactHashes != null && typeof manifest.artifactHashes === "object" && !Array.isArray(manifest.artifactHashes) ? manifest.artifactHashes : null;
|
|
42377
42455
|
const parsedSpec = JSON.parse(specBytes.toString("utf8"));
|
|
42378
42456
|
assert3(
|
|
42379
|
-
manifest.schema === "tradejs-core-research-manifest/v1" && manifest.status === "completed" && manifest.researchId === researchId && manifest.specSha256 === specSha256 && artifactHashes?.["result.json"] === resultSha256 && (0,
|
|
42457
|
+
manifest.schema === "tradejs-core-research-manifest/v1" && manifest.status === "completed" && manifest.researchId === researchId && manifest.specSha256 === specSha256 && artifactHashes?.["result.json"] === resultSha256 && (0, import_node_crypto23.createHash)("sha256").update(canonicalStrategyReleaseJson(parsedSpec)).digest("hex") === specSha256,
|
|
42380
42458
|
"core result is not bound by its completed core research manifest"
|
|
42381
42459
|
);
|
|
42382
42460
|
for (const [relativePath, expectedSha256] of Object.entries(
|
|
@@ -42408,12 +42486,12 @@ __export(runtimeScorecard_exports, {
|
|
|
42408
42486
|
main: () => main46,
|
|
42409
42487
|
runtimeScorecard: () => runtimeScorecard
|
|
42410
42488
|
});
|
|
42411
|
-
var import_promises45,
|
|
42489
|
+
var import_promises45, import_node_crypto24, import_node_path45, import_args34, import_chalk49, flags31, projectRoot14, resolveOptionalPath, readJson2, assertReportType, sha256File2, loadHistoryArtifacts, runtimeScorecard, main46;
|
|
42412
42490
|
var init_runtimeScorecard2 = __esm({
|
|
42413
42491
|
"src/scripts/runtimeScorecard.ts"() {
|
|
42414
42492
|
"use strict";
|
|
42415
42493
|
import_promises45 = __toESM(require("fs/promises"));
|
|
42416
|
-
|
|
42494
|
+
import_node_crypto24 = require("crypto");
|
|
42417
42495
|
import_node_path45 = __toESM(require("path"));
|
|
42418
42496
|
import_args34 = __toESM(require("args"));
|
|
42419
42497
|
import_chalk49 = __toESM(require("chalk"));
|
|
@@ -42492,7 +42570,7 @@ var init_runtimeScorecard2 = __esm({
|
|
|
42492
42570
|
throw new Error(`${label} must be a ${expected} artifact`);
|
|
42493
42571
|
}
|
|
42494
42572
|
};
|
|
42495
|
-
sha256File2 = async (filePath) => (0,
|
|
42573
|
+
sha256File2 = async (filePath) => (0, import_node_crypto24.createHash)("sha256").update(await import_promises45.default.readFile(filePath)).digest("hex");
|
|
42496
42574
|
loadHistoryArtifacts = async (historyDir) => {
|
|
42497
42575
|
if (!historyDir) return [];
|
|
42498
42576
|
const bundleDirs = await (0, runtimeEvidenceArtifacts_exports.discoverRuntimeEvidenceBundles)(historyDir);
|
|
@@ -43038,7 +43116,7 @@ __export(serverHealth_exports, {
|
|
|
43038
43116
|
main: () => main49,
|
|
43039
43117
|
resolveServerHealthThresholds: () => resolveServerHealthThresholds
|
|
43040
43118
|
});
|
|
43041
|
-
var import_config10, import_node_child_process12, import_node_os5, import_node_fs11, import_args35,
|
|
43119
|
+
var import_config10, import_node_child_process12, import_node_os5, import_node_fs11, import_args35, import_redis23, DEFAULT_STATE, DEFAULT_THRESHOLDS, escapeHtml6, formatPctValue, formatLoadPerCore, formatGiB, formatDuration2, readDiskUsage, parseMeminfoBytes, readMemorySnapshot, runDiagnosticCommand, runDiagnosticCommands, collectServerHealthSnapshot, buildHumanSummaryLines, evaluateServerHealth, shouldRecover, buildAlertMessage, buildRecoveryMessage, buildServerHealthDiagnostics, getStateKey, toFiniteNumber3, resolveServerHealthThresholds, main49;
|
|
43042
43120
|
var init_serverHealth = __esm({
|
|
43043
43121
|
"src/scripts/serverHealth.ts"() {
|
|
43044
43122
|
"use strict";
|
|
@@ -43047,7 +43125,7 @@ var init_serverHealth = __esm({
|
|
|
43047
43125
|
import_node_os5 = __toESM(require("os"));
|
|
43048
43126
|
import_node_fs11 = require("fs");
|
|
43049
43127
|
import_args35 = __toESM(require("args"));
|
|
43050
|
-
|
|
43128
|
+
import_redis23 = require("@tradejs/infra/redis");
|
|
43051
43129
|
init_telegramReports();
|
|
43052
43130
|
DEFAULT_STATE = {
|
|
43053
43131
|
status: "healthy",
|
|
@@ -43457,7 +43535,7 @@ var init_serverHealth = __esm({
|
|
|
43457
43535
|
const diskPath = String(flags36.diskPath || "/");
|
|
43458
43536
|
const snapshot = collectServerHealthSnapshot(diskPath);
|
|
43459
43537
|
const stateKey = getStateKey(String(flags36.user), snapshot.hostname);
|
|
43460
|
-
const prevState = await (0,
|
|
43538
|
+
const prevState = await (0, import_redis23.getData)(stateKey, DEFAULT_STATE) ?? DEFAULT_STATE;
|
|
43461
43539
|
const evaluation = evaluateServerHealth(snapshot, thresholds);
|
|
43462
43540
|
const cooldownMs = Math.max(60, Number(flags36.cooldownSec)) * 1e3;
|
|
43463
43541
|
const now2 = snapshot.timestamp;
|
|
@@ -43470,7 +43548,7 @@ var init_serverHealth = __esm({
|
|
|
43470
43548
|
lastOkAt: prevState.lastOkAt,
|
|
43471
43549
|
activeIssueCodes: evaluation.issues.map((issue) => issue.code)
|
|
43472
43550
|
};
|
|
43473
|
-
await (0,
|
|
43551
|
+
await (0, import_redis23.setData)(stateKey, nextState2, { expire: 0 });
|
|
43474
43552
|
if (shouldSend) {
|
|
43475
43553
|
const message = buildAlertMessage({
|
|
43476
43554
|
evaluation,
|
|
@@ -43499,7 +43577,7 @@ var init_serverHealth = __esm({
|
|
|
43499
43577
|
lastOkAt: now2,
|
|
43500
43578
|
activeIssueCodes: []
|
|
43501
43579
|
};
|
|
43502
|
-
await (0,
|
|
43580
|
+
await (0, import_redis23.setData)(stateKey, nextState, { expire: 0 });
|
|
43503
43581
|
if (recovered) {
|
|
43504
43582
|
const message = buildRecoveryMessage({ snapshot, prevState });
|
|
43505
43583
|
if (flags36.printOnly) {
|
|
@@ -44846,18 +44924,18 @@ __export(runtimeParity_exports, {
|
|
|
44846
44924
|
main: () => main50,
|
|
44847
44925
|
runtimeParity: () => runtimeParity
|
|
44848
44926
|
});
|
|
44849
|
-
var import_config11,
|
|
44927
|
+
var import_config11, import_node_crypto25, import_args36, import_chalk52, import_constants20, import_time13, import_logger8, import_redis24, import_cli12, import_backtest8, import_connectors16, flags32, interval3, projectRoot16, DEFAULT_LOOKBACK_DAYS, DETAIL_LIMIT2, DEFAULT_REPLAY_ENV, resolveParityConnectorName, createConnector, buildReplayAiAnalyses, formatReplayEnvSummary, buildReplayConfig, warmReplayHistory, runtimeParity, main50;
|
|
44850
44928
|
var init_runtimeParity2 = __esm({
|
|
44851
44929
|
"src/scripts/runtimeParity.ts"() {
|
|
44852
44930
|
"use strict";
|
|
44853
44931
|
import_config11 = require("dotenv/config");
|
|
44854
|
-
|
|
44932
|
+
import_node_crypto25 = require("crypto");
|
|
44855
44933
|
import_args36 = __toESM(require("args"));
|
|
44856
44934
|
import_chalk52 = __toESM(require("chalk"));
|
|
44857
|
-
|
|
44935
|
+
import_constants20 = require("@tradejs/core/constants");
|
|
44858
44936
|
import_time13 = require("@tradejs/core/time");
|
|
44859
|
-
|
|
44860
|
-
|
|
44937
|
+
import_logger8 = require("@tradejs/infra/logger");
|
|
44938
|
+
import_redis24 = require("@tradejs/infra/redis");
|
|
44861
44939
|
import_cli12 = require("@tradejs/node/cli");
|
|
44862
44940
|
import_backtest8 = require("@tradejs/node/backtest");
|
|
44863
44941
|
import_connectors16 = require("@tradejs/node/connectors");
|
|
@@ -44934,7 +45012,7 @@ var init_runtimeParity2 = __esm({
|
|
|
44934
45012
|
if (connectorName) {
|
|
44935
45013
|
return connectorName;
|
|
44936
45014
|
}
|
|
44937
|
-
|
|
45015
|
+
import_logger8.logger.warn(
|
|
44938
45016
|
'Unknown connector "%s". Fallback to %s.',
|
|
44939
45017
|
String(value || "").trim() || String(value),
|
|
44940
45018
|
import_connectors16.DEFAULT_CONNECTOR_NAME
|
|
@@ -45017,8 +45095,8 @@ var init_runtimeParity2 = __esm({
|
|
|
45017
45095
|
toleranceMs
|
|
45018
45096
|
}) => {
|
|
45019
45097
|
const [userConfig, strategyResults] = await Promise.all([
|
|
45020
|
-
(0,
|
|
45021
|
-
(0,
|
|
45098
|
+
(0, import_redis24.getData)(import_redis24.redisKeys.strategyConfig(userName3, strategy), {}),
|
|
45099
|
+
(0, import_redis24.getData)(import_redis24.redisKeys.strategyResults(userName3, strategy), {})
|
|
45022
45100
|
]);
|
|
45023
45101
|
const typedResults = strategyResults ?? {};
|
|
45024
45102
|
const symbolResult = typedResults?.[symbol];
|
|
@@ -45068,7 +45146,7 @@ var init_runtimeParity2 = __esm({
|
|
|
45068
45146
|
userName: userName3,
|
|
45069
45147
|
projectRoot: projectRoot16,
|
|
45070
45148
|
shouldUseDedicatedReferences: true,
|
|
45071
|
-
warn: (message) =>
|
|
45149
|
+
warn: (message) => import_logger8.logger.warn(message)
|
|
45072
45150
|
});
|
|
45073
45151
|
await updateMarketHistoryWithBtcReferences({
|
|
45074
45152
|
marketConnector: connector,
|
|
@@ -45155,7 +45233,7 @@ var init_runtimeParity2 = __esm({
|
|
|
45155
45233
|
const sourceCounts = countReplayTargetSources(replayTargets);
|
|
45156
45234
|
const preloadStart = (0, import_time13.getBacktestPreloadStart)(
|
|
45157
45235
|
window.start,
|
|
45158
|
-
|
|
45236
|
+
import_constants20.BACKTEST_PRELOAD_DAYS
|
|
45159
45237
|
);
|
|
45160
45238
|
const replayStartedAt = Date.now();
|
|
45161
45239
|
const replaySymbolsCount = new Set(
|
|
@@ -45234,9 +45312,9 @@ var init_runtimeParity2 = __esm({
|
|
|
45234
45312
|
start: window.start,
|
|
45235
45313
|
end: window.end
|
|
45236
45314
|
},
|
|
45237
|
-
name: `${target.symbol}_${target.strategy}_${(0,
|
|
45238
|
-
testId: (0,
|
|
45239
|
-
testSuiteId: (0,
|
|
45315
|
+
name: `${target.symbol}_${target.strategy}_${(0, import_node_crypto25.randomUUID)().slice(0, 8)}`,
|
|
45316
|
+
testId: (0, import_node_crypto25.randomUUID)().slice(0, 8),
|
|
45317
|
+
testSuiteId: (0, import_node_crypto25.randomUUID)().slice(0, 8),
|
|
45240
45318
|
strategyName: target.strategy,
|
|
45241
45319
|
strategyConfig: replayConfig,
|
|
45242
45320
|
connectorName,
|
|
@@ -45399,12 +45477,12 @@ var init_runtimeStrategies = __esm({
|
|
|
45399
45477
|
});
|
|
45400
45478
|
|
|
45401
45479
|
// src/lib/signals/skipStats.ts
|
|
45402
|
-
var import_chalk53,
|
|
45480
|
+
var import_chalk53, import_logger9, createStrategySkipStats, recordStrategyReason, logStrategySkipStats;
|
|
45403
45481
|
var init_skipStats = __esm({
|
|
45404
45482
|
"src/lib/signals/skipStats.ts"() {
|
|
45405
45483
|
"use strict";
|
|
45406
45484
|
import_chalk53 = __toESM(require("chalk"));
|
|
45407
|
-
|
|
45485
|
+
import_logger9 = require("@tradejs/infra/logger");
|
|
45408
45486
|
init_runtimeSignalsStorage();
|
|
45409
45487
|
createStrategySkipStats = (runtimeStrategies) => new Map(
|
|
45410
45488
|
runtimeStrategies.map(({ strategyName }) => [
|
|
@@ -45429,24 +45507,24 @@ var init_skipStats = __esm({
|
|
|
45429
45507
|
);
|
|
45430
45508
|
};
|
|
45431
45509
|
logStrategySkipStats = (runtimeStrategies, strategyStats) => {
|
|
45432
|
-
|
|
45510
|
+
import_logger9.logger.info(import_chalk53.default.yellow("skip stats:"));
|
|
45433
45511
|
for (const { strategyName } of runtimeStrategies) {
|
|
45434
45512
|
const stats = strategyStats.get(strategyName);
|
|
45435
45513
|
if (!stats) {
|
|
45436
45514
|
continue;
|
|
45437
45515
|
}
|
|
45438
|
-
|
|
45516
|
+
import_logger9.logger.info(
|
|
45439
45517
|
`${strategyName}: evaluated=${stats.evaluated}, signals=${stats.signals}`
|
|
45440
45518
|
);
|
|
45441
45519
|
const sortedReasons = [...stats.reasons.entries()].sort(
|
|
45442
45520
|
(left, right) => right[1] - left[1] || left[0].localeCompare(right[0])
|
|
45443
45521
|
);
|
|
45444
45522
|
if (!sortedReasons.length) {
|
|
45445
|
-
|
|
45523
|
+
import_logger9.logger.info(" none");
|
|
45446
45524
|
continue;
|
|
45447
45525
|
}
|
|
45448
45526
|
for (const [reason, count] of sortedReasons) {
|
|
45449
|
-
|
|
45527
|
+
import_logger9.logger.info(` ${reason}: ${count}`);
|
|
45450
45528
|
}
|
|
45451
45529
|
}
|
|
45452
45530
|
};
|
|
@@ -45454,11 +45532,11 @@ var init_skipStats = __esm({
|
|
|
45454
45532
|
});
|
|
45455
45533
|
|
|
45456
45534
|
// src/lib/signals/evaluations.ts
|
|
45457
|
-
var
|
|
45535
|
+
var import_redis25, runtimeLineageScopeCache, runtimeLineageScopeCacheDayKey, runtimeLineageScopeCacheLoaded, buildRuntimeSignalEvaluationId, buildLineageField, flushRuntimeSignalEvaluations, createRuntimeSignalEvaluationBuffer;
|
|
45458
45536
|
var init_evaluations = __esm({
|
|
45459
45537
|
"src/lib/signals/evaluations.ts"() {
|
|
45460
45538
|
"use strict";
|
|
45461
|
-
|
|
45539
|
+
import_redis25 = require("@tradejs/infra/redis");
|
|
45462
45540
|
init_runtimeSignalsStorage();
|
|
45463
45541
|
init_runtimeLineage();
|
|
45464
45542
|
runtimeLineageScopeCache = /* @__PURE__ */ new Map();
|
|
@@ -45509,7 +45587,7 @@ var init_evaluations = __esm({
|
|
|
45509
45587
|
runtimeLineageScopeCacheDayKey = dayKey;
|
|
45510
45588
|
runtimeLineageScopeCacheLoaded = false;
|
|
45511
45589
|
}
|
|
45512
|
-
const lineageBucket =
|
|
45590
|
+
const lineageBucket = import_redis25.redisKeys.runtimeLineageScopeBucket(
|
|
45513
45591
|
dayEvaluations[0].userName,
|
|
45514
45592
|
dayKey
|
|
45515
45593
|
);
|
|
@@ -45517,7 +45595,7 @@ var init_evaluations = __esm({
|
|
|
45517
45595
|
(evaluation) => evaluation.runtimeLineage != null
|
|
45518
45596
|
);
|
|
45519
45597
|
if (lineageEvaluations.length > 0 && !runtimeLineageScopeCacheLoaded) {
|
|
45520
|
-
const storedScopes = await (0,
|
|
45598
|
+
const storedScopes = await (0, import_redis25.getHashJsonValues)(lineageBucket);
|
|
45521
45599
|
for (const scope of storedScopes) {
|
|
45522
45600
|
const lineageField = buildLineageField(scope);
|
|
45523
45601
|
runtimeLineageScopeCache.set(`${lineageBucket}:${lineageField}`, scope);
|
|
@@ -45562,7 +45640,7 @@ var init_evaluations = __esm({
|
|
|
45562
45640
|
lineageWrites.set(lineageField, scope);
|
|
45563
45641
|
}
|
|
45564
45642
|
if (lineageWrites.size > 0) {
|
|
45565
|
-
await (0,
|
|
45643
|
+
await (0, import_redis25.setHashJsonFields)(
|
|
45566
45644
|
lineageBucket,
|
|
45567
45645
|
[...lineageWrites].map(([field, data]) => ({ field, data })),
|
|
45568
45646
|
{
|
|
@@ -45574,7 +45652,7 @@ var init_evaluations = __esm({
|
|
|
45574
45652
|
const statsIncrements = /* @__PURE__ */ new Map();
|
|
45575
45653
|
for (const evaluation of dayEvaluations) {
|
|
45576
45654
|
if (shouldStoreDetailedRuntimeSignalEvaluation(evaluation)) {
|
|
45577
|
-
const bucket =
|
|
45655
|
+
const bucket = import_redis25.redisKeys.runtimeSignalEvaluationBucket(
|
|
45578
45656
|
evaluation.userName,
|
|
45579
45657
|
dayKey,
|
|
45580
45658
|
evaluation.strategy
|
|
@@ -45586,7 +45664,7 @@ var init_evaluations = __esm({
|
|
|
45586
45664
|
});
|
|
45587
45665
|
detailedWrites.set(bucket, entries);
|
|
45588
45666
|
}
|
|
45589
|
-
const statsBucket =
|
|
45667
|
+
const statsBucket = import_redis25.redisKeys.runtimeSignalEvaluationStatsBucket(
|
|
45590
45668
|
evaluation.userName,
|
|
45591
45669
|
dayKey,
|
|
45592
45670
|
evaluation.strategy,
|
|
@@ -45602,12 +45680,12 @@ var init_evaluations = __esm({
|
|
|
45602
45680
|
}
|
|
45603
45681
|
await Promise.all([
|
|
45604
45682
|
...[...detailedWrites].map(
|
|
45605
|
-
([bucket, entries]) => (0,
|
|
45683
|
+
([bucket, entries]) => (0, import_redis25.setHashJsonFields)(bucket, entries, {
|
|
45606
45684
|
expire: runtimeSignalRetentionTtl
|
|
45607
45685
|
})
|
|
45608
45686
|
),
|
|
45609
45687
|
...[...statsIncrements].map(
|
|
45610
|
-
([bucket, increments]) => (0,
|
|
45688
|
+
([bucket, increments]) => (0, import_redis25.incrHashFields)(bucket, increments, {
|
|
45611
45689
|
expire: runtimeSignalRetentionTtl
|
|
45612
45690
|
})
|
|
45613
45691
|
)
|
|
@@ -45623,7 +45701,7 @@ var init_evaluations = __esm({
|
|
|
45623
45701
|
const runtimeSignalRetentionTtl = getRuntimeSignalRetentionTtlSeconds();
|
|
45624
45702
|
const signalRefsByBucket = /* @__PURE__ */ new Map();
|
|
45625
45703
|
for (const { userName: userName3, signal } of pendingSignals) {
|
|
45626
|
-
const bucket =
|
|
45704
|
+
const bucket = import_redis25.redisKeys.runtimeSignalBucket(
|
|
45627
45705
|
userName3,
|
|
45628
45706
|
(0, import_time5.getRuntimeStorageDayKey)(signal.timestamp),
|
|
45629
45707
|
signal.strategy
|
|
@@ -45637,14 +45715,14 @@ var init_evaluations = __esm({
|
|
|
45637
45715
|
}
|
|
45638
45716
|
await Promise.all([
|
|
45639
45717
|
...pendingSignals.map(
|
|
45640
|
-
({ signal }) => (0,
|
|
45641
|
-
|
|
45718
|
+
({ signal }) => (0, import_redis25.setData)(
|
|
45719
|
+
import_redis25.redisKeys.storeSignal(signal.symbol, signal.signalId),
|
|
45642
45720
|
toStoredRuntimeSignal(signal),
|
|
45643
45721
|
{ expire: runtimeSignalRetentionTtl }
|
|
45644
45722
|
)
|
|
45645
45723
|
),
|
|
45646
45724
|
...[...signalRefsByBucket].map(
|
|
45647
|
-
([bucket, entries]) => (0,
|
|
45725
|
+
([bucket, entries]) => (0, import_redis25.setHashJsonFields)(bucket, entries, {
|
|
45648
45726
|
expire: runtimeSignalRetentionTtl
|
|
45649
45727
|
})
|
|
45650
45728
|
)
|
|
@@ -45897,12 +45975,12 @@ var init_daemon = __esm({
|
|
|
45897
45975
|
});
|
|
45898
45976
|
|
|
45899
45977
|
// src/lib/signals/klineFeed.ts
|
|
45900
|
-
var import_connectors17,
|
|
45978
|
+
var import_connectors17, import_logger10, import_candles5, FLUSH_DELAY_MS, normalizeSymbols2, createSignalsKlineFeed;
|
|
45901
45979
|
var init_klineFeed = __esm({
|
|
45902
45980
|
"src/lib/signals/klineFeed.ts"() {
|
|
45903
45981
|
"use strict";
|
|
45904
45982
|
import_connectors17 = require("@tradejs/connectors");
|
|
45905
|
-
|
|
45983
|
+
import_logger10 = require("@tradejs/infra/logger");
|
|
45906
45984
|
import_candles5 = require("@tradejs/infra/timescale/candles");
|
|
45907
45985
|
init_klineEvents();
|
|
45908
45986
|
FLUSH_DELAY_MS = 100;
|
|
@@ -45956,7 +46034,7 @@ var init_klineFeed = __esm({
|
|
|
45956
46034
|
if (flushTimer || closed) return;
|
|
45957
46035
|
flushTimer = setTimeout(() => {
|
|
45958
46036
|
void flush().catch(
|
|
45959
|
-
(error) =>
|
|
46037
|
+
(error) => import_logger10.logger.error("websocket candle batch flush failed: %s", String(error))
|
|
45960
46038
|
);
|
|
45961
46039
|
}, FLUSH_DELAY_MS);
|
|
45962
46040
|
};
|
|
@@ -45973,7 +46051,7 @@ var init_klineFeed = __esm({
|
|
|
45973
46051
|
confirm: event.confirm,
|
|
45974
46052
|
receivedAt: event.receivedAt
|
|
45975
46053
|
}).catch(
|
|
45976
|
-
(error) =>
|
|
46054
|
+
(error) => import_logger10.logger.warn("websocket candle publish failed: %s", String(error))
|
|
45977
46055
|
);
|
|
45978
46056
|
if (!event.confirm) return;
|
|
45979
46057
|
pending.set(`${event.symbol}:${event.candle.timestamp}`, {
|
|
@@ -46028,12 +46106,12 @@ var init_klineFeed = __esm({
|
|
|
46028
46106
|
});
|
|
46029
46107
|
|
|
46030
46108
|
// src/lib/signals/tickerEvaluator.ts
|
|
46031
|
-
var import_strategies13,
|
|
46109
|
+
var import_strategies13, import_logger11, createSignalsTickerEvaluator;
|
|
46032
46110
|
var init_tickerEvaluator = __esm({
|
|
46033
46111
|
"src/lib/signals/tickerEvaluator.ts"() {
|
|
46034
46112
|
"use strict";
|
|
46035
46113
|
import_strategies13 = require("@tradejs/node/strategies");
|
|
46036
|
-
|
|
46114
|
+
import_logger11 = require("@tradejs/infra/logger");
|
|
46037
46115
|
init_windows();
|
|
46038
46116
|
init_runtimeLineage();
|
|
46039
46117
|
init_runtimeModeConfig();
|
|
@@ -46193,7 +46271,7 @@ var init_tickerEvaluator = __esm({
|
|
|
46193
46271
|
continue;
|
|
46194
46272
|
}
|
|
46195
46273
|
if (evaluation.action.startsWith("rebuilt_")) {
|
|
46196
|
-
|
|
46274
|
+
import_logger11.logger.info(
|
|
46197
46275
|
"Rebuilt signals strategy state (%s): %s %s",
|
|
46198
46276
|
evaluation.action.slice("rebuilt_".length),
|
|
46199
46277
|
strategyName,
|
|
@@ -46296,7 +46374,7 @@ var init_tickerEvaluator = __esm({
|
|
|
46296
46374
|
...signal.riskDecision ? { riskDecision: signal.riskDecision } : {},
|
|
46297
46375
|
...signal.ml ? { ml: signal.ml } : {}
|
|
46298
46376
|
});
|
|
46299
|
-
|
|
46377
|
+
import_logger11.logger.info("Signal found %s by strategy %s", symbol, strategyName);
|
|
46300
46378
|
}
|
|
46301
46379
|
return strategySignals;
|
|
46302
46380
|
};
|
|
@@ -46445,7 +46523,7 @@ var init_configuredScopes = __esm({
|
|
|
46445
46523
|
});
|
|
46446
46524
|
|
|
46447
46525
|
// src/lib/signals/runner.ts
|
|
46448
|
-
var import_progress12, import_chalk54, import_connectors18, import_cli13, import_async5, import_strategies14,
|
|
46526
|
+
var import_progress12, import_chalk54, import_connectors18, import_cli13, import_async5, import_strategies14, import_constants21, import_time14, import_logger12, import_runtimeDeploymentEvents, import_runtimeHeartbeats, import_runtimeStrategies7, SLOW_SIGNALS_WARNING_MS, formatDuration3, resolvePositiveInteger2, resolveNonNegativeInteger, createSignalsRunner;
|
|
46449
46527
|
var init_runner = __esm({
|
|
46450
46528
|
"src/lib/signals/runner.ts"() {
|
|
46451
46529
|
"use strict";
|
|
@@ -46455,9 +46533,9 @@ var init_runner = __esm({
|
|
|
46455
46533
|
import_cli13 = require("@tradejs/node/cli");
|
|
46456
46534
|
import_async5 = require("@tradejs/core/async");
|
|
46457
46535
|
import_strategies14 = require("@tradejs/core/strategies");
|
|
46458
|
-
|
|
46536
|
+
import_constants21 = require("@tradejs/core/constants");
|
|
46459
46537
|
import_time14 = require("@tradejs/core/time");
|
|
46460
|
-
|
|
46538
|
+
import_logger12 = require("@tradejs/infra/logger");
|
|
46461
46539
|
import_runtimeDeploymentEvents = require("@tradejs/infra/runtimeDeploymentEvents");
|
|
46462
46540
|
import_runtimeHeartbeats = require("@tradejs/infra/runtimeHeartbeats");
|
|
46463
46541
|
import_runtimeStrategies7 = require("@tradejs/node/runtimeStrategies");
|
|
@@ -46504,7 +46582,7 @@ var init_runner = __esm({
|
|
|
46504
46582
|
deploymentId: config2.deploymentId,
|
|
46505
46583
|
expectedCompositionId: compositionId
|
|
46506
46584
|
}),
|
|
46507
|
-
onError: (compositionId, error) =>
|
|
46585
|
+
onError: (compositionId, error) => import_logger12.logger.warn(
|
|
46508
46586
|
"runtime evidence snapshot unavailable; trading continues and the next cycle will retry (composition=%s): %s",
|
|
46509
46587
|
compositionId,
|
|
46510
46588
|
error instanceof Error ? error.message : String(error)
|
|
@@ -46513,7 +46591,7 @@ var init_runner = __esm({
|
|
|
46513
46591
|
const resolveSignalsDaemonMaxLiveBars = (runtimeInterval = interval4) => {
|
|
46514
46592
|
const intervalMinutes = Number(runtimeInterval);
|
|
46515
46593
|
const preloadBars = Math.ceil(
|
|
46516
|
-
|
|
46594
|
+
import_constants21.SIGNALS_CLI_PRELOAD_DAYS * 24 * 60 / intervalMinutes
|
|
46517
46595
|
);
|
|
46518
46596
|
return resolvePositiveInteger2(
|
|
46519
46597
|
process.env.SIGNALS_DAEMON_MAX_LIVE_BARS,
|
|
@@ -46532,7 +46610,7 @@ var init_runner = __esm({
|
|
|
46532
46610
|
const timeOperation3 = (label, operation) => timeOperation(
|
|
46533
46611
|
label,
|
|
46534
46612
|
operation,
|
|
46535
|
-
(message) =>
|
|
46613
|
+
(message) => import_logger12.logger.info(import_chalk54.default.gray(message))
|
|
46536
46614
|
);
|
|
46537
46615
|
const formatSlowSignalsWarning = (params) => [
|
|
46538
46616
|
"<b>Slow yarn signals run</b>",
|
|
@@ -46589,7 +46667,7 @@ var init_runner = __esm({
|
|
|
46589
46667
|
userName: config2.userName,
|
|
46590
46668
|
projectRoot: projectRoot18,
|
|
46591
46669
|
shouldUseDedicatedReferences: universe === "crypto" && connectorName.toLowerCase() === import_connectors18.DEFAULT_CONNECTOR_NAME.toLowerCase(),
|
|
46592
|
-
warn: (message) =>
|
|
46670
|
+
warn: (message) => import_logger12.logger.warn(message)
|
|
46593
46671
|
});
|
|
46594
46672
|
return {
|
|
46595
46673
|
connectorName,
|
|
@@ -46649,7 +46727,7 @@ var init_runner = __esm({
|
|
|
46649
46727
|
}) : [];
|
|
46650
46728
|
const selectedTickers = selection?.tickers ? [.../* @__PURE__ */ new Set([...selection.tickers, ...selectedActiveSymbols])] : void 0;
|
|
46651
46729
|
if (selectedActiveSymbols.length) {
|
|
46652
|
-
|
|
46730
|
+
import_logger12.logger.info(
|
|
46653
46731
|
import_chalk54.default.gray(
|
|
46654
46732
|
`runtime scope retained active symbols: ${selectedActiveSymbols.join(", ")}`
|
|
46655
46733
|
)
|
|
@@ -46687,7 +46765,7 @@ var init_runner = __esm({
|
|
|
46687
46765
|
const projectConfig = await (0, import_cli13.loadTradejsConfig)(projectRoot18);
|
|
46688
46766
|
projectHooks = projectConfig.hooks;
|
|
46689
46767
|
const currentTimestamp = (0, import_time14.getTimestamp)();
|
|
46690
|
-
const preloadStart = (0, import_time14.getTimestamp)(
|
|
46768
|
+
const preloadStart = (0, import_time14.getTimestamp)(import_constants21.SIGNALS_CLI_PRELOAD_DAYS);
|
|
46691
46769
|
if (!config2.cacheOnly && session.klineFeed) {
|
|
46692
46770
|
const expectedSymbols = universe === "crypto" ? [.../* @__PURE__ */ new Set([...tickers, "BTCUSDT", "ETHUSDT"])] : tickers;
|
|
46693
46771
|
session.klineFeed.setSubscriptions(expectedSymbols);
|
|
@@ -46701,7 +46779,7 @@ var init_runner = __esm({
|
|
|
46701
46779
|
})
|
|
46702
46780
|
);
|
|
46703
46781
|
await session.klineFeed.flush();
|
|
46704
|
-
|
|
46782
|
+
import_logger12.logger.info(
|
|
46705
46783
|
import_chalk54.default.gray(
|
|
46706
46784
|
`websocket candles: ready=${expectedSymbols.length - missingSymbols.length}/${expectedSymbols.length} missing=${missingSymbols.length}`
|
|
46707
46785
|
)
|
|
@@ -46711,17 +46789,17 @@ var init_runner = __esm({
|
|
|
46711
46789
|
connectorName,
|
|
46712
46790
|
interval: interval5,
|
|
46713
46791
|
symbols: missingSymbols,
|
|
46714
|
-
preloadDays:
|
|
46792
|
+
preloadDays: import_constants21.SIGNALS_CLI_PRELOAD_DAYS,
|
|
46715
46793
|
universe,
|
|
46716
|
-
log: (message) =>
|
|
46794
|
+
log: (message) => import_logger12.logger.info(import_chalk54.default.gray(message))
|
|
46717
46795
|
});
|
|
46718
46796
|
await updateBtcReferenceHistory({
|
|
46719
46797
|
marketConnector,
|
|
46720
46798
|
btcReferences,
|
|
46721
46799
|
interval: interval5,
|
|
46722
|
-
preloadDays:
|
|
46800
|
+
preloadDays: import_constants21.SIGNALS_CLI_PRELOAD_DAYS,
|
|
46723
46801
|
universe,
|
|
46724
|
-
log: (message) =>
|
|
46802
|
+
log: (message) => import_logger12.logger.info(import_chalk54.default.gray(message))
|
|
46725
46803
|
});
|
|
46726
46804
|
} else if (!config2.cacheOnly) {
|
|
46727
46805
|
await updateMarketHistoryWithBtcReferences({
|
|
@@ -46730,9 +46808,9 @@ var init_runner = __esm({
|
|
|
46730
46808
|
btcReferences,
|
|
46731
46809
|
interval: interval5,
|
|
46732
46810
|
symbols: tickers,
|
|
46733
|
-
preloadDays:
|
|
46811
|
+
preloadDays: import_constants21.SIGNALS_CLI_PRELOAD_DAYS,
|
|
46734
46812
|
universe,
|
|
46735
|
-
log: (message) =>
|
|
46813
|
+
log: (message) => import_logger12.logger.info(import_chalk54.default.gray(message))
|
|
46736
46814
|
});
|
|
46737
46815
|
}
|
|
46738
46816
|
await prepareMarketContextForRun({
|
|
@@ -46746,7 +46824,7 @@ var init_runner = __esm({
|
|
|
46746
46824
|
endMs: currentTimestamp,
|
|
46747
46825
|
preloadStartMs: preloadStart,
|
|
46748
46826
|
cacheOnly: config2.cacheOnly,
|
|
46749
|
-
log: (message) =>
|
|
46827
|
+
log: (message) => import_logger12.logger.info(import_chalk54.default.gray(message))
|
|
46750
46828
|
});
|
|
46751
46829
|
if (config2.updateOnly) {
|
|
46752
46830
|
return;
|
|
@@ -46816,7 +46894,7 @@ var init_runner = __esm({
|
|
|
46816
46894
|
) : configuredRuntimeStrategies;
|
|
46817
46895
|
if (!runtimeStrategies.length) {
|
|
46818
46896
|
lifecycle.clear();
|
|
46819
|
-
|
|
46897
|
+
import_logger12.logger.warn(
|
|
46820
46898
|
"No strategy releases are bound to deployment %s",
|
|
46821
46899
|
deployment?.id
|
|
46822
46900
|
);
|
|
@@ -46849,7 +46927,7 @@ var init_runner = __esm({
|
|
|
46849
46927
|
)
|
|
46850
46928
|
)
|
|
46851
46929
|
);
|
|
46852
|
-
|
|
46930
|
+
import_logger12.logger.info(
|
|
46853
46931
|
import_chalk54.default.yellow(
|
|
46854
46932
|
`loaded strategies (user=${config2.userName}): ${runtimeStrategies.map(formatConfiguredStrategyIdentity).join(", ")}`
|
|
46855
46933
|
)
|
|
@@ -46872,7 +46950,7 @@ var init_runner = __esm({
|
|
|
46872
46950
|
afterSignalsHookContext
|
|
46873
46951
|
);
|
|
46874
46952
|
if (beforeSignalsResult?.abort === true) {
|
|
46875
|
-
|
|
46953
|
+
import_logger12.logger.info(
|
|
46876
46954
|
"signals aborted before ticker evaluation: %s",
|
|
46877
46955
|
beforeSignalsResult.reason ?? "PROJECT_BEFORE_SIGNALS_ABORTED"
|
|
46878
46956
|
);
|
|
@@ -46886,9 +46964,9 @@ var init_runner = __esm({
|
|
|
46886
46964
|
width: 30
|
|
46887
46965
|
}
|
|
46888
46966
|
);
|
|
46889
|
-
|
|
46967
|
+
import_logger12.logger.info(import_chalk54.default.yellow(`tickers: ${tickers.length}`));
|
|
46890
46968
|
const signalsParallel = resolvePositiveInteger2(config2.parallel, 4);
|
|
46891
|
-
|
|
46969
|
+
import_logger12.logger.info(import_chalk54.default.yellow(`signal workers: ${signalsParallel}`));
|
|
46892
46970
|
const evaluateTicker = createSignalsTickerEvaluator({
|
|
46893
46971
|
userName: config2.userName,
|
|
46894
46972
|
makeOrders: config2.makeOrders,
|
|
@@ -46959,7 +47037,7 @@ var init_runner = __esm({
|
|
|
46959
47037
|
config2.userName
|
|
46960
47038
|
);
|
|
46961
47039
|
}
|
|
46962
|
-
|
|
47040
|
+
import_logger12.logger.info(
|
|
46963
47041
|
JSON.stringify(
|
|
46964
47042
|
signals3.map((s) => s.symbol),
|
|
46965
47043
|
null,
|
|
@@ -46972,7 +47050,7 @@ var init_runner = __esm({
|
|
|
46972
47050
|
} catch (error) {
|
|
46973
47051
|
status = "failed";
|
|
46974
47052
|
failureMessage = error?.message || String(error);
|
|
46975
|
-
|
|
47053
|
+
import_logger12.logger.error(
|
|
46976
47054
|
"signals failed: %s",
|
|
46977
47055
|
error?.message || String(error)
|
|
46978
47056
|
);
|
|
@@ -46982,7 +47060,7 @@ var init_runner = __esm({
|
|
|
46982
47060
|
await runtimeSignalEvaluations.flush();
|
|
46983
47061
|
} catch (error) {
|
|
46984
47062
|
telemetryPersistence = "failed";
|
|
46985
|
-
|
|
47063
|
+
import_logger12.logger.error(
|
|
46986
47064
|
"runtime signal evaluation flush failed: %s",
|
|
46987
47065
|
error?.message || String(error)
|
|
46988
47066
|
);
|
|
@@ -47013,7 +47091,7 @@ var init_runner = __esm({
|
|
|
47013
47091
|
durationMs
|
|
47014
47092
|
});
|
|
47015
47093
|
} catch (error) {
|
|
47016
|
-
|
|
47094
|
+
import_logger12.logger.error(
|
|
47017
47095
|
"afterSignals hook failed: %s",
|
|
47018
47096
|
error?.message || String(error)
|
|
47019
47097
|
);
|
|
@@ -47030,20 +47108,20 @@ var init_runner = __esm({
|
|
|
47030
47108
|
{ userName: config2.userName }
|
|
47031
47109
|
);
|
|
47032
47110
|
} catch (error) {
|
|
47033
|
-
|
|
47111
|
+
import_logger12.logger.error(
|
|
47034
47112
|
"slow signals warning failed: %s",
|
|
47035
47113
|
error?.message || String(error)
|
|
47036
47114
|
);
|
|
47037
47115
|
}
|
|
47038
47116
|
}
|
|
47039
|
-
|
|
47117
|
+
import_logger12.logger.info(
|
|
47040
47118
|
import_chalk54.default.yellow(
|
|
47041
47119
|
`signals ${status} in ${formatDuration3(durationMs)} (found=${signals3.length})`
|
|
47042
47120
|
)
|
|
47043
47121
|
);
|
|
47044
|
-
|
|
47045
|
-
|
|
47046
|
-
|
|
47122
|
+
import_logger12.logger.info("");
|
|
47123
|
+
import_logger12.logger.info("");
|
|
47124
|
+
import_logger12.logger.info("");
|
|
47047
47125
|
}
|
|
47048
47126
|
};
|
|
47049
47127
|
const loadConfiguredSignalsScopes = async (deployment) => {
|
|
@@ -47118,14 +47196,14 @@ var init_runner = __esm({
|
|
|
47118
47196
|
const sessions = /* @__PURE__ */ new Map();
|
|
47119
47197
|
const lastBoundaryByScope = /* @__PURE__ */ new Map();
|
|
47120
47198
|
const stop = (signalName) => {
|
|
47121
|
-
|
|
47199
|
+
import_logger12.logger.info("signals daemon stopping by %s", signalName);
|
|
47122
47200
|
abortController.abort();
|
|
47123
47201
|
};
|
|
47124
47202
|
const stopOnSigint = () => stop("SIGINT");
|
|
47125
47203
|
const stopOnSigterm = () => stop("SIGTERM");
|
|
47126
47204
|
process.once("SIGINT", stopOnSigint);
|
|
47127
47205
|
process.once("SIGTERM", stopOnSigterm);
|
|
47128
|
-
|
|
47206
|
+
import_logger12.logger.info("signals daemon started (deployment-driven scopes)");
|
|
47129
47207
|
try {
|
|
47130
47208
|
await runSignalsDaemon({
|
|
47131
47209
|
intervalMs: 6e4,
|
|
@@ -47151,7 +47229,7 @@ var init_runner = __esm({
|
|
|
47151
47229
|
strategies
|
|
47152
47230
|
});
|
|
47153
47231
|
} catch (error) {
|
|
47154
|
-
|
|
47232
|
+
import_logger12.logger.warn(
|
|
47155
47233
|
"runtime deployment composition event unavailable; trading continues and the next cycle will retry (composition=%s): %s",
|
|
47156
47234
|
currentDeployment.deploymentCompositionId,
|
|
47157
47235
|
error instanceof Error ? error.message : String(error)
|
|
@@ -47187,7 +47265,7 @@ var init_runner = __esm({
|
|
|
47187
47265
|
interval: session.interval,
|
|
47188
47266
|
universe: session.universe
|
|
47189
47267
|
});
|
|
47190
|
-
|
|
47268
|
+
import_logger12.logger.info(
|
|
47191
47269
|
"Bybit websocket candle feed enabled (account=%s, universe=%s, interval=%s)",
|
|
47192
47270
|
session.accountId ?? "default",
|
|
47193
47271
|
session.universe,
|
|
@@ -47209,7 +47287,7 @@ var init_runner = __esm({
|
|
|
47209
47287
|
(sum3, session) => sum3 + session.lifecycle.size(),
|
|
47210
47288
|
0
|
|
47211
47289
|
);
|
|
47212
|
-
|
|
47290
|
+
import_logger12.logger.info(
|
|
47213
47291
|
"signals daemon resources: rss=%sMB heapUsed=%sMB heapTotal=%sMB stateKeys=%s scopes=%s",
|
|
47214
47292
|
(memory.rss / 1024 / 1024).toFixed(1),
|
|
47215
47293
|
(memory.heapUsed / 1024 / 1024).toFixed(1),
|
|
@@ -47219,7 +47297,7 @@ var init_runner = __esm({
|
|
|
47219
47297
|
);
|
|
47220
47298
|
},
|
|
47221
47299
|
onCycleError: (error) => {
|
|
47222
|
-
|
|
47300
|
+
import_logger12.logger.error(
|
|
47223
47301
|
"signals daemon cycle failed: %s",
|
|
47224
47302
|
error?.message || String(error)
|
|
47225
47303
|
);
|
|
@@ -47359,14 +47437,14 @@ __export(signalsSummary_exports, {
|
|
|
47359
47437
|
main: () => main53,
|
|
47360
47438
|
signalsSummary: () => signalsSummary
|
|
47361
47439
|
});
|
|
47362
|
-
var import_config13, import_userSettings8, import_args38,
|
|
47440
|
+
var import_config13, import_userSettings8, import_args38, import_logger13, import_connectors19, import_runtimeStrategies9, flags34, projectRoot17, SUMMARY_TIMEZONE2, SUMMARY_TIMEZONE_LABEL2, escapeHtml8, formatMskDateTime4, formatSigned3, formatPnlMoneyText, formatWinRateText, resolveSummaryTitle, normalizeStatus, shouldAttachDebugReport, getSummaryDateParts, formatSummaryIsoDayKey, unescapeHtml, stripTelegramHtml, buildSignalsSummaryAttachment, appendReportAttachmentSummary, resolveSummaryConnectorName, groupRuntimeTradesByConnectorScope, syncRuntimeTradeScopes, createRuntimeSignalStats, mergeRuntimeSignalStats, buildSummaryPrelude, resolveTradeStatusEmoji, isTimestampInWindow, isRuntimeTradeClosedInWindow, buildSummaryMessages, signalsSummary, main53;
|
|
47363
47441
|
var init_signalsSummary = __esm({
|
|
47364
47442
|
"src/scripts/signalsSummary.ts"() {
|
|
47365
47443
|
"use strict";
|
|
47366
47444
|
import_config13 = require("dotenv/config");
|
|
47367
47445
|
import_userSettings8 = require("@tradejs/infra/userSettings");
|
|
47368
47446
|
import_args38 = __toESM(require("args"));
|
|
47369
|
-
|
|
47447
|
+
import_logger13 = require("@tradejs/infra/logger");
|
|
47370
47448
|
import_connectors19 = require("@tradejs/node/connectors");
|
|
47371
47449
|
init_runtimeRedis();
|
|
47372
47450
|
init_runtimeTradeSync();
|
|
@@ -47482,7 +47560,7 @@ var init_signalsSummary = __esm({
|
|
|
47482
47560
|
if (connectorName) {
|
|
47483
47561
|
return connectorName;
|
|
47484
47562
|
}
|
|
47485
|
-
|
|
47563
|
+
import_logger13.logger.warn(
|
|
47486
47564
|
'Unknown connector "%s". Fallback to %s.',
|
|
47487
47565
|
String(value || "").trim() || String(value),
|
|
47488
47566
|
import_connectors19.DEFAULT_CONNECTOR_NAME
|
|
@@ -47564,7 +47642,7 @@ var init_signalsSummary = __esm({
|
|
|
47564
47642
|
endTime,
|
|
47565
47643
|
openPositionCallbacks: {
|
|
47566
47644
|
onError: (error) => {
|
|
47567
|
-
|
|
47645
|
+
import_logger13.logger.warn(
|
|
47568
47646
|
"signals summary: getOpenPositionPnl failed for scope account=%s deployment=%s: %s",
|
|
47569
47647
|
scope.accountId ?? "default",
|
|
47570
47648
|
scope.deploymentId ?? "default",
|
|
@@ -47574,7 +47652,7 @@ var init_signalsSummary = __esm({
|
|
|
47574
47652
|
},
|
|
47575
47653
|
closedPnlCallbacks: {
|
|
47576
47654
|
onError: (error) => {
|
|
47577
|
-
|
|
47655
|
+
import_logger13.logger.warn(
|
|
47578
47656
|
"signals summary: getClosedPnl failed for scope account=%s deployment=%s: %s",
|
|
47579
47657
|
scope.accountId ?? "default",
|
|
47580
47658
|
scope.deploymentId ?? "default",
|
|
@@ -47988,7 +48066,7 @@ none`
|
|
|
47988
48066
|
(sum3, stats) => sum3 + stats.evaluated,
|
|
47989
48067
|
0
|
|
47990
48068
|
);
|
|
47991
|
-
|
|
48069
|
+
import_logger13.logger.info(
|
|
47992
48070
|
"signals summary deployment=%s window=%sh signals=%s evaluations=%s trades=%s connectors=%s scopes=%s user=%s",
|
|
47993
48071
|
scope.deploymentId ?? "legacy",
|
|
47994
48072
|
hours,
|
|
@@ -48055,17 +48133,17 @@ var test_ml_exports = {};
|
|
|
48055
48133
|
__export(test_ml_exports, {
|
|
48056
48134
|
main: () => main54
|
|
48057
48135
|
});
|
|
48058
|
-
var import_config14,
|
|
48136
|
+
var import_config14, import_constants22, import_ml3, import_registry6, now, INTERVAL_MIN, CANDLES, makeSeries, makeCandles, buildTrendline, main54;
|
|
48059
48137
|
var init_test_ml = __esm({
|
|
48060
48138
|
"src/scripts/test-ml.ts"() {
|
|
48061
48139
|
"use strict";
|
|
48062
48140
|
import_config14 = require("dotenv/config");
|
|
48063
|
-
|
|
48141
|
+
import_constants22 = require("@tradejs/core/constants");
|
|
48064
48142
|
import_ml3 = require("@tradejs/infra/ml");
|
|
48065
48143
|
import_registry6 = require("@tradejs/node/registry");
|
|
48066
48144
|
now = Date.now();
|
|
48067
48145
|
INTERVAL_MIN = 15;
|
|
48068
|
-
CANDLES =
|
|
48146
|
+
CANDLES = import_constants22.ML_BASE_CANDLES_WINDOW;
|
|
48069
48147
|
makeSeries = (len, base, step = 0.1) => Array.from({ length: len }, (_3, i) => base + i * step);
|
|
48070
48148
|
makeCandles = (startPrice, startTs) => {
|
|
48071
48149
|
const candles = [];
|
|
@@ -48137,8 +48215,8 @@ var init_test_ml = __esm({
|
|
|
48137
48215
|
correlation: 0.18,
|
|
48138
48216
|
touches: 6,
|
|
48139
48217
|
distance: 0.7,
|
|
48140
|
-
candles15m: candles.slice(-
|
|
48141
|
-
btcCandles15m: btcCandles.slice(-
|
|
48218
|
+
candles15m: candles.slice(-import_constants22.ML_BASE_CANDLES_WINDOW),
|
|
48219
|
+
btcCandles15m: btcCandles.slice(-import_constants22.ML_BASE_CANDLES_WINDOW),
|
|
48142
48220
|
atr: makeSeries(10, 1.2, 0.02),
|
|
48143
48221
|
atrPct: makeSeries(10, 1.05, 5e-3),
|
|
48144
48222
|
maFast: makeSeries(10, currentPrice * 0.995, 0.01),
|
|
@@ -48224,14 +48302,14 @@ var user_add_exports = {};
|
|
|
48224
48302
|
__export(user_add_exports, {
|
|
48225
48303
|
main: () => main56
|
|
48226
48304
|
});
|
|
48227
|
-
var import_args39, import_chalk55, import_bcryptjs,
|
|
48305
|
+
var import_args39, import_chalk55, import_bcryptjs, import_redis26, flags35, main56;
|
|
48228
48306
|
var init_user_add = __esm({
|
|
48229
48307
|
"src/scripts/user-add.ts"() {
|
|
48230
48308
|
"use strict";
|
|
48231
48309
|
import_args39 = __toESM(require("args"));
|
|
48232
48310
|
import_chalk55 = __toESM(require("chalk"));
|
|
48233
48311
|
import_bcryptjs = __toESM(require("bcryptjs"));
|
|
48234
|
-
|
|
48312
|
+
import_redis26 = require("@tradejs/infra/redis");
|
|
48235
48313
|
import_args39.default.example("yarn user-add -u myname -p 123456", "Create or update user");
|
|
48236
48314
|
import_args39.default.option(["u", "user"], "Username", "");
|
|
48237
48315
|
import_args39.default.option(["p", "password"], "Password (plain text)", "");
|
|
@@ -48244,14 +48322,14 @@ var init_user_add = __esm({
|
|
|
48244
48322
|
process.exit(1);
|
|
48245
48323
|
}
|
|
48246
48324
|
const passwordHash = await import_bcryptjs.default.hash(password, 10);
|
|
48247
|
-
const existing = await (0,
|
|
48325
|
+
const existing = await (0, import_redis26.getData)(import_redis26.redisKeys.user(userName3), null);
|
|
48248
48326
|
const next = {
|
|
48249
48327
|
...existing ?? {},
|
|
48250
48328
|
passwordHash,
|
|
48251
48329
|
userName: userName3,
|
|
48252
48330
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
48253
48331
|
};
|
|
48254
|
-
await (0,
|
|
48332
|
+
await (0, import_redis26.setData)(import_redis26.redisKeys.user(userName3), next, {
|
|
48255
48333
|
expire: 0
|
|
48256
48334
|
});
|
|
48257
48335
|
console.log(import_chalk55.default.green(`User ${userName3} updated`));
|
|
@@ -48270,7 +48348,7 @@ __export(cli_exports, {
|
|
|
48270
48348
|
});
|
|
48271
48349
|
module.exports = __toCommonJS(cli_exports);
|
|
48272
48350
|
var import_config16 = require("dotenv/config");
|
|
48273
|
-
var
|
|
48351
|
+
var import_redis27 = require("@tradejs/infra/redis");
|
|
48274
48352
|
var import_client9 = require("@tradejs/infra/timescale/client");
|
|
48275
48353
|
var scriptLoaders = {
|
|
48276
48354
|
"research-visuals": () => Promise.resolve().then(() => (init_researchVisuals2(), researchVisuals_exports)),
|
|
@@ -48345,7 +48423,7 @@ var runLoadedModule = async (loaded) => {
|
|
|
48345
48423
|
}
|
|
48346
48424
|
};
|
|
48347
48425
|
var cleanupCliResources = async () => {
|
|
48348
|
-
await Promise.allSettled([(0,
|
|
48426
|
+
await Promise.allSettled([(0, import_redis27.closeRedisConnection)(), (0, import_client9.closeTimescalePool)()]);
|
|
48349
48427
|
};
|
|
48350
48428
|
var main57 = async () => {
|
|
48351
48429
|
const [, scriptPath, command = "", ...args40] = process.argv;
|