@tradejs/cli 2.0.15 → 2.0.17

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.
@@ -0,0 +1,335 @@
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/scripts/runtimeEvidenceSync.ts
31
+ var runtimeEvidenceSync_exports = {};
32
+ __export(runtimeEvidenceSync_exports, {
33
+ main: () => main,
34
+ runtimeEvidenceSync: () => runtimeEvidenceSync
35
+ });
36
+ module.exports = __toCommonJS(runtimeEvidenceSync_exports);
37
+ var import_node_path3 = __toESM(require("path"));
38
+ var import_args = __toESM(require("args"));
39
+ var import_chalk = __toESM(require("chalk"));
40
+
41
+ // src/lib/runtimeEvidenceSync.ts
42
+ var import_node_child_process = require("child_process");
43
+ var import_promises2 = __toESM(require("fs/promises"));
44
+ var import_node_path2 = __toESM(require("path"));
45
+ var import_node_util = require("util");
46
+
47
+ // src/lib/runtimeEvidenceArtifacts.ts
48
+ var import_node_crypto = require("crypto");
49
+ var import_promises = __toESM(require("fs/promises"));
50
+ var import_node_path = __toESM(require("path"));
51
+ var RUNTIME_EVIDENCE_MANIFEST_FILE = "manifest.json";
52
+ var RUNTIME_EVIDENCE_PAYLOAD_FILE = "runtime-evidence.json";
53
+ var RUNTIME_EVIDENCE_COMPLETE_FILE = ".complete";
54
+ var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
55
+ var sha256 = (value) => (0, import_node_crypto.createHash)("sha256").update(value).digest("hex");
56
+ var assertFiniteTimestamp = (value, label) => {
57
+ if (typeof value !== "number" || !Number.isFinite(value)) {
58
+ throw new Error(`Invalid runtime evidence ${label}`);
59
+ }
60
+ return value;
61
+ };
62
+ var parseManifest = (value) => {
63
+ const manifest = asRecord(value);
64
+ const window = asRecord(manifest?.window);
65
+ const payload = asRecord(manifest?.payload);
66
+ const counts = asRecord(manifest?.counts);
67
+ if (manifest?.schemaVersion !== 1 || manifest.reportType !== "runtime-evidence" || typeof manifest.artifactId !== "string" || typeof manifest.deploymentId !== "string" || typeof manifest.userName !== "string" || typeof manifest.createdAt !== "number" || payload?.file !== RUNTIME_EVIDENCE_PAYLOAD_FILE || typeof payload.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(payload.sha256) || typeof payload.bytes !== "number" || !Array.isArray(manifest.lineageKeys)) {
68
+ throw new Error("Invalid runtime evidence manifest");
69
+ }
70
+ return {
71
+ schemaVersion: 1,
72
+ artifactId: manifest.artifactId,
73
+ reportType: "runtime-evidence",
74
+ deploymentId: manifest.deploymentId,
75
+ userName: manifest.userName,
76
+ createdAt: manifest.createdAt,
77
+ window: {
78
+ startTime: assertFiniteTimestamp(window?.startTime, "window.startTime"),
79
+ endTime: assertFiniteTimestamp(window?.endTime, "window.endTime")
80
+ },
81
+ payload: {
82
+ file: RUNTIME_EVIDENCE_PAYLOAD_FILE,
83
+ sha256: payload.sha256,
84
+ bytes: payload.bytes
85
+ },
86
+ counts: Object.fromEntries(
87
+ Object.entries(counts ?? {}).filter(
88
+ (entry) => typeof entry[1] === "number" && Number.isFinite(entry[1])
89
+ )
90
+ ),
91
+ lineageKeys: manifest.lineageKeys.filter(
92
+ (value2) => typeof value2 === "string" && value2.length > 0
93
+ )
94
+ };
95
+ };
96
+ var verifyRuntimeEvidenceBundle = async (bundleDir) => {
97
+ const manifestPath = import_node_path.default.join(bundleDir, RUNTIME_EVIDENCE_MANIFEST_FILE);
98
+ const payloadPath = import_node_path.default.join(bundleDir, RUNTIME_EVIDENCE_PAYLOAD_FILE);
99
+ const completePath = import_node_path.default.join(bundleDir, RUNTIME_EVIDENCE_COMPLETE_FILE);
100
+ const [manifestText, payload, completeText] = await Promise.all([
101
+ import_promises.default.readFile(manifestPath, "utf8"),
102
+ import_promises.default.readFile(payloadPath),
103
+ import_promises.default.readFile(completePath, "utf8")
104
+ ]);
105
+ const manifest = parseManifest(JSON.parse(manifestText));
106
+ if (completeText.trim() !== manifest.artifactId) {
107
+ throw new Error(`Invalid completion marker in ${bundleDir}`);
108
+ }
109
+ if (payload.byteLength !== manifest.payload.bytes) {
110
+ throw new Error(`Runtime evidence size mismatch in ${bundleDir}`);
111
+ }
112
+ if (sha256(payload) !== manifest.payload.sha256) {
113
+ throw new Error(`Runtime evidence checksum mismatch in ${bundleDir}`);
114
+ }
115
+ const artifact = asRecord(JSON.parse(payload.toString("utf8")));
116
+ const artifactWindow = asRecord(artifact?.window);
117
+ if (artifact?.reportType !== "runtime-evidence" || artifactWindow?.startTime !== manifest.window.startTime || artifactWindow.endTime !== manifest.window.endTime) {
118
+ throw new Error(`Runtime evidence payload mismatch in ${bundleDir}`);
119
+ }
120
+ return {
121
+ bundleDir,
122
+ manifestPath,
123
+ payloadPath,
124
+ manifest,
125
+ artifact
126
+ };
127
+ };
128
+ var discoverRuntimeEvidenceBundles = async (rootDir) => {
129
+ const bundles = [];
130
+ const visit = async (directory, depth) => {
131
+ if (depth > 8) return;
132
+ let entries;
133
+ try {
134
+ entries = await import_promises.default.readdir(directory, { withFileTypes: true });
135
+ } catch (error) {
136
+ if (error.code === "ENOENT") return;
137
+ throw error;
138
+ }
139
+ const names = new Set(entries.map((entry) => entry.name));
140
+ if (names.has(RUNTIME_EVIDENCE_MANIFEST_FILE) && names.has(RUNTIME_EVIDENCE_PAYLOAD_FILE) && names.has(RUNTIME_EVIDENCE_COMPLETE_FILE)) {
141
+ bundles.push(directory);
142
+ return;
143
+ }
144
+ await Promise.all(
145
+ entries.filter(
146
+ (entry) => entry.isDirectory() && !entry.name.startsWith(".") && !entry.name.includes(".tmp-")
147
+ ).map((entry) => visit(import_node_path.default.join(directory, entry.name), depth + 1))
148
+ );
149
+ };
150
+ await visit(rootDir, 0);
151
+ return bundles.sort();
152
+ };
153
+
154
+ // src/lib/runtimeEvidenceSync.ts
155
+ var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
156
+ var isExistingDestinationError = (error) => {
157
+ const code = error.code;
158
+ return code === "EEXIST" || code === "ENOTEMPTY";
159
+ };
160
+ var safeSegment = (value, fallback) => {
161
+ const normalized = value.trim().replace(/[^a-zA-Z0-9._-]+/g, "-");
162
+ return normalized && normalized !== "." && normalized !== ".." ? normalized : fallback;
163
+ };
164
+ var withTrailingSlash = (value) => value.endsWith("/") ? value : `${value}/`;
165
+ var dateParts = (timestamp) => {
166
+ const date = new Date(timestamp);
167
+ return [
168
+ String(date.getUTCFullYear()),
169
+ String(date.getUTCMonth() + 1).padStart(2, "0"),
170
+ String(date.getUTCDate()).padStart(2, "0")
171
+ ];
172
+ };
173
+ var buildRuntimeEvidenceRsyncArgs = ({
174
+ source,
175
+ destination
176
+ }) => [
177
+ "--recursive",
178
+ "--times",
179
+ "--partial",
180
+ "--partial-dir=.rsync-partial",
181
+ "--prune-empty-dirs",
182
+ withTrailingSlash(source),
183
+ withTrailingSlash(destination)
184
+ ];
185
+ var receiptPath = (receiptsRoot, artifactId) => import_node_path2.default.join(receiptsRoot, `${safeSegment(artifactId, "artifact")}.json`);
186
+ var listPendingRuntimeEvidenceBundles = async ({
187
+ evidenceRoot,
188
+ deploymentId
189
+ }) => {
190
+ const safeDeploymentId = safeSegment(deploymentId, "production");
191
+ const artifactsRoot = import_node_path2.default.join(evidenceRoot, "artifacts", safeDeploymentId);
192
+ const receiptsRoot = import_node_path2.default.join(evidenceRoot, "receipts", safeDeploymentId);
193
+ const bundles = await discoverRuntimeEvidenceBundles(artifactsRoot);
194
+ const pending = [];
195
+ for (const bundleDir of bundles) {
196
+ const verified = await verifyRuntimeEvidenceBundle(bundleDir);
197
+ if (verified.manifest.deploymentId !== safeDeploymentId) continue;
198
+ try {
199
+ await import_promises2.default.access(receiptPath(receiptsRoot, verified.manifest.artifactId));
200
+ } catch (error) {
201
+ if (error.code !== "ENOENT") throw error;
202
+ pending.push(verified);
203
+ }
204
+ }
205
+ return pending.sort(
206
+ (left, right) => left.manifest.window.startTime - right.manifest.window.startTime || left.manifest.createdAt - right.manifest.createdAt
207
+ );
208
+ };
209
+ var syncRuntimeEvidenceBundles = async ({
210
+ source,
211
+ evidenceRoot,
212
+ deploymentId,
213
+ runRsync = async (args2) => {
214
+ const result = await execFileAsync("rsync", args2, {
215
+ maxBuffer: 10 * 1024 * 1024
216
+ });
217
+ return { stdout: result.stdout, stderr: result.stderr };
218
+ }
219
+ }) => {
220
+ const safeDeploymentId = safeSegment(deploymentId, "production");
221
+ const inboxRoot = import_node_path2.default.join(evidenceRoot, "inbox", safeDeploymentId);
222
+ const artifactsRoot = import_node_path2.default.join(evidenceRoot, "artifacts", safeDeploymentId);
223
+ await Promise.all([
224
+ import_promises2.default.mkdir(inboxRoot, { recursive: true }),
225
+ import_promises2.default.mkdir(artifactsRoot, { recursive: true })
226
+ ]);
227
+ const rsyncArgs = buildRuntimeEvidenceRsyncArgs({
228
+ source,
229
+ destination: inboxRoot
230
+ });
231
+ const transfer = await runRsync(rsyncArgs);
232
+ const discovered = await discoverRuntimeEvidenceBundles(inboxRoot);
233
+ const received = [];
234
+ for (const bundleDir of discovered) {
235
+ const verified = await verifyRuntimeEvidenceBundle(bundleDir);
236
+ if (verified.manifest.deploymentId !== safeDeploymentId) {
237
+ throw new Error(
238
+ `Artifact deployment mismatch: expected ${safeDeploymentId}, received ${verified.manifest.deploymentId}`
239
+ );
240
+ }
241
+ const destinationDir = import_node_path2.default.join(
242
+ artifactsRoot,
243
+ ...dateParts(verified.manifest.window.endTime),
244
+ safeSegment(verified.manifest.artifactId, "artifact")
245
+ );
246
+ await import_promises2.default.mkdir(import_node_path2.default.dirname(destinationDir), { recursive: true });
247
+ try {
248
+ await import_promises2.default.rename(bundleDir, destinationDir);
249
+ } catch (error) {
250
+ if (!isExistingDestinationError(error)) throw error;
251
+ const existing = await verifyRuntimeEvidenceBundle(destinationDir);
252
+ if (existing.manifest.payload.sha256 !== verified.manifest.payload.sha256) {
253
+ throw new Error(
254
+ `Conflicting runtime evidence artifact ${verified.manifest.artifactId}`
255
+ );
256
+ }
257
+ await import_promises2.default.rm(bundleDir, { recursive: true, force: true });
258
+ }
259
+ received.push(await verifyRuntimeEvidenceBundle(destinationDir));
260
+ }
261
+ return {
262
+ rsyncArgs,
263
+ stdout: String(transfer.stdout ?? ""),
264
+ stderr: String(transfer.stderr ?? ""),
265
+ received,
266
+ pending: await listPendingRuntimeEvidenceBundles({
267
+ evidenceRoot,
268
+ deploymentId: safeDeploymentId
269
+ })
270
+ };
271
+ };
272
+
273
+ // src/scripts/runtimeEvidenceSync.ts
274
+ import_args.default.option(
275
+ "source",
276
+ "Rsync source ending at the deployment ready directory",
277
+ process.env.RUNTIME_EVIDENCE_RSYNC_SOURCE
278
+ );
279
+ import_args.default.option(
280
+ "deployment",
281
+ "Deployment id expected in artifact manifests",
282
+ process.env.RUNTIME_EVIDENCE_DEPLOYMENT_ID || "production"
283
+ );
284
+ import_args.default.option(
285
+ "dir",
286
+ "Local evidence storage root",
287
+ process.env.RUNTIME_EVIDENCE_LOCAL_DIR || "data/runtime-evidence"
288
+ );
289
+ var flags = import_args.default.parse(process.argv);
290
+ var projectRoot = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
291
+ var runtimeEvidenceSync = async () => {
292
+ const source = String(flags.source ?? "").trim();
293
+ if (!source) {
294
+ throw new Error(
295
+ "Provide --source or RUNTIME_EVIDENCE_RSYNC_SOURCE for runtime evidence sync."
296
+ );
297
+ }
298
+ const evidenceRoot = import_node_path3.default.resolve(projectRoot, String(flags.dir));
299
+ const result = await syncRuntimeEvidenceBundles({
300
+ source,
301
+ evidenceRoot,
302
+ deploymentId: String(flags.deployment)
303
+ });
304
+ console.log(
305
+ import_chalk.default.green(
306
+ `Runtime evidence sync completed: received=${result.received.length} pending=${result.pending.length}`
307
+ )
308
+ );
309
+ console.log(
310
+ JSON.stringify(
311
+ {
312
+ evidenceRoot,
313
+ received: result.received.map((bundle) => ({
314
+ artifactId: bundle.manifest.artifactId,
315
+ bundleDir: bundle.bundleDir,
316
+ payloadPath: bundle.payloadPath
317
+ })),
318
+ pending: result.pending.map((bundle) => ({
319
+ artifactId: bundle.manifest.artifactId,
320
+ bundleDir: bundle.bundleDir,
321
+ payloadPath: bundle.payloadPath,
322
+ window: bundle.manifest.window
323
+ }))
324
+ },
325
+ null,
326
+ 2
327
+ )
328
+ );
329
+ };
330
+ var main = runtimeEvidenceSync;
331
+ // Annotate the CommonJS export names for ESM import in node:
332
+ 0 && (module.exports = {
333
+ main,
334
+ runtimeEvidenceSync
335
+ });
@@ -2351,6 +2351,8 @@ var timeOperation = async (label, operation, log = console.log) => {
2351
2351
 
2352
2352
  // src/lib/marketContextPrepare.ts
2353
2353
  var import_chalk4 = __toESM(require("chalk"));
2354
+ var import_timescale5 = require("@tradejs/infra/timescale");
2355
+ var import_registry = require("@tradejs/node/registry");
2354
2356
 
2355
2357
  // src/lib/binanceMarketContextBackfill.ts
2356
2358
  var import_progress = __toESM(require("progress"));
@@ -5186,6 +5188,7 @@ var backfillCoinMarketCapContextForReplay = backfillCoinMarketCapContext;
5186
5188
  var backfillCoinMarketCapContextForSignals = (params) => backfillCoinMarketCapContext({ ...params, refreshStaleFearGreed: true });
5187
5189
 
5188
5190
  // src/lib/hyperliquidWhaleBackfill.ts
5191
+ var import_progress3 = __toESM(require("progress"));
5189
5192
  var import_timescale4 = require("@tradejs/infra/timescale");
5190
5193
  var import_strategies2 = require("@tradejs/node/strategies");
5191
5194
 
@@ -5560,11 +5563,36 @@ var backfillHyperliquidWhaleContext = async (params) => {
5560
5563
  toMs,
5561
5564
  ...identity
5562
5565
  });
