@tradejs/cli 2.0.13 → 2.0.15

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,307 @@
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/hyperliquidWhaleData.ts
21
+ var hyperliquidWhaleData_exports = {};
22
+ __export(hyperliquidWhaleData_exports, {
23
+ HYPERLIQUID_WHALE_BUCKET_MS: () => HYPERLIQUID_WHALE_BUCKET_MS,
24
+ aggregateHyperliquidWhaleEvents: () => aggregateHyperliquidWhaleEvents,
25
+ classifyHyperliquidPositionChange: () => classifyHyperliquidPositionChange,
26
+ normalizeHyperliquidUserFill: () => normalizeHyperliquidUserFill,
27
+ normalizeHyperliquidWsTrade: () => normalizeHyperliquidWsTrade
28
+ });
29
+ module.exports = __toCommonJS(hyperliquidWhaleData_exports);
30
+ var HYPERLIQUID_WHALE_BUCKET_MS = 6e4;
31
+ var finiteNumber = (value) => {
32
+ const numeric = typeof value === "number" ? value : Number(value);
33
+ return Number.isFinite(numeric) ? numeric : null;
34
+ };
35
+ var POSITION_EPSILON = 1e-12;
36
+ var normalizePosition = (value) => Math.abs(value) <= POSITION_EPSILON ? 0 : value;
37
+ var classifyHyperliquidPositionChange = (params) => {
38
+ const startValue = finiteNumber(params.startPosition);
39
+ const size = finiteNumber(params.size);
40
+ const side = String(params.side ?? "").toUpperCase();
41
+ if (startValue == null || size == null || size <= 0) return null;
42
+ if (side !== "B" && side !== "A") return null;
43
+ const startPosition = normalizePosition(startValue);
44
+ const endPosition = normalizePosition(
45
+ startPosition + (side === "B" ? size : -size)
46
+ );
47
+ const startLong = Math.max(startPosition, 0);
48
+ const endLong = Math.max(endPosition, 0);
49
+ const startShort = Math.max(-startPosition, 0);
50
+ const endShort = Math.max(-endPosition, 0);
51
+ const longEntrySize = Math.max(0, endLong - startLong);
52
+ const shortEntrySize = Math.max(0, endShort - startShort);
53
+ const longExitSize = Math.max(0, startLong - endLong);
54
+ const shortExitSize = Math.max(0, startShort - endShort);
55
+ const flipped = startPosition * endPosition < 0;
56
+ const opened = startPosition === 0;
57
+ const closed = endPosition === 0;
58
+ const increased = Math.sign(startPosition) === Math.sign(endPosition) && Math.abs(endPosition) > Math.abs(startPosition);
59
+ return {
60
+ startPosition,
61
+ endPosition,
62
+ action: flipped ? "flip" : opened ? "open" : closed ? "close" : increased ? "increase" : "reduce",
63
+ longEntrySize,
64
+ shortEntrySize,
65
+ longExitSize,
66
+ shortExitSize
67
+ };
68
+ };
69
+ var normalizeAddress = (value) => typeof value === "string" && /^0x[0-9a-fA-F]{40}$/.test(value) ? value.toLowerCase() : null;
70
+ var normalizeTradeFields = (value) => {
71
+ const symbol = typeof value.coin === "string" ? value.coin.trim() : "";
72
+ const price = finiteNumber(value.px);
73
+ const size = finiteNumber(value.sz);
74
+ const timestamp = finiteNumber(value.time);
75
+ const tid = typeof value.tid === "string" || typeof value.tid === "number" ? String(value.tid) : "";
76
+ if (!symbol || price == null || size == null || timestamp == null || !tid || price <= 0 || size <= 0) {
77
+ return null;
78
+ }
79
+ return {
80
+ symbol,
81
+ price,
82
+ size,
83
+ timestamp,
84
+ tid,
85
+ notionalUsd: price * size
86
+ };
87
+ };
88
+ var normalizeHyperliquidWsTrade = (params) => {
89
+ const normalized = normalizeTradeFields(params.trade);
90
+ if (!normalized || !params.trackedSymbols.has(normalized.symbol)) return null;
91
+ const users = Array.isArray(params.trade.users) ? params.trade.users : [];
92
+ const buyerAddress = normalizeAddress(users[0]);
93
+ const sellerAddress = normalizeAddress(users[1]);
94
+ const buyerTracked = buyerAddress != null && params.trackedWhales.has(buyerAddress);
95
+ const sellerTracked = sellerAddress != null && params.trackedWhales.has(sellerAddress);
96
+ if (!buyerTracked && !sellerTracked) return null;
97
+ return {
98
+ symbol: normalized.symbol,
99
+ ts: new Date(normalized.timestamp),
100
+ tid: normalized.tid,
101
+ price: normalized.price,
102
+ size: normalized.size,
103
+ notionalUsd: normalized.notionalUsd,
104
+ buyerAddress,
105
+ sellerAddress,
106
+ buyerTracked,
107
+ sellerTracked,
108
+ ...params.identity,
109
+ source: "hyperliquid_trades"
110
+ };
111
+ };
112
+ var normalizeHyperliquidUserFill = (params) => {
113
+ const normalized = normalizeTradeFields(params.fill);
114
+ if (!normalized || !params.trackedSymbols.has(normalized.symbol)) return null;
115
+ const address = normalizeAddress(params.address);
116
+ if (!address) return null;
117
+ const side = String(params.fill.side ?? "").toUpperCase();
118
+ if (side !== "B" && side !== "A") return null;
119
+ const positionChange = classifyHyperliquidPositionChange({
120
+ startPosition: params.fill.startPosition,
121
+ side,
122
+ size: normalized.size
123
+ });
124
+ const closedPnl = finiteNumber(params.fill.closedPnl);
125
+ const liquidation = params.fill.liquidation != null && typeof params.fill.liquidation === "object";
126
+ const positionFields = positionChange ? side === "B" ? {
127
+ buyerStartPosition: positionChange.startPosition,
128
+ buyerEndPosition: positionChange.endPosition,
129
+ buyerPositionAction: positionChange.action,
130
+ buyerClosedPnl: closedPnl,
131
+ buyerLiquidation: liquidation
132
+ } : {
133
+ sellerStartPosition: positionChange.startPosition,
134
+ sellerEndPosition: positionChange.endPosition,
135
+ sellerPositionAction: positionChange.action,
136
+ sellerClosedPnl: closedPnl,
137
+ sellerLiquidation: liquidation
138
+ } : {};
139
+ return {
140
+ symbol: normalized.symbol,
141
+ ts: new Date(normalized.timestamp),
142
+ tid: normalized.tid,
143
+ price: normalized.price,
144
+ size: normalized.size,
145
+ notionalUsd: normalized.notionalUsd,
146
+ buyerAddress: side === "B" ? address : null,
147
+ sellerAddress: side === "A" ? address : null,
148
+ buyerTracked: side === "B",
149
+ sellerTracked: side === "A",
150
+ ...positionFields,
151
+ ...params.identity,
152
+ source: "hyperliquid_user_fills"
153
+ };
154
+ };
155
+ var eventKey = (event) => `${event.universeFingerprint}:${event.whaleRegistryFingerprint}:${event.symbol}:${event.ts.getTime()}:${event.tid}`;
156
+ var mergeEvent = (left, right) => ({
157
+ ...left,
158
+ buyerAddress: left.buyerAddress ?? right.buyerAddress,
159
+ sellerAddress: left.sellerAddress ?? right.sellerAddress,
160
+ buyerTracked: left.buyerTracked || right.buyerTracked,
161
+ sellerTracked: left.sellerTracked || right.sellerTracked,
162
+ buyerStartPosition: left.buyerStartPosition ?? right.buyerStartPosition,
163
+ buyerEndPosition: left.buyerEndPosition ?? right.buyerEndPosition,
164
+ buyerPositionAction: left.buyerPositionAction ?? right.buyerPositionAction,
165
+ buyerClosedPnl: left.buyerClosedPnl ?? right.buyerClosedPnl,
166
+ buyerLiquidation: left.buyerLiquidation ?? right.buyerLiquidation,
167
+ sellerStartPosition: left.sellerStartPosition ?? right.sellerStartPosition,
168
+ sellerEndPosition: left.sellerEndPosition ?? right.sellerEndPosition,
169
+ sellerPositionAction: left.sellerPositionAction ?? right.sellerPositionAction,
170
+ sellerClosedPnl: left.sellerClosedPnl ?? right.sellerClosedPnl,
171
+ sellerLiquidation: left.sellerLiquidation ?? right.sellerLiquidation
172
+ });
173
+ var aggregateHyperliquidWhaleEvents = (events) => {
174
+ const deduplicated = /* @__PURE__ */ new Map();
175
+ for (const event of events) {
176
+ const key = eventKey(event);
177
+ const previous = deduplicated.get(key);
178
+ deduplicated.set(key, previous ? mergeEvent(previous, event) : event);
179
+ }
180
+ const buckets = /* @__PURE__ */ new Map();
181
+ for (const event of deduplicated.values()) {
182
+ const bucketTs = Math.floor(event.ts.getTime() / HYPERLIQUID_WHALE_BUCKET_MS) * HYPERLIQUID_WHALE_BUCKET_MS;
183
+ const key = `${event.universeFingerprint}:${event.whaleRegistryFingerprint}:${event.symbol}:${bucketTs}`;
184
+ const row = buckets.get(key) ?? {
185
+ symbol: event.symbol,
186
+ interval: "1m",
187
+ ts: new Date(bucketTs),
188
+ trades: 0,
189
+ whaleSides: 0,
190
+ uniqueWhales: 0,
191
+ buyNotionalUsd: 0,
192
+ sellNotionalUsd: 0,
193
+ netNotionalUsd: 0,
194
+ buySharePct: null,
195
+ positionAwareWhaleSides: 0,
196
+ longEntryWhaleAddresses: /* @__PURE__ */ new Set(),
197
+ shortEntryWhaleAddresses: /* @__PURE__ */ new Set(),
198
+ longExitWhaleAddresses: /* @__PURE__ */ new Set(),
199
+ shortExitWhaleAddresses: /* @__PURE__ */ new Set(),
200
+ longEntryNotionalUsd: 0,
201
+ shortEntryNotionalUsd: 0,
202
+ longExitNotionalUsd: 0,
203
+ shortExitNotionalUsd: 0,
204
+ entryNetNotionalUsd: 0,
205
+ entryLongSharePct: null,
206
+ universeFingerprint: event.universeFingerprint,
207
+ whaleRegistryFingerprint: event.whaleRegistryFingerprint,
208
+ source: "hyperliquid_trades",
209
+ whaleAddresses: /* @__PURE__ */ new Set()
210
+ };
211
+ row.trades += 1;
212
+ if (event.buyerTracked) {
213
+ row.whaleSides += 1;
214
+ row.buyNotionalUsd += event.notionalUsd;
215
+ if (event.buyerAddress) row.whaleAddresses.add(event.buyerAddress);
216
+ }
217
+ if (event.sellerTracked) {
218
+ row.whaleSides += 1;
219
+ row.sellNotionalUsd += event.notionalUsd;
220
+ if (event.sellerAddress) row.whaleAddresses.add(event.sellerAddress);
221
+ }
222
+ const applyPositionLeg = (params) => {
223
+ if (!params.address || !Number.isFinite(params.startPosition) || !Number.isFinite(params.endPosition)) {
224
+ return;
225
+ }
226
+ const startPosition = Number(params.startPosition);
227
+ const endPosition = Number(params.endPosition);
228
+ const longEntrySize = Math.max(
229
+ 0,
230
+ Math.max(endPosition, 0) - Math.max(startPosition, 0)
231
+ );
232
+ const shortEntrySize = Math.max(
233
+ 0,
234
+ Math.max(-endPosition, 0) - Math.max(-startPosition, 0)
235
+ );
236
+ const longExitSize = Math.max(
237
+ 0,
238
+ Math.max(startPosition, 0) - Math.max(endPosition, 0)
239
+ );
240
+ const shortExitSize = Math.max(
241
+ 0,
242
+ Math.max(-startPosition, 0) - Math.max(-endPosition, 0)
243
+ );
244
+ row.positionAwareWhaleSides += 1;
245
+ row.longEntryNotionalUsd += longEntrySize * event.price;
246
+ row.shortEntryNotionalUsd += shortEntrySize * event.price;
247
+ row.longExitNotionalUsd += longExitSize * event.price;
248
+ row.shortExitNotionalUsd += shortExitSize * event.price;
249
+ if (longEntrySize > 0) row.longEntryWhaleAddresses.add(params.address);
250
+ if (shortEntrySize > 0) row.shortEntryWhaleAddresses.add(params.address);
251
+ if (longExitSize > 0) row.longExitWhaleAddresses.add(params.address);
252
+ if (shortExitSize > 0) row.shortExitWhaleAddresses.add(params.address);
253
+ };
254
+ if (event.buyerTracked) {
255
+ applyPositionLeg({
256
+ address: event.buyerAddress,
257
+ startPosition: event.buyerStartPosition,
258
+ endPosition: event.buyerEndPosition
259
+ });
260
+ }
261
+ if (event.sellerTracked) {
262
+ applyPositionLeg({
263
+ address: event.sellerAddress,
264
+ startPosition: event.sellerStartPosition,
265
+ endPosition: event.sellerEndPosition
266
+ });
267
+ }
268
+ row.uniqueWhales = row.whaleAddresses.size;
269
+ row.netNotionalUsd = row.buyNotionalUsd - row.sellNotionalUsd;
270
+ const total = row.buyNotionalUsd + row.sellNotionalUsd;
271
+ row.buySharePct = total > 0 ? row.buyNotionalUsd / total : null;
272
+ row.entryNetNotionalUsd = row.longEntryNotionalUsd - row.shortEntryNotionalUsd;
273
+ const entryTotal = row.longEntryNotionalUsd + row.shortEntryNotionalUsd;
274
+ row.entryLongSharePct = entryTotal > 0 ? row.longEntryNotionalUsd / entryTotal : null;
275
+ if (row.positionAwareWhaleSides > 0) {
276
+ row.source = "hyperliquid_user_fills";
277
+ }
278
+ buckets.set(key, row);
279
+ }
280
+ return [...buckets.values()].map(
281
+ ({
282
+ whaleAddresses,
283
+ longEntryWhaleAddresses,
284
+ shortEntryWhaleAddresses,
285
+ longExitWhaleAddresses,
286
+ shortExitWhaleAddresses,
287
+ ...row
288
+ }) => ({
289
+ ...row,
290
+ whaleAddresses: [...whaleAddresses].sort(),
291
+ longEntryWhaleAddresses: [...longEntryWhaleAddresses].sort(),
292
+ shortEntryWhaleAddresses: [...shortEntryWhaleAddresses].sort(),
293
+ longExitWhaleAddresses: [...longExitWhaleAddresses].sort(),
294
+ shortExitWhaleAddresses: [...shortExitWhaleAddresses].sort()
295
+ })
296
+ ).sort(
297
+ (left, right) => left.ts.getTime() - right.ts.getTime() || left.symbol.localeCompare(right.symbol)
298
+ );
299
+ };
300
+ // Annotate the CommonJS export names for ESM import in node:
301
+ 0 && (module.exports = {
302
+ HYPERLIQUID_WHALE_BUCKET_MS,
303
+ aggregateHyperliquidWhaleEvents,
304
+ classifyHyperliquidPositionChange,
305
+ normalizeHyperliquidUserFill,
306
+ normalizeHyperliquidWsTrade
307
+ });
@@ -0,0 +1,116 @@
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/hyperliquidWhaleSelection.ts
21
+ var hyperliquidWhaleSelection_exports = {};
22
+ __export(hyperliquidWhaleSelection_exports, {
23
+ HYPERLIQUID_WHALE_SELECTION: () => HYPERLIQUID_WHALE_SELECTION,
24
+ evaluateHyperliquidWhaleStructure: () => evaluateHyperliquidWhaleStructure,
25
+ rankHyperliquidStructuralWhales: () => rankHyperliquidStructuralWhales
26
+ });
27
+ module.exports = __toCommonJS(hyperliquidWhaleSelection_exports);
28
+ var HYPERLIQUID_WHALE_SELECTION = {
29
+ minimumAccountValueUsd: 5e5,
30
+ minimumActiveDays: 1,
31
+ maximumRawFillsPerDay: 20,
32
+ maximumDirectionalExecutionsPerDay: 10,
33
+ minimumMedianNotionalUsd: 0,
34
+ minimumMedianInterExecutionMinutes: 0,
35
+ minimumTop30NotionalShare: 1e-3,
36
+ minimumTurnoverToEquity: 0.05,
37
+ maximumTurnoverToEquity: 5
38
+ };
39
+ var finiteNumber = (value) => {
40
+ const parsed = Number(value);
41
+ return Number.isFinite(parsed) ? parsed : 0;
42
+ };
43
+ var median = (values) => {
44
+ if (!values.length) return 0;
45
+ const sorted = [...values].sort((left, right) => left - right);
46
+ const middle = Math.floor(sorted.length / 2);
47
+ return sorted.length % 2 ? sorted[middle] : (sorted[middle - 1] + sorted[middle]) / 2;
48
+ };
49
+ var evaluateHyperliquidWhaleStructure = (params) => {
50
+ const fills = params.fills.filter((fill) => {
51
+ const time = finiteNumber(fill.time);
52
+ return time >= params.calibrationFromMs && time < params.calibrationToMs;
53
+ }).sort((left, right) => finiteNumber(left.time) - finiteNumber(right.time));
54
+ const days = Math.max(
55
+ 1,
56
+ (params.calibrationToMs - params.calibrationFromMs) / 864e5
57
+ );
58
+ const executions = fills.reduce((clusters, fill) => {
59
+ const coin = String(fill.coin);
60
+ const side = String(fill.side);
61
+ const time = finiteNumber(fill.time);
62
+ const notionalUsd = Math.abs(finiteNumber(fill.px) * finiteNumber(fill.sz));
63
+ const previous = clusters.at(-1);
64
+ if (previous && previous.coin === coin && previous.side === side && time - previous.time <= 6e4) {
65
+ previous.time = time;
66
+ previous.notionalUsd += notionalUsd;
67
+ } else {
68
+ clusters.push({ coin, side, time, notionalUsd });
69
+ }
70
+ return clusters;
71
+ }, []);
72
+ const notionals = executions.map((execution) => execution.notionalUsd);
73
+ const totalNotional = notionals.reduce((sum, value) => sum + value, 0);
74
+ const top30Notional = executions.reduce(
75
+ (sum, execution) => sum + (params.top30Symbols.has(execution.coin) ? execution.notionalUsd : 0),
76
+ 0
77
+ );
78
+ const interExecutionMinutes = executions.slice(1).map(
79
+ (execution, index) => (execution.time - executions[index].time) / 6e4
80
+ ).filter((value) => value >= 0);
81
+ const activeDays = new Set(
82
+ fills.map(
83
+ (fill) => new Date(finiteNumber(fill.time)).toISOString().slice(0, 10)
84
+ )
85
+ ).size;
86
+ const rawFillsPerDay = fills.length / days;
87
+ const directionalExecutionsPerDay = executions.length / days;
88
+ const medianNotionalUsd = median(notionals);
89
+ const medianInterExecutionMinutes = median(interExecutionMinutes);
90
+ const top30NotionalShare = totalNotional > 0 ? top30Notional / totalNotional : 0;
91
+ const eligible = params.accountValueUsd >= HYPERLIQUID_WHALE_SELECTION.minimumAccountValueUsd && activeDays >= HYPERLIQUID_WHALE_SELECTION.minimumActiveDays && rawFillsPerDay <= HYPERLIQUID_WHALE_SELECTION.maximumRawFillsPerDay && directionalExecutionsPerDay <= HYPERLIQUID_WHALE_SELECTION.maximumDirectionalExecutionsPerDay && medianNotionalUsd >= HYPERLIQUID_WHALE_SELECTION.minimumMedianNotionalUsd && medianInterExecutionMinutes >= HYPERLIQUID_WHALE_SELECTION.minimumMedianInterExecutionMinutes && top30NotionalShare >= HYPERLIQUID_WHALE_SELECTION.minimumTop30NotionalShare;
92
+ const score = Math.log1p(params.accountValueUsd) * Math.log1p(medianNotionalUsd) * Math.log1p(Math.max(1, medianInterExecutionMinutes)) * Math.sqrt(Math.max(0, activeDays)) * top30NotionalShare / Math.sqrt(1 + rawFillsPerDay);
93
+ return {
94
+ address: params.address.toLowerCase(),
95
+ accountValueUsd: params.accountValueUsd,
96
+ rawFills: fills.length,
97
+ rawFillsPerDay,
98
+ directionalExecutions: executions.length,
99
+ directionalExecutionsPerDay,
100
+ activeDays,
101
+ medianNotionalUsd,
102
+ medianInterExecutionMinutes,
103
+ top30NotionalShare,
104
+ score,
105
+ eligible
106
+ };
107
+ };
108
+ var rankHyperliquidStructuralWhales = (metrics, limit = 100) => metrics.filter((row) => row.eligible).sort(
109
+ (left, right) => right.score - left.score || left.address.localeCompare(right.address)
110
+ ).slice(0, limit);
111
+ // Annotate the CommonJS export names for ESM import in node:
112
+ 0 && (module.exports = {
113
+ HYPERLIQUID_WHALE_SELECTION,
114
+ evaluateHyperliquidWhaleStructure,
115
+ rankHyperliquidStructuralWhales
116
+ });