@tradejs/cli 2.0.6 → 2.0.8
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 +2448 -1374
- package/dist/lib/aiExport.js +1822 -0
- package/dist/lib/binanceMarketContextBackfill.js +97 -88
- package/dist/lib/binanceMarketData.js +6 -3
- package/dist/lib/marketContextPrepare.js +97 -88
- package/dist/lib/runEnvironment.js +48 -18
- package/dist/lib/runtimeLineage.js +255 -0
- package/dist/lib/runtimeParityDetails.js +24 -1
- package/dist/lib/runtimeSignalsLoader.js +19 -0
- package/dist/lib/runtimeSignalsStorage.js +3 -0
- package/dist/lib/runtimeTradeSync.js +40 -11
- package/dist/lib/timeWindow.js +44 -16
- package/dist/scripts/aiExport.js +200 -88
- package/dist/scripts/backtest.js +170 -107
- package/dist/scripts/binanceBreadthUniversesUpdate.js +120 -0
- package/dist/scripts/binanceMarketIngest.js +32 -33
- package/dist/scripts/mlExport.js +5 -2
- package/dist/scripts/replay.js +988 -218
- package/dist/scripts/replayRunner.js +988 -218
- package/dist/scripts/replayRuntimeEvidence.js +3 -1
- package/dist/scripts/resolveExportStrategy.js +7 -2
- package/dist/scripts/runtimeParity.js +141 -104
- package/dist/scripts/signals.js +381 -107
- package/dist/scripts/signalsDaemon.js +381 -107
- package/dist/scripts/signalsSummary.js +40 -11
- package/package.json +10 -9
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/lib/runtimeLineage.ts
|
|
31
|
+
var runtimeLineage_exports = {};
|
|
32
|
+
__export(runtimeLineage_exports, {
|
|
33
|
+
buildRuntimeLineage: () => buildRuntimeLineage,
|
|
34
|
+
fingerprintRuntimeValue: () => fingerprintRuntimeValue,
|
|
35
|
+
resetRuntimeLineageCachesForTests: () => resetRuntimeLineageCachesForTests,
|
|
36
|
+
runtimeLineageKey: () => runtimeLineageKey,
|
|
37
|
+
runtimeLineagesMatch: () => runtimeLineagesMatch
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(runtimeLineage_exports);
|
|
40
|
+
var import_node_child_process = require("child_process");
|
|
41
|
+
var import_node_crypto = require("crypto");
|
|
42
|
+
var import_promises = __toESM(require("fs/promises"));
|
|
43
|
+
var import_node_path = __toESM(require("path"));
|
|
44
|
+
var RUNTIME_CONTEXT_ENV_KEYS = [
|
|
45
|
+
"AI_MODE",
|
|
46
|
+
"MIN_AI_QUALITY",
|
|
47
|
+
"INTERVAL",
|
|
48
|
+
"DERIVATIVES_CONTEXT_ENABLED",
|
|
49
|
+
"DERIVATIVES_CONTEXT_TARGET_ENABLED",
|
|
50
|
+
"DERIVATIVES_CONTEXT_LOOKBACK_HOURS",
|
|
51
|
+
"DERIVATIVES_CONTEXT_EXTRA_REFERENCE_SYMBOLS",
|
|
52
|
+
"DERIVATIVES_CONTEXT_EXCHANGE_PRIORITY",
|
|
53
|
+
"COINMARKETCAP_CONTEXT_ENABLED",
|
|
54
|
+
"COINMARKETCAP_CONTEXT_MAX_AGE_MS",
|
|
55
|
+
"COINMARKETCAP_CONTEXT_EXCHANGE_LIQUIDITY_ENABLED",
|
|
56
|
+
"COINMARKETCAP_CONTEXT_EXCHANGE_SLUGS",
|
|
57
|
+
"COINMARKETCAP_CONTEXT_FEAR_GREED_ENABLED",
|
|
58
|
+
"COINMARKETCAP_CONTEXT_HISTORICAL_ACCESS_MONTHS",
|
|
59
|
+
"COINMARKETCAP_CONTEXT_BACKFILL_ENABLED",
|
|
60
|
+
"COINMARKETCAP_CONTEXT_BACKFILL_MAX_DAYS",
|
|
61
|
+
"COINMARKETCAP_CONTEXT_BACKFILL_WARMUP_DAYS"
|
|
62
|
+
];
|
|
63
|
+
var RUNTIME_CONTEXT_DATA_MODEL = {
|
|
64
|
+
derivativesSourceIntervals: "15m",
|
|
65
|
+
derivativesDerivedIntervals: "1h",
|
|
66
|
+
derivativesHourlyFallback: "stored-1h",
|
|
67
|
+
derivativesDataModelVersion: 2,
|
|
68
|
+
coinMarketCapAvailabilityModel: "closed-interval-all-daily",
|
|
69
|
+
coinMarketCapDataModelVersion: 3,
|
|
70
|
+
binanceBreadthUniverseModel: "fixed-versioned-top5-top10-top30-top50-top100",
|
|
71
|
+
binanceBreadthDataModelVersion: 2
|
|
72
|
+
};
|
|
73
|
+
var normalizeForStableJson = (value) => {
|
|
74
|
+
if (Array.isArray(value)) {
|
|
75
|
+
return value.map(normalizeForStableJson);
|
|
76
|
+
}
|
|
77
|
+
if (value && typeof value === "object") {
|
|
78
|
+
return Object.fromEntries(
|
|
79
|
+
Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, normalizeForStableJson(entry)])
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
return value;
|
|
83
|
+
};
|
|
84
|
+
var fingerprintRuntimeValue = (value) => (0, import_node_crypto.createHash)("sha256").update(JSON.stringify(normalizeForStableJson(value))).digest("hex").slice(0, 16);
|
|
85
|
+
var gitLineageCache = /* @__PURE__ */ new Map();
|
|
86
|
+
var gateFingerprintCache = /* @__PURE__ */ new Map();
|
|
87
|
+
var binanceBreadthFingerprintCache = /* @__PURE__ */ new Map();
|
|
88
|
+
var resolveGitLineage = (projectRoot) => {
|
|
89
|
+
const cached = gitLineageCache.get(projectRoot);
|
|
90
|
+
if (cached) {
|
|
91
|
+
return cached;
|
|
92
|
+
}
|
|
93
|
+
const envSha = String(process.env.TRADEJS_GIT_SHA ?? "").trim();
|
|
94
|
+
if (envSha && envSha !== "unknown") {
|
|
95
|
+
const result = {
|
|
96
|
+
gitSha: envSha,
|
|
97
|
+
gitDirty: false
|
|
98
|
+
};
|
|
99
|
+
gitLineageCache.set(projectRoot, result);
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
const gitSha = (0, import_node_child_process.execFileSync)("git", ["rev-parse", "HEAD"], {
|
|
104
|
+
cwd: projectRoot,
|
|
105
|
+
encoding: "utf8",
|
|
106
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
107
|
+
}).trim();
|
|
108
|
+
const status = (0, import_node_child_process.execFileSync)(
|
|
109
|
+
"git",
|
|
110
|
+
["status", "--porcelain", "--untracked-files=normal"],
|
|
111
|
+
{
|
|
112
|
+
cwd: projectRoot,
|
|
113
|
+
encoding: "utf8",
|
|
114
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
115
|
+
}
|
|
116
|
+
).trim();
|
|
117
|
+
const result = {
|
|
118
|
+
gitSha: gitSha || null,
|
|
119
|
+
gitDirty: status.length > 0
|
|
120
|
+
};
|
|
121
|
+
gitLineageCache.set(projectRoot, result);
|
|
122
|
+
return result;
|
|
123
|
+
} catch {
|
|
124
|
+
const result = {
|
|
125
|
+
gitSha: null,
|
|
126
|
+
gitDirty: null
|
|
127
|
+
};
|
|
128
|
+
gitLineageCache.set(projectRoot, result);
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
var readOptionalFile = async (filePath) => {
|
|
133
|
+
try {
|
|
134
|
+
return await import_promises.default.readFile(filePath);
|
|
135
|
+
} catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
var resolveBinanceBreadthFingerprint = async (projectRoot) => {
|
|
140
|
+
if (binanceBreadthFingerprintCache.has(projectRoot)) {
|
|
141
|
+
return binanceBreadthFingerprintCache.get(projectRoot) ?? null;
|
|
142
|
+
}
|
|
143
|
+
const content = await readOptionalFile(
|
|
144
|
+
import_node_path.default.join(
|
|
145
|
+
projectRoot,
|
|
146
|
+
"packages/node/src/config/binanceBreadthUniverses.json"
|
|
147
|
+
)
|
|
148
|
+
);
|
|
149
|
+
let result = null;
|
|
150
|
+
if (content) {
|
|
151
|
+
try {
|
|
152
|
+
const parsed = JSON.parse(content.toString("utf8"));
|
|
153
|
+
result = typeof parsed.fingerprint === "string" && parsed.fingerprint.trim() ? parsed.fingerprint.trim() : null;
|
|
154
|
+
} catch {
|
|
155
|
+
result = null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
binanceBreadthFingerprintCache.set(projectRoot, result);
|
|
159
|
+
return result;
|
|
160
|
+
};
|
|
161
|
+
var resolveGateFingerprint = async ({
|
|
162
|
+
projectRoot,
|
|
163
|
+
strategyName,
|
|
164
|
+
gitSha
|
|
165
|
+
}) => {
|
|
166
|
+
const cacheKey = `${projectRoot}:${strategyName}:${gitSha ?? "unknown"}`;
|
|
167
|
+
const cached = gateFingerprintCache.get(cacheKey);
|
|
168
|
+
if (cached) {
|
|
169
|
+
return cached;
|
|
170
|
+
}
|
|
171
|
+
const relativeCandidates = [
|
|
172
|
+
`packages/strategies/src/${strategyName}/adapters/ai.ts`,
|
|
173
|
+
`packages/strategies/src/${strategyName}/guardrails.ts`,
|
|
174
|
+
`packages/strategies/src/${strategyName}/pockets.ts`,
|
|
175
|
+
`packages/strategies/src/${strategyName}/config.ts`,
|
|
176
|
+
"packages/node/src/ai.ts"
|
|
177
|
+
];
|
|
178
|
+
const optionalEntries = await Promise.all(
|
|
179
|
+
relativeCandidates.map(async (relativePath) => {
|
|
180
|
+
const content = await readOptionalFile(
|
|
181
|
+
import_node_path.default.join(projectRoot, relativePath)
|
|
182
|
+
);
|
|
183
|
+
return content == null ? null : { relativePath, content };
|
|
184
|
+
})
|
|
185
|
+
);
|
|
186
|
+
const sourceEntries = [];
|
|
187
|
+
for (const entry of optionalEntries) {
|
|
188
|
+
if (entry != null) {
|
|
189
|
+
sourceEntries.push(entry);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
193
|
+
hash.update(strategyName);
|
|
194
|
+
if (sourceEntries.length) {
|
|
195
|
+
for (const entry of sourceEntries) {
|
|
196
|
+
hash.update(entry.relativePath);
|
|
197
|
+
hash.update(entry.content);
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
hash.update(gitSha ?? "unknown-git-sha");
|
|
201
|
+
}
|
|
202
|
+
const fingerprint = hash.digest("hex").slice(0, 16);
|
|
203
|
+
gateFingerprintCache.set(cacheKey, fingerprint);
|
|
204
|
+
return fingerprint;
|
|
205
|
+
};
|
|
206
|
+
var buildRuntimeLineage = async ({
|
|
207
|
+
projectRoot,
|
|
208
|
+
strategyName,
|
|
209
|
+
config,
|
|
210
|
+
runContext,
|
|
211
|
+
env = process.env
|
|
212
|
+
}) => {
|
|
213
|
+
const git = resolveGitLineage(projectRoot);
|
|
214
|
+
const context = {
|
|
215
|
+
...Object.fromEntries(
|
|
216
|
+
RUNTIME_CONTEXT_ENV_KEYS.map((key) => [key, env[key] ?? null])
|
|
217
|
+
),
|
|
218
|
+
...RUNTIME_CONTEXT_DATA_MODEL,
|
|
219
|
+
binanceBreadthUniverseFingerprint: await resolveBinanceBreadthFingerprint(projectRoot),
|
|
220
|
+
...runContext
|
|
221
|
+
};
|
|
222
|
+
return {
|
|
223
|
+
schemaVersion: 1,
|
|
224
|
+
...git,
|
|
225
|
+
gateFingerprint: await resolveGateFingerprint({
|
|
226
|
+
projectRoot,
|
|
227
|
+
strategyName,
|
|
228
|
+
gitSha: git.gitSha
|
|
229
|
+
}),
|
|
230
|
+
configFingerprint: fingerprintRuntimeValue(config),
|
|
231
|
+
contextFingerprint: fingerprintRuntimeValue(context)
|
|
232
|
+
};
|
|
233
|
+
};
|
|
234
|
+
var runtimeLineageKey = (lineage) => [
|
|
235
|
+
lineage.schemaVersion,
|
|
236
|
+
lineage.gitSha ?? "unknown",
|
|
237
|
+
lineage.gitDirty == null ? "unknown" : lineage.gitDirty ? "dirty" : "clean",
|
|
238
|
+
lineage.gateFingerprint,
|
|
239
|
+
lineage.configFingerprint,
|
|
240
|
+
lineage.contextFingerprint
|
|
241
|
+
].join(":");
|
|
242
|
+
var runtimeLineagesMatch = (left, right) => left != null && right != null && runtimeLineageKey(left) === runtimeLineageKey(right);
|
|
243
|
+
var resetRuntimeLineageCachesForTests = () => {
|
|
244
|
+
gitLineageCache.clear();
|
|
245
|
+
gateFingerprintCache.clear();
|
|
246
|
+
binanceBreadthFingerprintCache.clear();
|
|
247
|
+
};
|
|
248
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
249
|
+
0 && (module.exports = {
|
|
250
|
+
buildRuntimeLineage,
|
|
251
|
+
fingerprintRuntimeValue,
|
|
252
|
+
resetRuntimeLineageCachesForTests,
|
|
253
|
+
runtimeLineageKey,
|
|
254
|
+
runtimeLineagesMatch
|
|
255
|
+
});
|
|
@@ -639,6 +639,7 @@ var buildReplayRuntimeComparisonDetails = ({
|
|
|
639
639
|
),
|
|
640
640
|
limit
|
|
641
641
|
),
|
|
642
|
+
orderFailed: [],
|
|
642
643
|
runtimeOnly: cappedRuntimeOnlyDetails,
|
|
643
644
|
backtestOnly: cappedBacktestOnlyDetails,
|
|
644
645
|
nearestCandidates: cappedNearestCandidates,
|
|
@@ -658,6 +659,7 @@ var buildReplayRuntimeComparisonDetails = ({
|
|
|
658
659
|
};
|
|
659
660
|
var buildReplayExchangeComparisonDetails = ({
|
|
660
661
|
matched,
|
|
662
|
+
orderFailed = [],
|
|
661
663
|
exchangeOnly,
|
|
662
664
|
backtestOnly,
|
|
663
665
|
exchangeEntries,
|
|
@@ -708,7 +710,7 @@ var buildReplayExchangeComparisonDetails = ({
|
|
|
708
710
|
limit
|
|
709
711
|
);
|
|
710
712
|
return {
|
|
711
|
-
capped: matched.length > limit || exchangeOnlyDetails.length > limit || backtestOnlyDetails.length > limit || nearestCandidates.length > limit,
|
|
713
|
+
capped: matched.length > limit || orderFailed.length > limit || exchangeOnlyDetails.length > limit || backtestOnlyDetails.length > limit || nearestCandidates.length > limit,
|
|
712
714
|
limit,
|
|
713
715
|
matched: capReplayDetails(
|
|
714
716
|
matched.map(
|
|
@@ -724,6 +726,27 @@ var buildReplayExchangeComparisonDetails = ({
|
|
|
724
726
|
),
|
|
725
727
|
limit
|
|
726
728
|
),
|
|
729
|
+
orderFailed: capReplayDetails(
|
|
730
|
+
orderFailed.map((item) => {
|
|
731
|
+
const detail = buildMatchedReplayDetail({
|
|
732
|
+
runtime: toExchangeDetail(item.exchange),
|
|
733
|
+
backtest: toBacktestParityDetail(
|
|
734
|
+
item.backtest,
|
|
735
|
+
backtestTimestampOffsetMs
|
|
736
|
+
),
|
|
737
|
+
timestampDiffMs: item.timestampDiffMs,
|
|
738
|
+
priceDeltaPct: item.priceDeltaPct
|
|
739
|
+
});
|
|
740
|
+
return {
|
|
741
|
+
runtime: detail.runtime,
|
|
742
|
+
backtest: detail.backtest,
|
|
743
|
+
timestampDiffMs: detail.timestampDiffMs,
|
|
744
|
+
priceDeltaPct: detail.priceDeltaPct,
|
|
745
|
+
reason: item.reason
|
|
746
|
+
};
|
|
747
|
+
}),
|
|
748
|
+
limit
|
|
749
|
+
),
|
|
727
750
|
runtimeOnly: cappedExchangeOnlyDetails,
|
|
728
751
|
backtestOnly: cappedBacktestOnlyDetails,
|
|
729
752
|
nearestCandidates: cappedNearestCandidates,
|
|
@@ -22,6 +22,7 @@ var runtimeSignalsLoader_exports = {};
|
|
|
22
22
|
__export(runtimeSignalsLoader_exports, {
|
|
23
23
|
isRuntimeSignalEvaluationRecord: () => isRuntimeSignalEvaluationRecord,
|
|
24
24
|
isSignalRecord: () => isSignalRecord,
|
|
25
|
+
loadRuntimeLineageScopes: () => loadRuntimeLineageScopes,
|
|
25
26
|
loadRuntimeSignalEvaluationStatsBuckets: () => loadRuntimeSignalEvaluationStatsBuckets,
|
|
26
27
|
loadRuntimeSignalEvaluations: () => loadRuntimeSignalEvaluations,
|
|
27
28
|
loadRuntimeSignals: () => loadRuntimeSignals
|
|
@@ -145,6 +146,23 @@ var loadRuntimeSignalEvaluations = async (userName, {
|
|
|
145
146
|
}
|
|
146
147
|
return sortByTimestamp([...deduped.values()]);
|
|
147
148
|
};
|
|
149
|
+
var loadRuntimeLineageScopes = async (userName, {
|
|
150
|
+
startTime,
|
|
151
|
+
endTime
|
|
152
|
+
}) => {
|
|
153
|
+
const records = (await Promise.all(
|
|
154
|
+
(0, import_time.getRuntimeStorageDayKeys)(startTime, endTime).map(
|
|
155
|
+
(dayKey) => (0, import_redis.getHashJsonValues)(
|
|
156
|
+
import_redis.redisKeys.runtimeLineageScopeBucket(userName, dayKey)
|
|
157
|
+
)
|
|
158
|
+
)
|
|
159
|
+
)).flat().filter(
|
|
160
|
+
(record) => record != null && typeof record.strategy === "string" && typeof record.symbol === "string" && typeof record.firstTimestamp === "number" && typeof record.lastTimestamp === "number" && record.lineage != null
|
|
161
|
+
);
|
|
162
|
+
return records.sort(
|
|
163
|
+
(left, right) => left.firstTimestamp - right.firstTimestamp || left.strategy.localeCompare(right.strategy) || left.symbol.localeCompare(right.symbol)
|
|
164
|
+
);
|
|
165
|
+
};
|
|
148
166
|
var parseBucketKey = (prefix, key) => {
|
|
149
167
|
if (!key.startsWith(prefix)) {
|
|
150
168
|
return null;
|
|
@@ -181,6 +199,7 @@ var loadRuntimeSignalEvaluationStatsBuckets = async (userName) => {
|
|
|
181
199
|
0 && (module.exports = {
|
|
182
200
|
isRuntimeSignalEvaluationRecord,
|
|
183
201
|
isSignalRecord,
|
|
202
|
+
loadRuntimeLineageScopes,
|
|
184
203
|
loadRuntimeSignalEvaluationStatsBuckets,
|
|
185
204
|
loadRuntimeSignalEvaluations,
|
|
186
205
|
loadRuntimeSignals
|
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var runtimeSignalsStorage_exports = {};
|
|
22
22
|
__export(runtimeSignalsStorage_exports, {
|
|
23
23
|
DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS: () => DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS,
|
|
24
|
+
RUNTIME_LINEAGE_SCOPE_RETENTION_TTL_SECONDS: () => RUNTIME_LINEAGE_SCOPE_RETENTION_TTL_SECONDS,
|
|
24
25
|
RUNTIME_SIGNAL_RETENTION_DAYS_ENV: () => RUNTIME_SIGNAL_RETENTION_DAYS_ENV,
|
|
25
26
|
buildRuntimeSignalStatsIncrements: () => buildRuntimeSignalStatsIncrements,
|
|
26
27
|
getRuntimeSignalRetentionTtlSeconds: () => getRuntimeSignalRetentionTtlSeconds,
|
|
@@ -40,6 +41,7 @@ var import_time = require("@tradejs/core/time");
|
|
|
40
41
|
var SECONDS_PER_DAY = 86400;
|
|
41
42
|
var RUNTIME_SIGNAL_RETENTION_DAYS_ENV = "RUNTIME_SIGNAL_RETENTION_DAYS";
|
|
42
43
|
var DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS = import_constants.TTL_3D;
|
|
44
|
+
var RUNTIME_LINEAGE_SCOPE_RETENTION_TTL_SECONDS = import_constants.TTL_1M;
|
|
43
45
|
var parsePositiveNumber = (value) => {
|
|
44
46
|
if (value == null || value === "") {
|
|
45
47
|
return null;
|
|
@@ -170,6 +172,7 @@ var parseRuntimeSignalStatsBucket = (value) => {
|
|
|
170
172
|
// Annotate the CommonJS export names for ESM import in node:
|
|
171
173
|
0 && (module.exports = {
|
|
172
174
|
DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS,
|
|
175
|
+
RUNTIME_LINEAGE_SCOPE_RETENTION_TTL_SECONDS,
|
|
173
176
|
RUNTIME_SIGNAL_RETENTION_DAYS_ENV,
|
|
174
177
|
buildRuntimeSignalStatsIncrements,
|
|
175
178
|
getRuntimeSignalRetentionTtlSeconds,
|
|
@@ -125,6 +125,18 @@ var consumeClosedPnlMatch = (buckets, trade) => {
|
|
|
125
125
|
const [row] = rows.splice(matchIndex, 1);
|
|
126
126
|
return row ?? null;
|
|
127
127
|
};
|
|
128
|
+
var isRuntimeTradeInConnectorScope = (trade, connector) => {
|
|
129
|
+
if (trade.deploymentId && trade.deploymentId !== connector.deploymentId) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
if (trade.accountId && trade.accountId !== connector.accountId) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
if (trade.universe && connector.universe && trade.universe !== connector.universe) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
return true;
|
|
139
|
+
};
|
|
128
140
|
var syncRuntimeTrades = async ({
|
|
129
141
|
userName,
|
|
130
142
|
connector,
|
|
@@ -148,16 +160,23 @@ var syncRuntimeTrades = async ({
|
|
|
148
160
|
const openPositionsBySymbol = new Map(
|
|
149
161
|
openPositions.map((position) => [position.symbol, position])
|
|
150
162
|
);
|
|
151
|
-
const
|
|
152
|
-
const
|
|
163
|
+
const activeOrderIdByKey = /* @__PURE__ */ new Map();
|
|
164
|
+
const activeTradeKeys = [
|
|
165
|
+
...new Set(
|
|
166
|
+
trades.filter((trade) => isRuntimeTradeInConnectorScope(trade, connector)).map(
|
|
167
|
+
(trade) => import_redis.redisKeys.runtimeActiveTrade(
|
|
168
|
+
userName,
|
|
169
|
+
trade.symbol,
|
|
170
|
+
trade.deploymentId ?? trade.accountId
|
|
171
|
+
)
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
];
|
|
153
175
|
await Promise.all(
|
|
154
|
-
|
|
155
|
-
const activeRef = await (0, import_redis.getData)(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
);
|
|
159
|
-
activeOrderIdBySymbol.set(
|
|
160
|
-
symbol,
|
|
176
|
+
activeTradeKeys.map(async (key) => {
|
|
177
|
+
const activeRef = await (0, import_redis.getData)(key, null);
|
|
178
|
+
activeOrderIdByKey.set(
|
|
179
|
+
key,
|
|
161
180
|
typeof activeRef?.orderId === "string" ? activeRef.orderId : null
|
|
162
181
|
);
|
|
163
182
|
})
|
|
@@ -176,12 +195,21 @@ var syncRuntimeTrades = async ({
|
|
|
176
195
|
}
|
|
177
196
|
const syncedTrades = [];
|
|
178
197
|
for (const trade of trades) {
|
|
198
|
+
if (!isRuntimeTradeInConnectorScope(trade, connector)) {
|
|
199
|
+
syncedTrades.push(trade);
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
179
202
|
if (trade.status !== "active" && !isRuntimeTradeSyncFallbackClose(trade)) {
|
|
180
203
|
syncedTrades.push(trade);
|
|
181
204
|
continue;
|
|
182
205
|
}
|
|
206
|
+
const activeTradeKey = import_redis.redisKeys.runtimeActiveTrade(
|
|
207
|
+
userName,
|
|
208
|
+
trade.symbol,
|
|
209
|
+
trade.deploymentId ?? trade.accountId
|
|
210
|
+
);
|
|
183
211
|
const openPosition = openPositionsBySymbol.get(trade.symbol);
|
|
184
|
-
const activeOrderId =
|
|
212
|
+
const activeOrderId = activeOrderIdByKey.get(activeTradeKey);
|
|
185
213
|
const isCurrentActiveTrade = activeOrderId === trade.orderId;
|
|
186
214
|
if (trade.status === "active" && !openPositionsReliable) {
|
|
187
215
|
syncedTrades.push({
|
|
@@ -220,6 +248,7 @@ var syncRuntimeTrades = async ({
|
|
|
220
248
|
}
|
|
221
249
|
const matchedClosedPnl = consumeClosedPnlMatch(closedPnlBuckets, trade);
|
|
222
250
|
if (!matchedClosedPnl) {
|
|
251
|
+
syncedTrades.push(trade);
|
|
223
252
|
continue;
|
|
224
253
|
}
|
|
225
254
|
const nextTrade = {
|
|
@@ -252,7 +281,7 @@ var syncRuntimeTrades = async ({
|
|
|
252
281
|
nextTrade,
|
|
253
282
|
{ expire: import_constants.TTL_1M }
|
|
254
283
|
),
|
|
255
|
-
...isCurrentActiveTrade ? [(0, import_redis.delKey)(
|
|
284
|
+
...isCurrentActiveTrade ? [(0, import_redis.delKey)(activeTradeKey)] : []
|
|
256
285
|
]);
|
|
257
286
|
syncedTrades.push(nextTrade);
|
|
258
287
|
}
|
package/dist/lib/timeWindow.js
CHANGED
|
@@ -50,11 +50,30 @@ var resolveTimeWindow = ({
|
|
|
50
50
|
endTime,
|
|
51
51
|
nowMs = Date.now(),
|
|
52
52
|
defaultStartMs,
|
|
53
|
-
defaultEndMs
|
|
53
|
+
defaultEndMs,
|
|
54
|
+
closedIntervalMs
|
|
54
55
|
}) => {
|
|
55
56
|
const explicitStart = toEpochMs(startTime);
|
|
56
57
|
const explicitEnd = toEpochMs(endTime);
|
|
57
58
|
const resolvedDays = toPositiveNumber(days);
|
|
59
|
+
const alignToLastClosedInterval = (window, preserveDuration) => {
|
|
60
|
+
if (typeof closedIntervalMs !== "number" || !Number.isFinite(closedIntervalMs) || closedIntervalMs <= 0) {
|
|
61
|
+
return window;
|
|
62
|
+
}
|
|
63
|
+
const alignedEnd = Math.floor(window.end / closedIntervalMs) * closedIntervalMs - 1;
|
|
64
|
+
const delta = window.end - alignedEnd;
|
|
65
|
+
const alignedStart = preserveDuration ? window.start - delta : window.start;
|
|
66
|
+
if (alignedStart >= alignedEnd) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`Invalid closed-candle window: start (${alignedStart}) must be less than end (${alignedEnd})`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
...window,
|
|
73
|
+
start: Math.trunc(alignedStart),
|
|
74
|
+
end: Math.trunc(alignedEnd)
|
|
75
|
+
};
|
|
76
|
+
};
|
|
58
77
|
if (explicitStart != null || explicitEnd != null) {
|
|
59
78
|
const resolvedStart = explicitStart ?? (resolvedDays != null && explicitEnd != null ? explicitEnd - resolvedDays * ONE_DAY_MS : defaultStartMs);
|
|
60
79
|
const resolvedEnd2 = explicitEnd ?? (resolvedDays != null && explicitStart != null ? explicitStart + resolvedDays * ONE_DAY_MS : defaultEndMs ?? nowMs);
|
|
@@ -63,11 +82,14 @@ var resolveTimeWindow = ({
|
|
|
63
82
|
`Invalid time window: startTime (${resolvedStart}) must be less than endTime (${resolvedEnd2})`
|
|
64
83
|
);
|
|
65
84
|
}
|
|
66
|
-
return
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
85
|
+
return alignToLastClosedInterval(
|
|
86
|
+
{
|
|
87
|
+
start: resolvedStart,
|
|
88
|
+
end: resolvedEnd2,
|
|
89
|
+
source: "explicit"
|
|
90
|
+
},
|
|
91
|
+
explicitStart == null && resolvedDays != null
|
|
92
|
+
);
|
|
71
93
|
}
|
|
72
94
|
if (resolvedDays != null) {
|
|
73
95
|
const resolvedEnd2 = defaultEndMs ?? nowMs;
|
|
@@ -77,11 +99,14 @@ var resolveTimeWindow = ({
|
|
|
77
99
|
`Invalid time window: computed start (${resolvedStart}) must be less than end (${resolvedEnd2})`
|
|
78
100
|
);
|
|
79
101
|
}
|
|
80
|
-
return
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
102
|
+
return alignToLastClosedInterval(
|
|
103
|
+
{
|
|
104
|
+
start: Math.trunc(resolvedStart),
|
|
105
|
+
end: Math.trunc(resolvedEnd2),
|
|
106
|
+
source: "days"
|
|
107
|
+
},
|
|
108
|
+
true
|
|
109
|
+
);
|
|
85
110
|
}
|
|
86
111
|
const resolvedEnd = defaultEndMs ?? nowMs;
|
|
87
112
|
if (defaultStartMs >= resolvedEnd) {
|
|
@@ -89,11 +114,14 @@ var resolveTimeWindow = ({
|
|
|
89
114
|
`Invalid default time window: start (${defaultStartMs}) must be less than end (${resolvedEnd})`
|
|
90
115
|
);
|
|
91
116
|
}
|
|
92
|
-
return
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
117
|
+
return alignToLastClosedInterval(
|
|
118
|
+
{
|
|
119
|
+
start: Math.trunc(defaultStartMs),
|
|
120
|
+
end: Math.trunc(resolvedEnd),
|
|
121
|
+
source: "default"
|
|
122
|
+
},
|
|
123
|
+
true
|
|
124
|
+
);
|
|
97
125
|
};
|
|
98
126
|
// Annotate the CommonJS export names for ESM import in node:
|
|
99
127
|
0 && (module.exports = {
|