5566
+ const totalCoverageBuckets = Math.ceil(
5567
+ (toMs - fromMs) / HYPERLIQUID_WHALE_BUCKET_MS
5568
+ );
5569
+ const coverageBar = new import_progress3.default(
5570
+ "Hyperliquid coverage :current/:total [:bar][:percent] :eta(s) rows=:rows chunk=:chunk",
5571
+ {
5572
+ total: Math.max(1, totalCoverageBuckets),
5573
+ width: 24
5574
+ }
5575
+ );
5576
+ let displayedCoverageBuckets = 0;
5563
5577
  const coverageBuckets = await (0, import_timescale4.rebuildHyperliquidWhaleCoverageRows)({
5564
5578
  fromMs,
5565
5579
  toMs,
5566
5580
  expectedWhales: whales.addresses.length,
5567
- ...identity
5581
+ ...identity,
5582
+ onProgress: (progress) => {
5583
+ const next = Math.max(
5584
+ displayedCoverageBuckets,
5585
+ Math.min(progress.completedBuckets, coverageBar.total)
5586
+ );
5587
+ const delta = next - displayedCoverageBuckets;
5588
+ if (delta > 0) {
5589
+ coverageBar.tick(delta, {
5590
+ rows: progress.rows,
5591
+ chunk: `${progress.chunkIndex}/${progress.totalChunks}`
5592
+ });
5593
+ displayedCoverageBuckets = next;
5594
+ }
5595
+ }
5568
5596
  });
