@tradejs/cli 2.0.12 → 2.0.14

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.
@@ -313,6 +313,8 @@ var summarizeAiTrainEvaluations = (evaluations) => {
313
313
  };
314
314
 
315
315
  // src/lib/aiTrainResearch.ts
316
+ var import_strategies = require("@tradejs/node/strategies");
317
+ var import_types = require("@tradejs/types");
316
318
  var DAY_MS2 = 24 * 60 * 60 * 1e3;
317
319
  var RESEARCH_CONTEXT_ENV_KEYS = [
318
320
  "AI_MODE",
@@ -331,13 +333,22 @@ var RESEARCH_CONTEXT_ENV_KEYS = [
331
333
  "COINMARKETCAP_CONTEXT_HISTORICAL_ACCESS_MONTHS",
332
334
  "COINMARKETCAP_CONTEXT_BACKFILL_ENABLED",
333
335
  "COINMARKETCAP_CONTEXT_BACKFILL_MAX_DAYS",
334
- "COINMARKETCAP_CONTEXT_BACKFILL_WARMUP_DAYS"
336
+ "COINMARKETCAP_CONTEXT_BACKFILL_WARMUP_DAYS",
337
+ "HYPERLIQUID_WHALE_CONTEXT_ENABLED",
338
+ "HYPERLIQUID_WHALE_BACKFILL_ENABLED",
339
+ "HYPERLIQUID_WHALE_MIN_COVERAGE_PCT",
340
+ "HYPERLIQUID_WHALE_CONCURRENCY",
341
+ "HYPERLIQUID_WHALE_RATE_LIMIT_WEIGHT"
335
342
  ];
336
343
  var DERIVATIVES_CONTEXT_DATA_MODEL = {
337
344
  derivativesSourceIntervals: "15m",
338
345
  derivativesDerivedIntervals: "1h",
339
346
  derivativesHourlyFallback: "stored-1h",
340
- derivativesDataModelVersion: 2
347
+ derivativesDataModelVersion: 2,
348
+ hyperliquidWhaleCanonicalInterval: "1m",
349
+ hyperliquidWhaleGateMinNotionalUsd: 5e4,
350
+ hyperliquidWhaleMinCoveragePct: 0.8,
351
+ hyperliquidWhaleDataModelVersion: import_types.HYPERLIQUID_WHALE_DATA_MODEL_VERSION
341
352
  };
342
353
  var normalizeForStableJson = (value) => {
343
354
  if (Array.isArray(value)) {
@@ -494,12 +505,16 @@ var buildAiTrainLineage = async ({
494
505
  const { gitSha, gitDirty } = getGitLineage(projectRoot);
495
506
  const gate = await resolveGateFingerprint(projectRoot, strategyName, gitSha);
496
507
  const normalizedConfigIds = [...new Set(configIds.filter(Boolean))].sort();
508
+ const hyperliquidPerpUniverseFingerprint = typeof import_strategies.getHyperliquidPerpUniverseSnapshot === "function" ? (0, import_strategies.getHyperliquidPerpUniverseSnapshot)().fingerprint : null;
509
+ const hyperliquidWhaleRegistryFingerprint = typeof import_strategies.getHyperliquidWhaleRegistrySnapshot === "function" ? (0, import_strategies.getHyperliquidWhaleRegistrySnapshot)().fingerprint : null;
497
510
  const context = {
498
511
  ...Object.fromEntries(
499
512
  RESEARCH_CONTEXT_ENV_KEYS.map((key) => [key, env[key] ?? null])
500
513
  ),
501
514
  ...runContext,
502
- ...DERIVATIVES_CONTEXT_DATA_MODEL
515
+ ...DERIVATIVES_CONTEXT_DATA_MODEL,
516
+ hyperliquidPerpUniverseFingerprint,
517
+ hyperliquidWhaleRegistryFingerprint
503
518
  };
504
519
  return {
505
520
  gitSha,
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/lib/hyperliquidRateLimiter.ts
21
+ var hyperliquidRateLimiter_exports = {};
22
+ __export(hyperliquidRateLimiter_exports, {
23
+ HyperliquidInfoRateLimiter: () => HyperliquidInfoRateLimiter,
24
+ hyperliquidInfoResponseWeight: () => hyperliquidInfoResponseWeight
25
+ });
26
+ module.exports = __toCommonJS(hyperliquidRateLimiter_exports);
27
+ var DEFAULT_WEIGHT_PER_MINUTE = 1e3;
28
+ var WINDOW_MS = 6e4;
29
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
30
+ var HyperliquidInfoRateLimiter = class {
31
+ constructor(capacity = DEFAULT_WEIGHT_PER_MINUTE, now = Date.now, wait = sleep) {
32
+ this.capacity = capacity;
33
+ this.now = now;
34
+ this.wait = wait;
35
+ this.reservations = [];
36
+ this.queue = Promise.resolve();
37
+ }
38
+ reserve(weight) {
39
+ const normalizedWeight = Math.max(1, Math.ceil(weight));
40
+ const pending = this.queue.then(
41
+ () => this.reserveInternal(normalizedWeight)
42
+ );
43
+ this.queue = pending.catch(() => void 0);
44
+ return pending;
45
+ }
46
+ async reserveInternal(weight) {
47
+ if (weight > this.capacity) {
48
+ throw new Error(
49
+ `Hyperliquid request weight ${weight} exceeds limiter capacity ${this.capacity}`
50
+ );
51
+ }
52
+ for (; ; ) {
53
+ const nowMs = this.now();
54
+ this.reservations = this.reservations.filter(
55
+ (reservation) => reservation.atMs > nowMs - WINDOW_MS
56
+ );
57
+ const used = this.reservations.reduce(
58
+ (sum, reservation) => sum + reservation.weight,
59
+ 0
60
+ );
61
+ if (used + weight <= this.capacity) {
62
+ this.reservations.push({ atMs: nowMs, weight });
63
+ return;
64
+ }
65
+ const oldest = this.reservations[0];
66
+ await this.wait(Math.max(1, oldest.atMs + WINDOW_MS - nowMs));
67
+ }
68
+ }
69
+ };
70
+ var hyperliquidInfoResponseWeight = (rows) => Math.max(0, Math.ceil(Math.max(0, rows) / 20));
71
+ // Annotate the CommonJS export names for ESM import in node:
72
+ 0 && (module.exports = {
73
+ HyperliquidInfoRateLimiter,
74
+ hyperliquidInfoResponseWeight
75
+ });
@@ -0,0 +1,435 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/lib/hyperliquidWhaleBackfill.ts
21
+ var hyperliquidWhaleBackfill_exports = {};
22
+ __export(hyperliquidWhaleBackfill_exports, {
23
+ backfillHyperliquidWhaleContext: () => backfillHyperliquidWhaleContext,
24
+ fetchHyperliquidUserFillsByTime: () => fetchHyperliquidUserFillsByTime
25
+ });
26
+ module.exports = __toCommonJS(hyperliquidWhaleBackfill_exports);
27
+ var import_timescale = require("@tradejs/infra/timescale");
28
+ var import_strategies = require("@tradejs/node/strategies");
29
+
30
+ // src/lib/hyperliquidWhaleData.ts
31
+ var HYPERLIQUID_WHALE_BUCKET_MS = 6e4;
32
+ var finiteNumber = (value) => {
33
+ const numeric = typeof value === "number" ? value : Number(value);
34
+ return Number.isFinite(numeric) ? numeric : null;
35
+ };
36
+ var POSITION_EPSILON = 1e-12;
37
+ var normalizePosition = (value) => Math.abs(value) <= POSITION_EPSILON ? 0 : value;
38
+ var classifyHyperliquidPositionChange = (params) => {
39
+ const startValue = finiteNumber(params.startPosition);
40
+ const size = finiteNumber(params.size);
41
+ const side = String(params.side ?? "").toUpperCase();
42
+ if (startValue == null || size == null || size <= 0) return null;
43
+ if (side !== "B" && side !== "A") return null;
44
+ const startPosition = normalizePosition(startValue);
45
+ const endPosition = normalizePosition(
46
+ startPosition + (side === "B" ? size : -size)
47
+ );
48
+ const startLong = Math.max(startPosition, 0);
49
+ const endLong = Math.max(endPosition, 0);
50
+ const startShort = Math.max(-startPosition, 0);
51
+ const endShort = Math.max(-endPosition, 0);
52
+ const longEntrySize = Math.max(0, endLong - startLong);
53
+ const shortEntrySize = Math.max(0, endShort - startShort);
54
+ const longExitSize = Math.max(0, startLong - endLong);
55
+ const shortExitSize = Math.max(0, startShort - endShort);
56
+ const flipped = startPosition * endPosition < 0;
57
+ const opened = startPosition === 0;
58
+ const closed = endPosition === 0;
59
+ const increased = Math.sign(startPosition) === Math.sign(endPosition) && Math.abs(endPosition) > Math.abs(startPosition);
60
+ return {
61
+ startPosition,
62
+ endPosition,
63
+ action: flipped ? "flip" : opened ? "open" : closed ? "close" : increased ? "increase" : "reduce",
64
+ longEntrySize,
65
+ shortEntrySize,
66
+ longExitSize,
67
+ shortExitSize
68
+ };
69
+ };
70
+ var normalizeAddress = (value) => typeof value === "string" && /^0x[0-9a-fA-F]{40}$/.test(value) ? value.toLowerCase() : null;
71
+ var normalizeTradeFields = (value) => {
72
+ const symbol = typeof value.coin === "string" ? value.coin.trim() : "";
73
+ const price = finiteNumber(value.px);
74
+ const size = finiteNumber(value.sz);
75
+ const timestamp = finiteNumber(value.time);
76
+ const tid = typeof value.tid === "string" || typeof value.tid === "number" ? String(value.tid) : "";
77
+ if (!symbol || price == null || size == null || timestamp == null || !tid || price <= 0 || size <= 0) {
78
+ return null;
79
+ }
80
+ return {
81
+ symbol,
82
+ price,
83
+ size,
84
+ timestamp,
85
+ tid,
86
+ notionalUsd: price * size
87
+ };
88
+ };
89
+ var normalizeHyperliquidUserFill = (params) => {
90
+ const normalized = normalizeTradeFields(params.fill);
91
+ if (!normalized || !params.trackedSymbols.has(normalized.symbol)) return null;
92
+ const address = normalizeAddress(params.address);
93
+ if (!address) return null;
94
+ const side = String(params.fill.side ?? "").toUpperCase();
95
+ if (side !== "B" && side !== "A") return null;
96
+ const positionChange = classifyHyperliquidPositionChange({
97
+ startPosition: params.fill.startPosition,
98
+ side,
99
+ size: normalized.size
100
+ });
101
+ const closedPnl = finiteNumber(params.fill.closedPnl);
102
+ const liquidation = params.fill.liquidation != null && typeof params.fill.liquidation === "object";
103
+ const positionFields = positionChange ? side === "B" ? {
104
+ buyerStartPosition: positionChange.startPosition,
105
+ buyerEndPosition: positionChange.endPosition,
106
+ buyerPositionAction: positionChange.action,
107
+ buyerClosedPnl: closedPnl,
108
+ buyerLiquidation: liquidation
109
+ } : {
110
+ sellerStartPosition: positionChange.startPosition,
111
+ sellerEndPosition: positionChange.endPosition,
112
+ sellerPositionAction: positionChange.action,
113
+ sellerClosedPnl: closedPnl,
114
+ sellerLiquidation: liquidation
115
+ } : {};
116
+ return {
117
+ symbol: normalized.symbol,
118
+ ts: new Date(normalized.timestamp),
119
+ tid: normalized.tid,
120
+ price: normalized.price,
121
+ size: normalized.size,
122
+ notionalUsd: normalized.notionalUsd,
123
+ buyerAddress: side === "B" ? address : null,
124
+ sellerAddress: side === "A" ? address : null,
125
+ buyerTracked: side === "B",
126
+ sellerTracked: side === "A",
127
+ ...positionFields,
128
+ ...params.identity,
129
+ source: "hyperliquid_user_fills"
130
+ };
131
+ };
132
+
133
+ // src/lib/hyperliquidRateLimiter.ts
134
+ var DEFAULT_WEIGHT_PER_MINUTE = 1e3;
135
+ var WINDOW_MS = 6e4;
136
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
137
+ var HyperliquidInfoRateLimiter = class {
138
+ constructor(capacity = DEFAULT_WEIGHT_PER_MINUTE, now = Date.now, wait = sleep) {
139
+ this.capacity = capacity;
140
+ this.now = now;
141
+ this.wait = wait;
142
+ this.reservations = [];
143
+ this.queue = Promise.resolve();
144
+ }
145
+ reserve(weight) {
146
+ const normalizedWeight = Math.max(1, Math.ceil(weight));
147
+ const pending = this.queue.then(
148
+ () => this.reserveInternal(normalizedWeight)
149
+ );
150
+ this.queue = pending.catch(() => void 0);
151
+ return pending;
152
+ }
153
+ async reserveInternal(weight) {
154
+ if (weight > this.capacity) {
155
+ throw new Error(
156
+ `Hyperliquid request weight ${weight} exceeds limiter capacity ${this.capacity}`
157
+ );
158
+ }
159
+ for (; ; ) {
160
+ const nowMs = this.now();
161
+ this.reservations = this.reservations.filter(
162
+ (reservation) => reservation.atMs > nowMs - WINDOW_MS
163
+ );
164
+ const used = this.reservations.reduce(
165
+ (sum, reservation) => sum + reservation.weight,
166
+ 0
167
+ );
168
+ if (used + weight <= this.capacity) {
169
+ this.reservations.push({ atMs: nowMs, weight });
170
+ return;
171
+ }
172
+ const oldest = this.reservations[0];
173
+ await this.wait(Math.max(1, oldest.atMs + WINDOW_MS - nowMs));
174
+ }
175
+ }
176
+ };
177
+ var hyperliquidInfoResponseWeight = (rows) => Math.max(0, Math.ceil(Math.max(0, rows) / 20));
178
+
179
+ // src/lib/hyperliquidWhaleBackfill.ts
180
+ var DEFAULT_BASE_URL = "https://api.hyperliquid.xyz";
181
+ var DEFAULT_CONCURRENCY = 2;
182
+ var DEFAULT_RATE_LIMIT_WEIGHT = 1e3;
183
+ var MAX_PAGE_SIZE = 2e3;
184
+ var MAX_PAGES_PER_WHALE = 5;
185
+ var REQUEST_WEIGHT = 20;
186
+ var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
187
+ var positiveInt = (value, fallback) => {
188
+ const parsed = Number.parseInt(String(value ?? ""), 10);
189
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
190
+ };
191
+ var minuteCeil = (value) => Math.ceil(value / HYPERLIQUID_WHALE_BUCKET_MS) * HYPERLIQUID_WHALE_BUCKET_MS;
192
+ var nextMinute = (value) => (Math.floor(value / HYPERLIQUID_WHALE_BUCKET_MS) + 1) * HYPERLIQUID_WHALE_BUCKET_MS;
193
+ var fetchHyperliquidUserFillsByTime = async (params) => {
194
+ const fetchImpl = params.fetchImpl ?? fetch;
195
+ const limiter = params.rateLimiter ?? new HyperliquidInfoRateLimiter(
196
+ positiveInt(
197
+ process.env.HYPERLIQUID_WHALE_RATE_LIMIT_WEIGHT,
198
+ DEFAULT_RATE_LIMIT_WEIGHT
199
+ ),
200
+ Date.now,
201
+ params.wait ?? sleep2
202
+ );
203
+ const fills = [];
204
+ let cursor = params.startTime;
205
+ for (let page = 0; page < (params.maxPages ?? MAX_PAGES_PER_WHALE) && cursor <= params.endTime; page += 1) {
206
+ await limiter.reserve(REQUEST_WEIGHT);
207
+ const response = await fetchImpl(
208
+ `${process.env.HYPERLIQUID_API_BASE_URL?.trim() || DEFAULT_BASE_URL}/info`,
209
+ {
210
+ method: "POST",
211
+ headers: { "content-type": "application/json" },
212
+ body: JSON.stringify({
213
+ type: "userFillsByTime",
214
+ user: params.address,
215
+ startTime: cursor,
216
+ endTime: params.endTime,
217
+ aggregateByTime: true
218
+ })
219
+ }
220
+ );
221
+ if (!response.ok) {
222
+ throw new Error(
223
+ `Hyperliquid userFillsByTime ${response.status}: ${await response.text()}`
224
+ );
225
+ }
226
+ const raw = await response.json();
227
+ const pageRows = Array.isArray(raw) ? raw : [];
228
+ const responseWeight = hyperliquidInfoResponseWeight(pageRows.length);
229
+ if (responseWeight > 0) await limiter.reserve(responseWeight);
230
+ fills.push(...pageRows);
231
+ if (pageRows.length < MAX_PAGE_SIZE) {
232
+ return { fills, truncated: false, coveredFromMs: params.startTime };
233
+ }
234
+ const lastTime = Math.max(
235
+ ...pageRows.map((row) => Number(row.time)).filter(Number.isFinite)
236
+ );
237
+ if (!Number.isFinite(lastTime) || lastTime < cursor) {
238
+ throw new Error(
239
+ `Hyperliquid fills pagination stalled for ${params.address}`
240
+ );
241
+ }
242
+ cursor = lastTime + 1;
243
+ }
244
+ if (cursor > params.endTime) {
245
+ return { fills, truncated: false, coveredFromMs: params.startTime };
246
+ }
247
+ const firstAvailableTime = Math.min(
248
+ ...fills.map((fill) => Number(fill.time)).filter(Number.isFinite)
249
+ );
250
+ return {
251
+ fills,
252
+ truncated: true,
253
+ coveredFromMs: Math.min(params.endTime + 1, nextMinute(firstAvailableTime))
254
+ };
255
+ };
256
+ var runConcurrent = async (params) => {
257
+ let nextIndex = 0;
258
+ await Promise.all(
259
+ Array.from(
260
+ { length: Math.min(params.concurrency, params.items.length) },
261
+ async () => {
262
+ for (; ; ) {
263
+ const index = nextIndex;
264
+ nextIndex += 1;
265
+ if (index >= params.items.length) return;
266
+ await params.worker(params.items[index], index);
267
+ }
268
+ }
269
+ )
270
+ );
271
+ };
272
+ var backfillHyperliquidWhaleContext = async (params) => {
273
+ const universe = (0, import_strategies.getHyperliquidPerpUniverseSnapshot)();
274
+ const whales = (0, import_strategies.getHyperliquidWhaleRegistrySnapshot)();
275
+ const trackedSymbols = new Set(universe.symbols);
276
+ const identity = {
277
+ universeFingerprint: universe.fingerprint,
278
+ whaleRegistryFingerprint: whales.fingerprint
279
+ };
280
+ const fromMs = Math.floor(params.startMs / HYPERLIQUID_WHALE_BUCKET_MS) * HYPERLIQUID_WHALE_BUCKET_MS;
281
+ const toMs = minuteCeil(params.endMs);
282
+ const cached = await (0, import_timescale.hasHyperliquidWhaleBackfillCoverage)({
283
+ fromMs,
284
+ toMs,
285
+ ...identity
286
+ });
287
+ const emptyResult = () => ({
288
+ cached,
289
+ cacheOnly: params.cacheOnly,
290
+ fills: 0,
291
+ events: 0,
292
+ buckets: 0,
293
+ coverageBuckets: 0,
294
+ complete: cached,
295
+ walletsProcessed: 0,
296
+ walletsCached: 0,
297
+ completeWallets: 0,
298
+ truncatedWallets: 0,
299
+ failedWallets: 0,
300
+ fromMs,
301
+ toMs
302
+ });
303
+ if (cached || params.cacheOnly) return emptyResult();
304
+ const limiter = new HyperliquidInfoRateLimiter(
305
+ positiveInt(
306
+ process.env.HYPERLIQUID_WHALE_RATE_LIMIT_WEIGHT,
307
+ DEFAULT_RATE_LIMIT_WEIGHT
308
+ ),
309
+ Date.now,
310
+ params.wait ?? sleep2
311
+ );
312
+ const concurrency = Math.min(
313
+ 4,
314
+ positiveInt(
315
+ params.concurrency ?? process.env.HYPERLIQUID_WHALE_CONCURRENCY,
316
+ DEFAULT_CONCURRENCY
317
+ )
318
+ );
319
+ let fills = 0;
320
+ let events = 0;
321
+ let walletsProcessed = 0;
322
+ let walletsCached = 0;
323
+ let completeWallets = 0;
324
+ let truncatedWallets = 0;
325
+ let failedWallets = 0;
326
+ const failures = [];
327
+ await runConcurrent({
328
+ items: whales.addresses,
329
+ concurrency,
330
+ worker: async (address) => {
331
+ const previous = await (0, import_timescale.getHyperliquidWhaleWalletCoverage)({
332
+ address,
333
+ fromMs,
334
+ toMs,
335
+ ...identity
336
+ });
337
+ if (previous && previous.status !== "failed") {
338
+ walletsCached += 1;
339
+ if (previous.status === "complete") completeWallets += 1;
340
+ else truncatedWallets += 1;
341
+ } else {
342
+ try {
343
+ const result2 = await fetchHyperliquidUserFillsByTime({
344
+ address,
345
+ startTime: fromMs,
346
+ endTime: toMs - 1,
347
+ fetchImpl: params.fetchImpl,
348
+ rateLimiter: limiter
349
+ });
350
+ const addressEvents = result2.fills.map(
351
+ (fill) => normalizeHyperliquidUserFill({
352
+ fill,
353
+ address,
354
+ trackedSymbols,
355
+ identity
356
+ })
357
+ ).filter((row) => row != null);
358
+ await (0, import_timescale.upsertHyperliquidWhaleTradeEvents)(addressEvents);
359
+ await (0, import_timescale.upsertHyperliquidWhaleWalletCoverage)({
360
+ address,
361
+ fromMs,
362
+ toMs,
363
+ coveredFromMs: result2.coveredFromMs,
364
+ coveredToMs: toMs,
365
+ status: result2.truncated ? "truncated" : "complete",
366
+ fillsCount: result2.fills.length,
367
+ ...identity
368
+ });
369
+ fills += result2.fills.length;
370
+ events += addressEvents.length;
371
+ if (result2.truncated) truncatedWallets += 1;
372
+ else completeWallets += 1;
373
+ } catch (error) {
374
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
375
+ failures.push(normalizedError);
376
+ failedWallets += 1;
377
+ await (0, import_timescale.upsertHyperliquidWhaleWalletCoverage)({
378
+ address,
379
+ fromMs,
380
+ toMs,
381
+ coveredFromMs: null,
382
+ coveredToMs: null,
383
+ status: "failed",
384
+ fillsCount: 0,
385
+ error: normalizedError.message,
386
+ ...identity
387
+ });
388
+ }
389
+ }
390
+ walletsProcessed += 1;
391
+ params.log?.(
392
+ `Hyperliquid whales ${walletsProcessed}/${whales.addresses.length}: complete=${completeWallets}, truncated=${truncatedWallets}, failed=${failedWallets}, fills=${fills}, events=${events}`
393
+ );
394
+ }
395
+ });
396
+ const buckets = await (0, import_timescale.rebuildHyperliquidWhaleFlowRows)({
397
+ fromMs,
398
+ toMs,
399
+ ...identity
400
+ });
401
+ const coverageBuckets = await (0, import_timescale.rebuildHyperliquidWhaleCoverageRows)({
402
+ fromMs,
403
+ toMs,
404
+ expectedWhales: whales.addresses.length,
405
+ ...identity
406
+ });
407
+ const result = {
408
+ cached: false,
409
+ cacheOnly: false,
410
+ fills,
411
+ events,
412
+ buckets,
413
+ coverageBuckets,
414
+ complete: truncatedWallets === 0 && failedWallets === 0,
415
+ walletsProcessed,
416
+ walletsCached,
417
+ completeWallets,
418
+ truncatedWallets,
419
+ failedWallets,
420
+ fromMs,
421
+ toMs
422
+ };
423
+ if (params.strict !== false && failures.length) {
424
+ throw new AggregateError(
425
+ failures,
426
+ `Hyperliquid whale backfill failed for ${failures.length}/${whales.addresses.length} wallets`
427
+ );
428
+ }
429
+ return result;
430
+ };
431
+ // Annotate the CommonJS export names for ESM import in node:
432
+ 0 && (module.exports = {
433
+ backfillHyperliquidWhaleContext,
434
+ fetchHyperliquidUserFillsByTime
435
+ });