5569
5597
  const result = {
5570
5598
  cached: false,
@@ -5592,6 +5620,9 @@ var backfillHyperliquidWhaleContext = async (params) => {
5592
5620
  };
5593
5621
 
5594
5622
  // src/lib/marketContextPrepare.ts
5623
+ var uniqueReasons = (reasons) => [
5624
+ ...new Set(reasons)
5625
+ ];
5595
5626
  var shouldPrepareDerivativesContextForRun = (params) => {
5596
5627
  if (params.universe === "tradfi") return false;
5597
5628
  if (params.mode === "signals") {
@@ -5599,6 +5630,9 @@ var shouldPrepareDerivativesContextForRun = (params) => {
5599
5630
  cacheOnly: params.cacheOnly
5600
5631
  });
5601
5632
  }
5633
+ if (params.mode === "backtest" && !params.aiEnabled && !params.mlEnabled) {
5634
+ return false;
5635
+ }
5602
5636
  return shouldBackfillDerivativesContextForBacktest({
5603
5637
  aiEnabled: Boolean(params.aiEnabled),
5604
5638
  cacheOnly: params.cacheOnly,
@@ -5608,6 +5642,7 @@ var shouldPrepareDerivativesContextForRun = (params) => {
5608
5642
  var shouldPrepareBinanceMarketContextForRun = (params) => {
5609
5643
  if (params.universe === "tradfi") return false;
5610
5644
  if (params.mode === "backtest") {
5645
+ if (!params.aiEnabled && !params.mlEnabled) return false;
5611
5646
  return shouldBackfillBinanceMarketContextForBacktest({
5612
5647
  aiEnabled: Boolean(params.aiEnabled),
5613
5648
  cacheOnly: params.cacheOnly,
@@ -5626,6 +5661,7 @@ var shouldPrepareBinanceMarketContextForRun = (params) => {
5626
5661
  var shouldPrepareCoinMarketCapContextForRun = (params) => {
5627
5662
  if (params.universe === "tradfi") return false;
5628
5663
  if (params.mode === "backtest") {
5664
+ if (!params.aiEnabled && !params.mlEnabled) return false;
5629
5665
  return shouldBackfillCoinMarketCapContextForBacktest({
5630
5666
  aiEnabled: Boolean(params.aiEnabled),
5631
5667
  cacheOnly: params.cacheOnly,
@@ -5641,10 +5677,8 @@ var shouldPrepareCoinMarketCapContextForRun = (params) => {
5641
5677
  cacheOnly: params.cacheOnly
5642
5678
  });
5643
5679
  };
5644
- var shouldPrepareHyperliquidWhaleContextForRun = (params) => {
5645
- const strategyRequiresContext = params.strategyNames?.includes(
5646
- "HyperliquidConsensus"
5647
- );
5680
+ var shouldPrepareHyperliquidWhaleContextForRun = (params, coreContextSources = []) => {
5681
+ const strategyRequiresContext = coreContextSources.includes("hyperliquidWhales");
5648
5682
  if (params.universe === "tradfi" || params.mode === "signals" || params.cacheOnly || !params.aiEnabled && !params.mlEnabled && !strategyRequiresContext) {
5649
5683
  return false;
5650
5684
  }
@@ -5655,6 +5689,64 @@ var shouldPrepareHyperliquidWhaleContextForRun = (params) => {
5655
5689
  if (strategyRequiresContext) return true;
5656
5690
  return ["1", "true", "yes", "on"].includes(configured);
5657
5691
  };
5692
+ var resolveCoreContextSources = async (params) => {
5693
+ const strategyNames = [...new Set(params.strategyNames ?? [])];
5694
+ if (!strategyNames.length) return [];
5695
+ await (0, import_registry.ensureStrategyPluginsLoaded)(params.projectRoot);
5696
+ return [
5697
+ ...new Set(
5698
+ strategyNames.flatMap(
5699
+ (strategyName) => (0, import_registry.getStrategyManifest)(strategyName, params.projectRoot)?.contextRequirements?.core ?? []
5700
+ )
5701
+ )
5702
+ ];
5703
+ };
5704
+ var resolveMarketContextRunRequirements = async (params) => {
5705
+ const coreContextSources = await resolveCoreContextSources(params);
5706
+ const paramsWithCoreDemand = (source) => coreContextSources.includes(source) ? { ...params, aiEnabled: true } : params;
5707
+ const isCrypto = params.universe !== "tradfi";
5708
+ const capturesPayload = Boolean(params.aiEnabled || params.mlEnabled);
5709
+ const runtimeReadsContext = params.mode !== "backtest";
5710
+ const reasonsFor = (source) => uniqueReasons([
5711
+ ...coreContextSources.includes(source) ? ["core"] : [],
5712
+ ...params.aiEnabled ? ["ai"] : [],
5713
+ ...params.mlEnabled ? ["ml"] : [],
5714
+ ...runtimeReadsContext ? ["runtime"] : []
5715
+ ]);
5716
+ const readsStandardContext = isCrypto && (capturesPayload || runtimeReadsContext);
5717
+ const readsHyperliquid = isCrypto && (readsStandardContext || coreContextSources.includes("hyperliquidWhales"));
5718
+ return {
5719
+ binance: {
5720
+ read: readsStandardContext || coreContextSources.includes("binance"),
5721
+ backfill: shouldPrepareBinanceMarketContextForRun(
5722
+ paramsWithCoreDemand("binance")
5723
+ ),
5724
+ requiredBy: reasonsFor("binance")
5725
+ },
5726
+ coinmarketcap: {
5727
+ read: readsStandardContext || coreContextSources.includes("coinmarketcap"),
5728
+ backfill: shouldPrepareCoinMarketCapContextForRun(
5729
+ paramsWithCoreDemand("coinmarketcap")
5730
+ ),
5731
+ requiredBy: reasonsFor("coinmarketcap")
5732
+ },
5733
+ derivatives: {
5734
+ read: readsStandardContext || coreContextSources.includes("derivatives"),
5735
+ backfill: shouldPrepareDerivativesContextForRun(
5736
+ paramsWithCoreDemand("derivatives")
5737
+ ),
5738
+ requiredBy: reasonsFor("derivatives")
5739
+ },
5740
+ hyperliquidWhales: {
5741
+ read: readsHyperliquid,
5742
+ backfill: shouldPrepareHyperliquidWhaleContextForRun(
5743
+ params,
5744
+ coreContextSources
5745
+ ),
5746
+ requiredBy: reasonsFor("hyperliquidWhales")
5747
+ }
5748
+ };
5749
+ };
5658
5750
  var resolveCoinMarketCapBackfillForMode = (mode) => mode === "backtest" ? backfillCoinMarketCapContextForBacktest : mode === "signals" ? backfillCoinMarketCapContextForSignals : backfillCoinMarketCapContextForReplay;
5659
5751
  var buildCoinMarketCapBackfillParams = (params) => ({
5660
5752
  userName: params.userName,
@@ -5683,7 +5775,15 @@ var prepareMarketContextForRun = async (params) => {
5683
5775
  console.log(import_chalk4.default.gray(message));
5684
5776
  });
5685
5777
  const timeOperation2 = (label, operation) => timeOperation(label, operation, log);
5686
- if (shouldPrepareDerivativesContextForRun(params)) {
5778
+ const requirements = await resolveMarketContextRunRequirements(params);
5779
+ const readableSources = Object.entries(requirements).filter(([, requirement]) => requirement.read).map(([source]) => source);
5780
+ if (readableSources.length) {
5781
+ await timeOperation2(
5782
+ "market context schema ensure",
5783
+ () => (0, import_timescale5.ensureMarketContextSchemas)(readableSources)
5784
+ );
5785
+ }
5786
+ if (requirements.derivatives.backfill) {
5687
5787
  await timeOperation2(
5688
5788
  "derivatives context backfill",
5689
5789
  () => (params.mode === "signals" ? backfillDerivativesContextForSignals : backfillDerivativesContextForBacktest)(
@@ -5691,7 +5791,7 @@ var prepareMarketContextForRun = async (params) => {
5691
5791
  )
5692
5792
  );
5693
5793
  }
5694
- if (shouldPrepareHyperliquidWhaleContextForRun(params)) {
5794
+ if (requirements.hyperliquidWhales.backfill) {
5695
5795
  await timeOperation2(
5696
5796
  "hyperliquid whale context backfill",
5697
5797
  () => backfillHyperliquidWhaleContext({
@@ -5703,13 +5803,13 @@ var prepareMarketContextForRun = async (params) => {
5703
5803
  })
5704
5804
  );
5705
5805
  }
5706
- if (shouldPrepareBinanceMarketContextForRun(params)) {
5806
+ if (requirements.binance.backfill) {
5707
5807
  await timeOperation2("binance market context backfill", () => {
5708
5808
  const backfill = params.mode === "backtest" ? backfillBinanceMarketContextForBacktest : params.mode === "signals" ? backfillBinanceMarketContextForSignals : backfillBinanceMarketContextForReplay;
5709
5809
  return backfill(buildBinanceMarketBackfillParams(params));
5710
5810
  });
5711
5811
  }
5712
- if (shouldPrepareCoinMarketCapContextForRun(params)) {
5812
+ if (requirements.coinmarketcap.backfill) {
5713
5813
  await timeOperation2(
5714
5814
  "coinmarketcap historical context backfill",
5715
5815
  () => resolveCoinMarketCapBackfillForMode(params.mode)(
@@ -5717,6 +5817,7 @@ var prepareMarketContextForRun = async (params) => {
5717
5817
  )
5718
5818
  );
5719
5819
  }
5820
+ return requirements;
5720
5821
  };
5721
5822
 
5722
5823
  // src/lib/marketData/historyPrepare.ts