@tradejs/node 2.0.13 → 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.
@@ -5556,6 +5556,7 @@ __export(strategies_exports, {
5556
5556
  enrichSignalWithAi: () => enrichSignalWithAi,
5557
5557
  enrichSignalWithBinanceMarketContext: () => enrichSignalWithBinanceMarketContext,
5558
5558
  enrichSignalWithCoinMarketCapContext: () => enrichSignalWithCoinMarketCapContext,
5559
+ enrichSignalWithHyperliquidWhaleContext: () => enrichSignalWithHyperliquidWhaleContext,
5559
5560
  enrichSignalWithMl: () => enrichSignalWithMl,
5560
5561
  enrichSignalWithMlAi: () => enrichSignalWithMlAi,
5561
5562
  ensureAiStrategyPluginsLoaded: () => ensureAiStrategyPluginsLoaded,
@@ -5566,6 +5567,10 @@ __export(strategies_exports, {
5566
5567
  getBinanceBreadthUniverseSnapshot: () => getBinanceBreadthUniverseSnapshot,
5567
5568
  getBinanceBreadthUniverses: () => getBinanceBreadthUniverses,
5568
5569
  getDeterministicAiGateContext: () => getDeterministicAiGateContext,
5570
+ getHyperliquidPerpSymbols: () => getHyperliquidPerpSymbols,
5571
+ getHyperliquidPerpUniverseSnapshot: () => getHyperliquidPerpUniverseSnapshot,
5572
+ getHyperliquidWhaleAddresses: () => getHyperliquidWhaleAddresses,
5573
+ getHyperliquidWhaleRegistrySnapshot: () => getHyperliquidWhaleRegistrySnapshot,
5569
5574
  getOpenRouterModelKwargs: () => getOpenRouterModelKwargs,
5570
5575
  getOrderArrivalSnapshot: () => getOrderArrivalSnapshot,
5571
5576
  getPrimaryBinanceBreadthUniverse: () => getPrimaryBinanceBreadthUniverse,
@@ -5574,9 +5579,12 @@ __export(strategies_exports, {
5574
5579
  getStrategyCreator: () => getStrategyCreator,
5575
5580
  getStrategyManifest: () => getStrategyManifest,
5576
5581
  isKnownStrategy: () => isKnownStrategy,
5582
+ isTrackedHyperliquidPerp: () => isTrackedHyperliquidPerp,
5583
+ isTrackedHyperliquidWhale: () => isTrackedHyperliquidWhale,
5577
5584
  registerStrategyEntries: () => registerStrategyEntries,
5578
5585
  resetAiRuntimeCache: () => resetAiRuntimeCache,
5579
5586
  resetStrategyRegistryCache: () => resetStrategyRegistryCache,
5587
+ resolveHyperliquidPerpFromSignalSymbol: () => resolveHyperliquidPerpFromSignalSymbol,
5580
5588
  resolveStrategyConfig: () => resolveStrategyConfig,
5581
5589
  runAiPrompt: () => runAiPrompt,
5582
5590
  runAiPromptLocal: () => runAiPromptLocal,
@@ -6932,7 +6940,7 @@ Input payload structure:
6932
6940
  \u2022 \`baseContext.raw\`: current MA, ATR, BB, OBV, price stats, levels, BTC correlation.
6933
6941
  \u2022 \`baseContext.regime\`: derived trend / volatility / momentum / session regime fields.
6934
6942
  \u2022 \`baseContext.structure\`: local range position, breakout freshness/quality, level-touch counts, rejection wick context.
6935
- \u2022 \`baseContext.participation\`: volume/turnover participation, effort-vs-result context, and Binance aggTrades trade-flow when available.
6943
+ \u2022 \`baseContext.participation\`: volume/turnover participation, effort-vs-result context, Binance aggTrades, and fingerprinted Hyperliquid whale-flow when available.
6936
6944
  \u2022 \`baseContext.relative\`: BTC/ETH relative-strength, benchmark MA bias context, Binance alt-basket breadth, and CoinMarketCap historical global/exchange/index context when available.
6937
6945
  \u2022 \`baseContext.derivatives\`: Coinalyze-aligned derivatives summary when available.
6938
6946
  \u2022 \`baseContext.mtf\`: compact multi-timeframe summary plus only the latest few candles for each timeframe.
@@ -7253,12 +7261,12 @@ var askAI = async (signal, options = {}) => {
7253
7261
  // src/strategyRuntime.ts
7254
7262
  var import_node_path2 = __toESM(require("path"));
7255
7263
  var import_constants4 = require("@tradejs/core/constants");
7256
- var import_data2 = require("@tradejs/core/data");
7257
- var import_strategies4 = require("@tradejs/core/strategies");
7258
- var import_logger8 = require("@tradejs/infra/logger");
7264
+ var import_data3 = require("@tradejs/core/data");
7265
+ var import_strategies5 = require("@tradejs/core/strategies");
7266
+ var import_logger9 = require("@tradejs/infra/logger");
7259
7267
 
7260
7268
  // src/strategyHelpers/runtime.ts
7261
- var import_logger7 = require("@tradejs/infra/logger");
7269
+ var import_logger8 = require("@tradejs/infra/logger");
7262
7270
  var import_constants3 = require("@tradejs/core/constants");
7263
7271
  var import_ml2 = require("@tradejs/infra/ml");
7264
7272
 
@@ -8856,6 +8864,562 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
8856
8864
  }
8857
8865
  };
8858
8866
 
8867
+ // src/strategyHelpers/hyperliquidWhaleContext.ts
8868
+ var import_data2 = require("@tradejs/core/data");
8869
+ var import_strategies4 = require("@tradejs/core/strategies");
8870
+ var import_timescale4 = require("@tradejs/infra/timescale");
8871
+ var import_logger7 = require("@tradejs/infra/logger");
8872
+
8873
+ // src/hyperliquidWhaleUniverse.ts
8874
+ var import_node_crypto3 = require("crypto");
8875
+
8876
+ // src/config/hyperliquidPerpUniverse.json
8877
+ var hyperliquidPerpUniverse_default = {
8878
+ schemaVersion: 1,
8879
+ updatedAt: "2026-08-04T11:46:43.476Z",
8880
+ source: "hyperliquid_main_perp_day_notional_volume",
8881
+ fingerprint: "58f7e024b19158dc",
8882
+ size: 30,
8883
+ symbols: [
8884
+ "BTC",
8885
+ "ETH",
8886
+ "HYPE",
8887
+ "SOL",
8888
+ "ZEC",
8889
+ "PUMP",
8890
+ "XRP",
8891
+ "CASHCAT",
8892
+ "WLD",
8893
+ "GRAM",
8894
+ "UNI",
8895
+ "ADA",
8896
+ "LIT",
8897
+ "ENA",
8898
+ "NEAR",
8899
+ "kPEPE",
8900
+ "FARTCOIN",
8901
+ "KAITO",
8902
+ "AAVE",
8903
+ "SUI",
8904
+ "ONDO",
8905
+ "AVAX",
8906
+ "DOGE",
8907
+ "VVV",
8908
+ "BNB",
8909
+ "ALGO",
8910
+ "XMR",
8911
+ "MEGA",
8912
+ "LINK",
8913
+ "TAO"
8914
+ ]
8915
+ };
8916
+
8917
+ // src/config/hyperliquidWhales.json
8918
+ var hyperliquidWhales_default = {
8919
+ schemaVersion: 2,
8920
+ updatedAt: "2026-08-04T15:10:21.316Z",
8921
+ source: "hyperliquid_structural_fills_snapshot",
8922
+ selection: {
8923
+ calibrationFrom: "2026-07-28T00:00:00.000Z",
8924
+ calibrationTo: "2026-08-04T00:00:00.000Z",
8925
+ effectiveFrom: "2026-08-04T00:00:00.000Z",
8926
+ candidateLimit: 400,
8927
+ minimumAccountValueUsd: 5e5,
8928
+ minimumActiveDays: 1,
8929
+ maximumRawFillsPerDay: 20,
8930
+ maximumDirectionalExecutionsPerDay: 10,
8931
+ minimumMedianNotionalUsd: 0,
8932
+ minimumMedianInterExecutionMinutes: 0,
8933
+ minimumTop30NotionalShare: 1e-3,
8934
+ minimumTurnoverToEquity: 0.05,
8935
+ maximumTurnoverToEquity: 5,
8936
+ score: "log1p(accountValue)*log1p(medianExecutionNotional)*log1p(max(1,medianInterExecutionMinutes))*sqrt(activeDays)*top30Share/sqrt(1+rawFillsPerDay)",
8937
+ forbiddenSelectionMetrics: ["pnl", "roi", "winRate", "closedPnl"]
8938
+ },
8939
+ fingerprint: "77a6e9d41222efdb",
8940
+ size: 100,
8941
+ addresses: [
8942
+ "0xacb66d1996501bcc82a0e7819c9e041599f5efbd",
8943
+ "0x90dbb196cacf24bd212b377a0dd62eaad5e8151b",
8944
+ "0xde5b8c8e713f7c29ec72c22a326d61e5ac76e402",
8945
+ "0x22edc38749b59c31c9319eae7fc62143ac2fcc6c",
8946
+ "0x4bc9a771cd2c96cb2a4501f2c049402b4e7e11b3",
8947
+ "0x9a0825ca6c4c577a1202a8fae3b8f044c1d5711d",
8948
+ "0xb6ca5d1ed0ca4bf8444c9dee2d068a9f4c5e2e92",
8949
+ "0xc3610d02548cdb1a30ede87c5dc0d2ffe5b9b99f",
8950
+ "0x48c6aaa647ad5197e85797f8eb95d7b9ce1ec5b6",
8951
+ "0x8c1ab015da7e5319649afca4a551924f89eff883",
8952
+ "0x64bddab5f13a99576fca6747f0aa205422c5f708",
8953
+ "0x98785f2a43fe32f972476b86ed5a5cfaf5240f00",
8954
+ "0x9836e286fbf4f71998827d4bd6ea3b470c26457e",
8955
+ "0x8f8d2d2565bfb10608a7ce64b48e2aea7875a344",
8956
+ "0xe6df4ed7a6ccb8426cbc87bdcdd3cc6d0e6c0690",
8957
+ "0xab04d040dec929a204298d44701476968b238b69",
8958
+ "0x870f718a84843abc3e22412a9b4dc2924466d448",
8959
+ "0x12c206d3e2f0d0059420c54d33fe604ebbecc230",
8960
+ "0x7d9e91a8a47eb553cbfd323e7633c0c213327124",
8961
+ "0x2057d4f2b6ea957b63371980775b0a5505a438f0",
8962
+ "0xead5b7d86c681c036c59cd00a0390541061c69f2",
8963
+ "0x3005fade4c0df5e1cd187d7062da359416f0eb8e",
8964
+ "0xe83b5e3644b50e802a25b34b38b91a061a0d3ca8",
8965
+ "0x525232cb6ed5030d2b052b36bfc0baec96986ee3",
8966
+ "0xa251520154ca342f0b1d702bf5a56f78c982405b",
8967
+ "0xa9184bb57fd75c7c63e4c074d6319eceac6be53b",
8968
+ "0xa20fb0c9e04063eec5be286e9269028d966646fa",
8969
+ "0x169ba96d963e77a87dbe58922ecdcdd0f0cf3315",
8970
+ "0x115849ce84370f25cadcf0d348510d73837e1aa5",
8971
+ "0x37b81ab9e3ab04b9e3738e4891621205aaa31fd5",
8972
+ "0x90f57d90a7dd3114312d4c31803ad5732baf5935",
8973
+ "0xad227f63d34e7251c1d0ab65e64eeea07aee4e44",
8974
+ "0xd38e2b0b3c85ae138532f9fe1a1d5f5455866b82",
8975
+ "0xf5f4c3aa62a0f903a8529905031b1536d1cf16f8",
8976
+ "0x75632aaf83120eae9b0618f8f50773ce347de2ad",
8977
+ "0x3927af597c09774f91ef84bf765ded4109e9f8ea",
8978
+ "0xf1863bd6d60a8f4b5f583ec54009af6a044877bf",
8979
+ "0xe7b34f28c54f85533896f8827edc92edac28b17f",
8980
+ "0x1cda20f9f6a23c209d54940af3ef63b96c9b2c31",
8981
+ "0x9e55b0e43b7f7f3909af841d326b2dadfda9392e",
8982
+ "0x610b8dd6b392d010c2b6ad8d121dfc09524cb613",
8983
+ "0x1d639a688b78f3d7e57166e59d9a8886b1bfb5a5",
8984
+ "0x34d3a17095ef7def39a489d63c7c916e673c9ca2",
8985
+ "0x5d0bde4017530ed43370e332a5d30194941f73c6",
8986
+ "0xaa7afc250041e2c56a06d3b7a5295bd01929e11b",
8987
+ "0x325edd95bb016c36027ce3b9f7595af7094a9564",
8988
+ "0x47f5a6397b79deaaca5c456503e7c1a49357b942",
8989
+ "0xf5e7ffe523d0491709958490b4877e1d9de6c6f7",
8990
+ "0x64702807a1f0f9888ea22b858099d7f481227b55",
8991
+ "0xd08a4557671ca465e7bba41110a93148c90f9931",
8992
+ "0x0423b4b2acb4f219ae4a270abd5dde2360e455bb",
8993
+ "0x7b29f8c0ea709b96b72214b3de5d85c3d9570794",
8994
+ "0xeb8ebad162a9ce4cb7e2325c92b960b9df63365c",
8995
+ "0x939f95036d2e7b6d7419ec072bf9d967352204d2",
8996
+ "0x2490aa2b48022e857d44e738911787c8e2296aed",
8997
+ "0x7622f628135378f1b8d1876952de9bab80245f1c",
8998
+ "0x9d677028e0e592d48fc8a8ddc910693301a4a450",
8999
+ "0x85e410e4c535cb1709dbd36468f132037a5b2087",
9000
+ "0xd6f52e2ab58a678eced4a4d1693757b0677631c8",
9001
+ "0x24d8969e2bd6aabb6c4dfe042ef8b2cd8085217e",
9002
+ "0xda51323fe9800c8365646ad5c7ade0dd17fdc167",
9003
+ "0x53f8f390fd4f70941c5d160a964f6893c8dbceff",
9004
+ "0x72dae3560e7f4c59a305e2e739d6bd6777f738b5",
9005
+ "0x36f5e448c9cf0032551e58919cf4eabefcd742c1",
9006
+ "0x5b43b7162694de766c164202df0f0c716e4292ab",
9007
+ "0xae551d73161bac3315c5ade0e2d499a44ebe2236",
9008
+ "0x4eca8d62e07b3f3e78a8ae8725d4666da324c5a8",
9009
+ "0x40a632026febd007b0e4431a29170507f7aa3896",
9010
+ "0xd453e91f692eb5437cf345e09545827576e3225d",
9011
+ "0xbe2c69eb3d7b8ee35cbe3a28293472be31179d75",
9012
+ "0xfdf891f2b214a4c9374d26595ec6d4080262e381",
9013
+ "0xfd97600ac44b3c4e20ac1a5f23e3b18d10fa5912",
9014
+ "0x98e073b579fd483eac8f10d5bd0b32c8c3bbd7e0",
9015
+ "0xb56f19e917546a60d658110a611cf62a6877b517",
9016
+ "0xbd334a55db91617545e8d1b09941e036ad8e4200",
9017
+ "0x9f1920d0cbb63ed03376a1e09fd2851d601234c8",
9018
+ "0xe9cef9fd872a03cedf9d3e6e90309782b3724ea6",
9019
+ "0xa43682a1f129e4faf0152175cc03c44e4957e8cf",
9020
+ "0x6fbb33de5f39c690d2decb95b9ab46ed0c83e3bc",
9021
+ "0x81d4163289cf61a0eaaac4862cb88ef0f4215c29",
9022
+ "0xd248d2f09bfbe04e67fc7fea08828d6ad6d95b6d",
9023
+ "0x01ffcc7285866e5cee14c8e807cb2e8d5f61079f",
9024
+ "0xc69ae428f6049e78d445f053d2c1df879c59b34c",
9025
+ "0xaab4dfe6d735c4ac46217216fe883a39fbfe8284",
9026
+ "0xe912cac1a6641004a8803687ee7699227fdb0550",
9027
+ "0x5fdbf83c3d95d525704f61401db68cbec1b2a775",
9028
+ "0xebd7c4b3677a4480fb5f69ac2f51c51d66a19990",
9029
+ "0xe4d1fa7e6141f9131345117bdb8b5701bca67662",
9030
+ "0x685feceec46dd4e5c9b5b726f5d7550fd0eda526",
9031
+ "0x3ea8b09da72972e953541500721803a187526da6",
9032
+ "0xdbe0780a5c5a0e3b345101bbc01ac2218196d6d5",
9033
+ "0x18cd4597e06b7fe0a8cd33dda499121b3a145a8b",
9034
+ "0xb8243756956e722bff5c763971b562ac551bfbd2",
9035
+ "0xe0bf8c96795d2df0b61b3b17e7cfd7d3ba13d4be",
9036
+ "0x218a65e21eddeece7a9df38c6bbdd89f692b7da2",
9037
+ "0x53b63a30a688beb53b5dc7bd731c661d678c555c",
9038
+ "0xfce053a5e461683454bf37ad66d20344c0e3f4c0",
9039
+ "0x3e516cf3c9d4f29fae6c1324c2414dc872fc9c09",
9040
+ "0xe5f1486dc84706d2509885fe6bbc46d21ba81286",
9041
+ "0x38042d713af713f0275b00640a83654db91ea543"
9042
+ ]
9043
+ };
9044
+
9045
+ // src/hyperliquidWhaleUniverse.ts
9046
+ var fingerprint2 = (value) => (0, import_node_crypto3.createHash)("sha256").update(JSON.stringify(value)).digest("hex").slice(0, 16);
9047
+ var validateUnique = (values, label) => {
9048
+ if (new Set(values).size !== values.length) {
9049
+ throw new Error(`Hyperliquid ${label} snapshot contains duplicates`);
9050
+ }
9051
+ };
9052
+ var validatePerpSnapshot = (value) => {
9053
+ const symbols = value.symbols.map((symbol) => symbol.trim()).filter(Boolean);
9054
+ validateUnique(symbols, "perp universe");
9055
+ if (value.schemaVersion !== 1 || value.source !== "hyperliquid_main_perp_day_notional_volume" || value.size !== 30 || symbols.length !== 30 || value.fingerprint !== fingerprint2(symbols)) {
9056
+ throw new Error("Invalid Hyperliquid perp universe snapshot");
9057
+ }
9058
+ return value;
9059
+ };
9060
+ var validateWhaleSnapshot = (value) => {
9061
+ const addresses = value.addresses.map((address) => address.toLowerCase());
9062
+ validateUnique(addresses, "whale registry");
9063
+ if (value.schemaVersion !== 2 || value.source !== "hyperliquid_structural_fills_snapshot" || value.size !== 100 || addresses.length !== 100 || addresses.some((address) => !/^0x[0-9a-f]{40}$/.test(address)) || value.fingerprint !== fingerprint2(addresses)) {
9064
+ throw new Error("Invalid Hyperliquid whale registry snapshot");
9065
+ }
9066
+ return value;
9067
+ };
9068
+ var perpSnapshot = validatePerpSnapshot(hyperliquidPerpUniverse_default);
9069
+ var whaleSnapshot = validateWhaleSnapshot(hyperliquidWhales_default);
9070
+ var perpSymbolSet = new Set(perpSnapshot.symbols);
9071
+ var whaleAddressSet = new Set(whaleSnapshot.addresses);
9072
+ var getHyperliquidPerpUniverseSnapshot = () => perpSnapshot;
9073
+ var getHyperliquidWhaleRegistrySnapshot = () => whaleSnapshot;
9074
+ var getHyperliquidPerpSymbols = () => [...perpSnapshot.symbols];
9075
+ var getHyperliquidWhaleAddresses = () => [...whaleSnapshot.addresses];
9076
+ var isTrackedHyperliquidPerp = (symbol) => perpSymbolSet.has(symbol.trim());
9077
+ var isTrackedHyperliquidWhale = (address) => whaleAddressSet.has(address.trim().toLowerCase());
9078
+ var SIGNAL_TO_HYPERLIQUID_ALIASES = {
9079
+ PEPE: "kPEPE",
9080
+ "1000PEPE": "kPEPE",
9081
+ PUMPFUN: "PUMP",
9082
+ SHIB: "kSHIB",
9083
+ BONK: "kBONK"
9084
+ };
9085
+ var resolveHyperliquidPerpFromSignalSymbol = (symbol) => {
9086
+ const normalized = symbol.trim().toUpperCase().replace(/(?:USDT|USDC)$/, "");
9087
+ const candidate = SIGNAL_TO_HYPERLIQUID_ALIASES[normalized] ?? normalized;
9088
+ return perpSymbolSet.has(candidate) ? candidate : null;
9089
+ };
9090
+
9091
+ // src/strategyHelpers/hyperliquidWhaleContext.ts
9092
+ var MAX_CACHE_ENTRIES = 2048;
9093
+ var MAX_COVERAGE_SERIES_CACHE_ENTRIES = 20;
9094
+ var MAX_FLOW_SERIES_CACHE_ENTRIES = 64;
9095
+ var SERIES_CHUNK_MS = 30 * 24 * 60 * 6e4;
9096
+ var MAX_SERIES_LOOKBACK_MS = 60 * 6e4;
9097
+ var DEFAULT_MIN_COVERAGE_PCT = 0.8;
9098
+ var INTERVAL_MS = {
9099
+ "1m": 6e4,
9100
+ "5m": 5 * 6e4,
9101
+ "15m": 15 * 6e4,
9102
+ "1h": 60 * 6e4
9103
+ };
9104
+ var DEFAULT_MAX_AGE_BY_INTERVAL2 = {
9105
+ "1m": 2 * 6e4,
9106
+ "5m": 10 * 6e4,
9107
+ "15m": 30 * 6e4,
9108
+ "1h": 2 * 60 * 6e4
9109
+ };
9110
+ var hyperliquidWhaleContextUnavailable = false;
9111
+ var contextCache = /* @__PURE__ */ new Map();
9112
+ var coverageSeriesCache = /* @__PURE__ */ new Map();
9113
+ var flowSeriesCache = /* @__PURE__ */ new Map();
9114
+ var parseEnabledFlag4 = (value, env) => {
9115
+ const normalized = String(value ?? "").trim().toLowerCase();
9116
+ if (!normalized) return env !== "TEST";
9117
+ if (["1", "true", "yes", "on"].includes(normalized)) return true;
9118
+ if (["0", "false", "no", "off"].includes(normalized)) return false;
9119
+ if (normalized === "backtest") return env === "BACKTEST";
9120
+ if (normalized === "live") return env !== "BACKTEST";
9121
+ return false;
9122
+ };
9123
+ var getMinimumCoveragePct = () => {
9124
+ const parsed = Number(process.env.HYPERLIQUID_WHALE_MIN_COVERAGE_PCT);
9125
+ return Number.isFinite(parsed) ? Math.max(0, Math.min(1, parsed)) : DEFAULT_MIN_COVERAGE_PCT;
9126
+ };
9127
+ var signalIntervalToMarketInterval2 = (value) => {
9128
+ const normalized = String(value).trim().toLowerCase();
9129
+ if (normalized === "1" || normalized === "1m") return "1m";
9130
+ if (normalized === "5" || normalized === "5m") return "5m";
9131
+ if (normalized === "60" || normalized === "1h") return "1h";
9132
+ return "15m";
9133
+ };
9134
+ var hasBaseContext3 = (signal) => Boolean(
9135
+ signal.additionalIndicators?.baseContext && typeof signal.additionalIndicators.baseContext === "object" && !Array.isArray(signal.additionalIndicators.baseContext)
9136
+ );
9137
+ var setBoundedCache = (key, value) => {
9138
+ if (contextCache.size >= MAX_CACHE_ENTRIES) {
9139
+ const oldestKey = contextCache.keys().next().value;
9140
+ if (oldestKey != null) contextCache.delete(oldestKey);
9141
+ }
9142
+ contextCache.set(key, value);
9143
+ };
9144
+ var setBoundedSeriesCache = (cache, maxEntries, key, value) => {
9145
+ if (cache.size >= maxEntries) {
9146
+ const oldestKey = cache.keys().next().value;
9147
+ if (oldestKey != null) cache.delete(oldestKey);
9148
+ }
9149
+ cache.set(key, value);
9150
+ };
9151
+ var uniqueAddressCount = (rows, field) => {
9152
+ const addresses = /* @__PURE__ */ new Set();
9153
+ for (const row of rows) {
9154
+ for (const address of row[field]) addresses.add(address);
9155
+ }
9156
+ return addresses.size;
9157
+ };
9158
+ var sumFlowField = (rows, field) => rows.reduce((sum, row) => sum + row[field], 0);
9159
+ var sliceSeriesWindow = (rows, fromMs, toMs) => {
9160
+ const lowerBound = (timestamp) => {
9161
+ let low = 0;
9162
+ let high = rows.length;
9163
+ while (low < high) {
9164
+ const middle = low + Math.floor((high - low) / 2);
9165
+ if (rows[middle].ts.getTime() < timestamp) low = middle + 1;
9166
+ else high = middle;
9167
+ }
9168
+ return low;
9169
+ };
9170
+ return rows.slice(lowerBound(fromMs), lowerBound(toMs));
9171
+ };
9172
+ var aggregateHyperliquidWhaleFlowSeries = (params) => {
9173
+ const intervalMs = INTERVAL_MS[params.interval];
9174
+ const windowStartMs = params.decisionTimeMs - intervalMs;
9175
+ const coverageRows = sliceSeriesWindow(
9176
+ params.coverageRows,
9177
+ windowStartMs,
9178
+ params.decisionTimeMs
9179
+ );
9180
+ const expectedBuckets = Math.ceil(intervalMs / 6e4);
9181
+ if (coverageRows.length !== expectedBuckets || coverageRows.some((row) => row.coveredWhales <= 0)) {
9182
+ return null;
9183
+ }
9184
+ const flowRows = sliceSeriesWindow(
9185
+ params.flowRows,
9186
+ windowStartMs,
9187
+ params.decisionTimeMs
9188
+ );
9189
+ const asOfTs = new Date(
9190
+ Math.max(...coverageRows.map((row) => row.ts.getTime()))
9191
+ );
9192
+ const coveredWhales = Math.min(
9193
+ ...coverageRows.map((row) => row.coveredWhales)
9194
+ );
9195
+ const expectedWhales = Math.max(
9196
+ ...coverageRows.map((row) => row.expectedWhales)
9197
+ );
9198
+ const coveragePct = Math.min(...coverageRows.map((row) => row.coveragePct));
9199
+ const trades = sumFlowField(flowRows, "trades");
9200
+ const whaleSides = sumFlowField(flowRows, "whaleSides");
9201
+ const buyNotionalUsd = sumFlowField(flowRows, "buyNotionalUsd");
9202
+ const sellNotionalUsd = sumFlowField(flowRows, "sellNotionalUsd");
9203
+ const positionAwareWhaleSides = sumFlowField(
9204
+ flowRows,
9205
+ "positionAwareWhaleSides"
9206
+ );
9207
+ const longEntryNotionalUsd = sumFlowField(flowRows, "longEntryNotionalUsd");
9208
+ const shortEntryNotionalUsd = sumFlowField(flowRows, "shortEntryNotionalUsd");
9209
+ const longExitNotionalUsd = sumFlowField(flowRows, "longExitNotionalUsd");
9210
+ const shortExitNotionalUsd = sumFlowField(flowRows, "shortExitNotionalUsd");
9211
+ const totalNotionalUsd = buyNotionalUsd + sellNotionalUsd;
9212
+ const totalEntryNotionalUsd = longEntryNotionalUsd + shortEntryNotionalUsd;
9213
+ const ageMs = params.decisionTimeMs - (asOfTs.getTime() + 6e4);
9214
+ return {
9215
+ symbol: params.symbol,
9216
+ interval: params.interval,
9217
+ asOfTs,
9218
+ windowEndTs: new Date(params.decisionTimeMs),
9219
+ trades,
9220
+ whaleSides,
9221
+ uniqueWhales: uniqueAddressCount(flowRows, "whaleAddresses"),
9222
+ coveredWhales,
9223
+ expectedWhales,
9224
+ coveragePct,
9225
+ buyNotionalUsd,
9226
+ sellNotionalUsd,
9227
+ netNotionalUsd: buyNotionalUsd - sellNotionalUsd,
9228
+ buySharePct: totalNotionalUsd > 0 ? buyNotionalUsd / totalNotionalUsd : null,
9229
+ positionAwareWhaleSides,
9230
+ positionAwarePct: whaleSides > 0 ? positionAwareWhaleSides / whaleSides : 0,
9231
+ longEntryWhales: uniqueAddressCount(flowRows, "longEntryWhaleAddresses"),
9232
+ shortEntryWhales: uniqueAddressCount(flowRows, "shortEntryWhaleAddresses"),
9233
+ longExitWhales: uniqueAddressCount(flowRows, "longExitWhaleAddresses"),
9234
+ shortExitWhales: uniqueAddressCount(flowRows, "shortExitWhaleAddresses"),
9235
+ longEntryNotionalUsd,
9236
+ shortEntryNotionalUsd,
9237
+ longExitNotionalUsd,
9238
+ shortExitNotionalUsd,
9239
+ entryNetNotionalUsd: longEntryNotionalUsd - shortEntryNotionalUsd,
9240
+ entryLongSharePct: totalEntryNotionalUsd > 0 ? longEntryNotionalUsd / totalEntryNotionalUsd : null,
9241
+ universeFingerprint: params.universeFingerprint,
9242
+ whaleRegistryFingerprint: params.whaleRegistryFingerprint,
9243
+ source: positionAwareWhaleSides > 0 ? "hyperliquid_user_fills" : null,
9244
+ ageMs,
9245
+ stale: ageMs < 0 || (params.maxAgeMs != null && Number.isFinite(params.maxAgeMs) ? ageMs > params.maxAgeMs : false)
9246
+ };
9247
+ };
9248
+ var loadHyperliquidWhaleFlowAggregateFromSeries = async (params) => {
9249
+ const chunkStartMs = Math.floor(params.decisionTimeMs / SERIES_CHUNK_MS) * SERIES_CHUNK_MS;
9250
+ const fromMs = chunkStartMs - MAX_SERIES_LOOKBACK_MS;
9251
+ const toMs = chunkStartMs + SERIES_CHUNK_MS;
9252
+ const sharedKey = [
9253
+ fromMs,
9254
+ toMs,
9255
+ params.universeFingerprint,
9256
+ params.whaleRegistryFingerprint
9257
+ ].join(":");
9258
+ let pendingCoverage = coverageSeriesCache.get(sharedKey);
9259
+ if (!pendingCoverage) {
9260
+ pendingCoverage = (0, import_timescale4.getHyperliquidWhaleCoverageSeriesRows)({
9261
+ fromMs,
9262
+ toMs,
9263
+ universeFingerprint: params.universeFingerprint,
9264
+ whaleRegistryFingerprint: params.whaleRegistryFingerprint
9265
+ });
9266
+ setBoundedSeriesCache(
9267
+ coverageSeriesCache,
9268
+ MAX_COVERAGE_SERIES_CACHE_ENTRIES,
9269
+ sharedKey,
9270
+ pendingCoverage
9271
+ );
9272
+ }
9273
+ const flowKey = `${params.symbol}:${sharedKey}`;
9274
+ let pendingFlow = flowSeriesCache.get(flowKey);
9275
+ if (!pendingFlow) {
9276
+ pendingFlow = (0, import_timescale4.getHyperliquidWhaleFlowSeriesRows)({
9277
+ symbol: params.symbol,
9278
+ fromMs,
9279
+ toMs,
9280
+ universeFingerprint: params.universeFingerprint,
9281
+ whaleRegistryFingerprint: params.whaleRegistryFingerprint
9282
+ });
9283
+ setBoundedSeriesCache(
9284
+ flowSeriesCache,
9285
+ MAX_FLOW_SERIES_CACHE_ENTRIES,
9286
+ flowKey,
9287
+ pendingFlow
9288
+ );
9289
+ }
9290
+ const [coverageRows, flowRows] = await Promise.all([
9291
+ pendingCoverage,
9292
+ pendingFlow
9293
+ ]);
9294
+ return aggregateHyperliquidWhaleFlowSeries({
9295
+ ...params,
9296
+ coverageRows,
9297
+ flowRows
9298
+ });
9299
+ };
9300
+ var toBaseHyperliquidWhaleFlowContext = (row, minimumCoveragePct) => ({
9301
+ source: row.positionAwareWhaleSides > 0 ? "hyperliquid_user_fills" : "hyperliquid_trades",
9302
+ interval: row.interval,
9303
+ asOfTs: row.asOfTs.getTime(),
9304
+ windowEndTs: row.windowEndTs.getTime(),
9305
+ ageMs: row.ageMs,
9306
+ stale: row.stale,
9307
+ symbol: row.symbol,
9308
+ trades: row.trades,
9309
+ whaleSides: row.whaleSides,
9310
+ uniqueWhales: row.uniqueWhales,
9311
+ coveredWhales: row.coveredWhales,
9312
+ expectedWhales: row.expectedWhales,
9313
+ coveragePct: row.coveragePct,
9314
+ coverageSufficient: row.coveragePct >= minimumCoveragePct,
9315
+ buyNotionalUsd: row.buyNotionalUsd,
9316
+ sellNotionalUsd: row.sellNotionalUsd,
9317
+ netNotionalUsd: row.netNotionalUsd,
9318
+ buySharePct: row.buySharePct,
9319
+ positionAwareWhaleSides: row.positionAwareWhaleSides,
9320
+ positionAwarePct: row.positionAwarePct,
9321
+ longEntryWhales: row.longEntryWhales,
9322
+ shortEntryWhales: row.shortEntryWhales,
9323
+ longExitWhales: row.longExitWhales,
9324
+ shortExitWhales: row.shortExitWhales,
9325
+ longEntryNotionalUsd: row.longEntryNotionalUsd,
9326
+ shortEntryNotionalUsd: row.shortEntryNotionalUsd,
9327
+ longExitNotionalUsd: row.longExitNotionalUsd,
9328
+ shortExitNotionalUsd: row.shortExitNotionalUsd,
9329
+ entryNetNotionalUsd: row.entryNetNotionalUsd,
9330
+ entryLongSharePct: row.entryLongSharePct,
9331
+ universeFingerprint: row.universeFingerprint,
9332
+ whaleRegistryFingerprint: row.whaleRegistryFingerprint
9333
+ });
9334
+ var isHyperliquidWhaleContextEnabled = (env) => parseEnabledFlag4(process.env.HYPERLIQUID_WHALE_CONTEXT_ENABLED, env);
9335
+ var loadHyperliquidWhaleFlowContext = async (params) => {
9336
+ if (!(params.enabled ?? isHyperliquidWhaleContextEnabled(params.env)) || hyperliquidWhaleContextUnavailable || params.interval == null) {
9337
+ return null;
9338
+ }
9339
+ const symbol = resolveHyperliquidPerpFromSignalSymbol(params.symbol);
9340
+ if (!symbol) return null;
9341
+ const interval = params.marketInterval ?? signalIntervalToMarketInterval2(params.interval);
9342
+ const decisionTimeMs = params.timestamp + (0, import_data2.intervalToMs)(params.interval);
9343
+ const maxAgeMs = params.maxAgeMs ?? DEFAULT_MAX_AGE_BY_INTERVAL2[interval];
9344
+ const universe = getHyperliquidPerpUniverseSnapshot();
9345
+ const whales = getHyperliquidWhaleRegistrySnapshot();
9346
+ const minimumCoveragePct = getMinimumCoveragePct();
9347
+ const cacheKey = [
9348
+ symbol,
9349
+ interval,
9350
+ decisionTimeMs,
9351
+ maxAgeMs,
9352
+ universe.fingerprint,
9353
+ whales.fingerprint,
9354
+ minimumCoveragePct
9355
+ ].join(":");
9356
+ try {
9357
+ let row;
9358
+ if (params.useSeriesCache) {
9359
+ row = await loadHyperliquidWhaleFlowAggregateFromSeries({
9360
+ symbol,
9361
+ interval,
9362
+ decisionTimeMs,
9363
+ maxAgeMs,
9364
+ universeFingerprint: universe.fingerprint,
9365
+ whaleRegistryFingerprint: whales.fingerprint
9366
+ });
9367
+ } else {
9368
+ let pending = contextCache.get(cacheKey);
9369
+ if (!pending) {
9370
+ pending = (0, import_timescale4.getHyperliquidWhaleFlowAggregate)({
9371
+ symbol,
9372
+ interval,
9373
+ decisionTimeMs,
9374
+ maxAgeMs,
9375
+ universeFingerprint: universe.fingerprint,
9376
+ whaleRegistryFingerprint: whales.fingerprint
9377
+ });
9378
+ setBoundedCache(cacheKey, pending);
9379
+ }
9380
+ row = await pending;
9381
+ }
9382
+ if (!row) return null;
9383
+ return toBaseHyperliquidWhaleFlowContext(row, minimumCoveragePct);
9384
+ } catch (error) {
9385
+ hyperliquidWhaleContextUnavailable = true;
9386
+ import_logger7.logger.warn(
9387
+ "Hyperliquid whale context disabled after Timescale read failure: %s",
9388
+ String(error)
9389
+ );
9390
+ return null;
9391
+ }
9392
+ };
9393
+ var enrichSignalWithHyperliquidWhaleContext = async (params) => {
9394
+ const { signal, env } = params;
9395
+ if (signal.universe === "tradfi" || signal.interval == null || !hasBaseContext3(signal)) {
9396
+ return false;
9397
+ }
9398
+ const hyperliquidWhales = await loadHyperliquidWhaleFlowContext({
9399
+ symbol: signal.symbol,
9400
+ interval: signal.interval,
9401
+ timestamp: signal.timestamp,
9402
+ env,
9403
+ enabled: params.enabled,
9404
+ marketInterval: params.interval,
9405
+ maxAgeMs: params.maxAgeMs
9406
+ });
9407
+ if (!hyperliquidWhales) return false;
9408
+ const baseContext = signal.additionalIndicators.baseContext;
9409
+ signal.additionalIndicators = {
9410
+ ...signal.additionalIndicators,
9411
+ baseContext: {
9412
+ ...baseContext,
9413
+ participation: {
9414
+ ...baseContext.participation,
9415
+ hyperliquidWhales
9416
+ }
9417
+ }
9418
+ };
9419
+ (0, import_strategies4.refreshSignalBaseContextGateFeatures)(signal);
9420
+ return true;
9421
+ };
9422
+
8859
9423
  // src/strategyHelpers/runtime.ts
8860
9424
  var formatAiError = (err) => {
8861
9425
  const error = err;
@@ -8972,7 +9536,7 @@ var enrichSignalWithAi = async ({
8972
9536
  signal.aiAnalysis = analysis;
8973
9537
  return resolveAiQuality(analysis, direction);
8974
9538
  } catch (err) {
8975
- import_logger7.logger.error("AI analysis error: %s %s", symbol, formatAiError(err));
9539
+ import_logger8.logger.error("AI analysis error: %s %s", symbol, formatAiError(err));
8976
9540
  }
8977
9541
  return void 0;
8978
9542
  };
@@ -8988,6 +9552,7 @@ var enrichSignalWithMlAi = async ({
8988
9552
  await enrichSignalWithBinanceMarketContext({ signal, env });
8989
9553
  await enrichSignalWithCoinMarketCapContext({ signal, env });
8990
9554
  await enrichSignalWithDerivativesContext({ signal, env });
9555
+ await enrichSignalWithHyperliquidWhaleContext({ signal, env });
8991
9556
  await enrichSignalWithMl({ signal, env, ml });
8992
9557
  return enrichSignalWithAi({ signal, userName, symbol, direction, env, ai });
8993
9558
  };
@@ -9022,7 +9587,7 @@ var getOrderArrivalSnapshot = async ({
9022
9587
  spreadBps
9023
9588
  };
9024
9589
  } catch (error) {
9025
- import_logger7.logger.warn(
9590
+ import_logger8.logger.warn(
9026
9591
  "runtime order arrival snapshot failed: %s %s",
9027
9592
  symbol,
9028
9593
  error?.message || String(error)
@@ -9526,7 +10091,7 @@ var resolveBacktestExecutionDelayMs = (value, fallbackDelayMs) => {
9526
10091
  };
9527
10092
  var safeIntervalToMs = (interval) => {
9528
10093
  try {
9529
- return (0, import_data2.intervalToMs)(interval);
10094
+ return (0, import_data3.intervalToMs)(interval);
9530
10095
  } catch {
9531
10096
  return null;
9532
10097
  }
@@ -9608,14 +10173,14 @@ var applyBacktestDelayedEntryExecution = ({
9608
10173
  btcExecutionCandle: null
9609
10174
  };
9610
10175
  }
9611
- const executionPrice = (0, import_strategies4.resolveBacktestExecutionPrice)(
10176
+ const executionPrice = (0, import_strategies5.resolveBacktestExecutionPrice)(
9612
10177
  candle,
9613
10178
  backtestPriceMode ?? "open"
9614
10179
  );
9615
10180
  const executionTimestamp = candle.timestamp;
9616
10181
  const takeProfitPrice = decision.entryContext.prices.takeProfitPrice;
9617
10182
  const stopLossPrice = decision.orderPlan.stopLossPrice;
9618
- const riskRatio = (0, import_strategies4.calculateRiskRatio)({
10183
+ const riskRatio = (0, import_strategies5.calculateRiskRatio)({
9619
10184
  direction: decision.entryContext.direction,
9620
10185
  currentPrice: executionPrice,
9621
10186
  takeProfitPrice,
@@ -9643,7 +10208,7 @@ var applyBacktestDelayedEntryExecution = ({
9643
10208
  executionCandle: buildBacktestExecutionOnlyCandle(candle, executionPrice),
9644
10209
  btcExecutionCandle: buildBacktestExecutionOnlyCandle(
9645
10210
  btcCandle,
9646
- (0, import_strategies4.resolveBacktestExecutionPrice)(btcCandle, backtestPriceMode ?? "open")
10211
+ (0, import_strategies5.resolveBacktestExecutionPrice)(btcCandle, backtestPriceMode ?? "open")
9647
10212
  )
9648
10213
  };
9649
10214
  if (!decision.signal) {
@@ -9888,7 +10453,7 @@ var handleExitDecision = async ({
9888
10453
  deploymentId: connector.deploymentId
9889
10454
  });
9890
10455
  if (!activeTrade) {
9891
- import_logger8.logger.warn(
10456
+ import_logger9.logger.warn(
9892
10457
  "[%s] blocked closePosition for untracked runtime position: %s",
9893
10458
  strategyName ?? "unknown",
9894
10459
  symbol
@@ -9896,7 +10461,7 @@ var handleExitDecision = async ({
9896
10461
  return "CLOSE_BLOCKED_BY_UNTRACKED_POSITION";
9897
10462
  }
9898
10463
  if (!strategyName || activeTrade.strategy !== strategyName) {
9899
- import_logger8.logger.warn(
10464
+ import_logger9.logger.warn(
9900
10465
  "[%s] blocked closePosition for foreign runtime position: %s ownedBy=%s",
9901
10466
  strategyName ?? "unknown",
9902
10467
  symbol,
@@ -9948,7 +10513,7 @@ var handleExitDecision = async ({
9948
10513
  exitType: closedTrade?.exitType ?? "exit"
9949
10514
  });
9950
10515
  } catch (notificationError) {
9951
- import_logger8.logger.error(
10516
+ import_logger9.logger.error(
9952
10517
  "runtime close notification error: %s %s",
9953
10518
  symbol,
9954
10519
  notificationError
@@ -9962,7 +10527,7 @@ var handleExitDecision = async ({
9962
10527
  decision,
9963
10528
  market
9964
10529
  });
9965
- import_logger8.logger.error("close order error: %s %s", symbol, err);
10530
+ import_logger9.logger.error("close order error: %s %s", symbol, err);
9966
10531
  return "ORDER_ERROR";
9967
10532
  }
9968
10533
  return decision.code;
@@ -9989,7 +10554,7 @@ var handleProtectDecision = async ({
9989
10554
  decision,
9990
10555
  market
9991
10556
  });
9992
- import_logger8.logger.error("protect position error: %s %s", symbol, err);
10557
+ import_logger9.logger.error("protect position error: %s %s", symbol, err);
9993
10558
  return "ORDER_ERROR";
9994
10559
  }
9995
10560
  return decision.code;
@@ -10152,9 +10717,9 @@ var executeEntryDecision = async ({
10152
10717
  market
10153
10718
  });
10154
10719
  if (err?.message === import_types.BACKTEST_WARNING_CODES.TAKE_PROFIT_CROSSED_BEFORE_ENTRY) {
10155
- import_logger8.logger.warn("order warning: %s %s", symbol, err);
10720
+ import_logger9.logger.warn("order warning: %s %s", symbol, err);
10156
10721
  } else {
10157
- import_logger8.logger.error("order error: %s %s", symbol, err);
10722
+ import_logger9.logger.error("order error: %s %s", symbol, err);
10158
10723
  }
10159
10724
  return signal ?? "ORDER_ERROR";
10160
10725
  }
@@ -10251,7 +10816,7 @@ var createStrategyRuntime = ({
10251
10816
  assetClass
10252
10817
  });
10253
10818
  const strategyPolicyProfile = getPolicyProfile();
10254
- const indicatorPeriods = (0, import_strategies4.buildDefaultIndicatorPeriods)(config);
10819
+ const indicatorPeriods = (0, import_strategies5.buildDefaultIndicatorPeriods)(config);
10255
10820
  const hookBase = {
10256
10821
  connector,
10257
10822
  strategyName,
@@ -10309,7 +10874,7 @@ var createStrategyRuntime = ({
10309
10874
  try {
10310
10875
  await projectHook(errorParams);
10311
10876
  } catch (hookError) {
10312
- import_logger8.logger.error(
10877
+ import_logger9.logger.error(
10313
10878
  "project hook onRuntimeError failed: %s %s",
10314
10879
  strategyName,
10315
10880
  hookError
@@ -10323,7 +10888,7 @@ var createStrategyRuntime = ({
10323
10888
  try {
10324
10889
  await onRuntimeError(errorParams);
10325
10890
  } catch (hookError) {
10326
- import_logger8.logger.error(
10891
+ import_logger9.logger.error(
10327
10892
  "runtime hook onRuntimeError failed: %s %s",
10328
10893
  strategyName,
10329
10894
  hookError
@@ -10337,7 +10902,7 @@ var createStrategyRuntime = ({
10337
10902
  try {
10338
10903
  return await hook(params);
10339
10904
  } catch (error) {
10340
- import_logger8.logger.error(
10905
+ import_logger9.logger.error(
10341
10906
  'strategy hook "%s" failed for %s: %s',
10342
10907
  stage,
10343
10908
  strategyName,
@@ -10473,7 +11038,7 @@ var createStrategyRuntime = ({
10473
11038
  }
10474
11039
  return void 0;
10475
11040
  };
10476
- const indicatorsState = (0, import_strategies4.createStrategyIndicatorsState)({
11041
+ const indicatorsState = (0, import_strategies5.createStrategyIndicatorsState)({
10477
11042
  env,
10478
11043
  data,
10479
11044
  btcData,
@@ -10485,7 +11050,7 @@ var createStrategyRuntime = ({
10485
11050
  sharedReplayKey: indicatorSharedReplayKey,
10486
11051
  useBtcReference: universe === "crypto"
10487
11052
  });
10488
- const strategyApi = (0, import_strategies4.createStrategyAPI)({
11053
+ const strategyApi = (0, import_strategies5.createStrategyAPI)({
10489
11054
  strategy: strategyName,
10490
11055
  symbol,
10491
11056
  interval: config.INTERVAL ?? "15",
@@ -10495,7 +11060,30 @@ var createStrategyRuntime = ({
10495
11060
  indicatorsState,
10496
11061
  isConfigFromBacktest,
10497
11062
  sharedReplayKey: strategySharedReplayKey,
10498
- getSharedReplayState: import_strategies4.getSharedStrategyReplayState
11063
+ getSharedReplayState: import_strategies5.getSharedStrategyReplayState,
11064
+ loadDecisionBaseContext: async ({
11065
+ baseContext,
11066
+ candle,
11067
+ symbol: decisionSymbol,
11068
+ interval: decisionInterval
11069
+ }) => {
11070
+ if (!baseContext) return void 0;
11071
+ const hyperliquidWhales = await loadHyperliquidWhaleFlowContext({
11072
+ symbol: decisionSymbol,
11073
+ interval: decisionInterval,
11074
+ timestamp: candle.timestamp,
11075
+ env,
11076
+ useSeriesCache: env === "BACKTEST" || env === "PARITY"
11077
+ });
11078
+ if (!hyperliquidWhales) return baseContext;
11079
+ return {
11080
+ ...baseContext,
11081
+ participation: {
11082
+ ...baseContext.participation,
11083
+ hyperliquidWhales
11084
+ }
11085
+ };
11086
+ }
10499
11087
  });
10500
11088
  const core = await createCore({
10501
11089
  userName,
@@ -10510,7 +11098,7 @@ var createStrategyRuntime = ({
10510
11098
  strategyApi,
10511
11099
  indicatorsState,
10512
11100
  sharedReplayKey: strategySharedReplayKey,
10513
- getSharedReplayState: import_strategies4.getSharedStrategyReplayState
11101
+ getSharedReplayState: import_strategies5.getSharedStrategyReplayState
10514
11102
  });
10515
11103
  await invokeStageHooks("onInit", strategyManifest?.hooks?.onInit, {
10516
11104
  ctx: getHookCtx(),
@@ -11056,7 +11644,7 @@ var createStrategyRuntime = ({
11056
11644
 
11057
11645
  // src/strategyHooks/closeOppositePositionsBeforeOpen.ts
11058
11646
  var import_lodash2 = __toESM(require_lodash());
11059
- var import_logger9 = require("@tradejs/infra/logger");
11647
+ var import_logger10 = require("@tradejs/infra/logger");
11060
11648
  var closeOppositePositionsBeforeOpen = async ({
11061
11649
  connector,
11062
11650
  entryContext
@@ -11070,7 +11658,7 @@ var closeOppositePositionsBeforeOpen = async ({
11070
11658
  } = entryContext;
11071
11659
  const price = prices.currentPrice;
11072
11660
  try {
11073
- import_logger9.logger.log(
11661
+ import_logger10.logger.log(
11074
11662
  "info",
11075
11663
  "[%s] checking open positions before open: %s %s",
11076
11664
  strategyName,
@@ -11081,7 +11669,7 @@ var closeOppositePositionsBeforeOpen = async ({
11081
11669
  const openPositions = (positions || []).filter(
11082
11670
  (item) => item && Number(item.qty) > 0
11083
11671
  );
11084
- import_logger9.logger.log(
11672
+ import_logger10.logger.log(
11085
11673
  "info",
11086
11674
  "[%s] open positions found: %s",
11087
11675
  strategyName,
@@ -11091,7 +11679,7 @@ var closeOppositePositionsBeforeOpen = async ({
11091
11679
  (item) => item.symbol !== currentSymbol && item.direction !== currentDirection
11092
11680
  );
11093
11681
  if (import_lodash2.default.isEmpty(oppositePositions)) {
11094
- import_logger9.logger.log(
11682
+ import_logger10.logger.log(
11095
11683
  "info",
11096
11684
  "[%s] no opposite positions to close before open: %s",
11097
11685
  strategyName,
@@ -11100,7 +11688,7 @@ var closeOppositePositionsBeforeOpen = async ({
11100
11688
  return;
11101
11689
  }
11102
11690
  for (const position of oppositePositions) {
11103
- import_logger9.logger.log(
11691
+ import_logger10.logger.log(
11104
11692
  "info",
11105
11693
  "[%s] closing opposite position: %s %s qty=%s",
11106
11694
  strategyName,
@@ -11115,14 +11703,14 @@ var closeOppositePositionsBeforeOpen = async ({
11115
11703
  timestamp,
11116
11704
  direction: position.direction
11117
11705
  });
11118
- import_logger9.logger.log(
11706
+ import_logger10.logger.log(
11119
11707
  "info",
11120
11708
  "[%s] opposite position closed: %s",
11121
11709
  strategyName,
11122
11710
  position.symbol
11123
11711
  );
11124
11712
  } catch (err) {
11125
- import_logger9.logger.log(
11713
+ import_logger10.logger.log(
11126
11714
  "error",
11127
11715
  "[%s] failed to close opposite position: %s %s",
11128
11716
  strategyName,
@@ -11132,7 +11720,7 @@ var closeOppositePositionsBeforeOpen = async ({
11132
11720
  }
11133
11721
  }
11134
11722
  } catch (err) {
11135
- import_logger9.logger.log(
11723
+ import_logger10.logger.log(
11136
11724
  "error",
11137
11725
  "[%s] failed to load open positions before open: %s %s",
11138
11726
  strategyName,
@@ -11344,7 +11932,7 @@ var createMoveStopToBreakEvenOnBarHook = ({
11344
11932
  var createMoveStopToBreakEvenAfterCoreDecisionHook = createMoveStopToBreakEvenOnBarHook;
11345
11933
 
11346
11934
  // src/signalsHooks/closeAllPositionsOnGlobalProfitBeforeSignals.ts
11347
- var import_logger10 = require("@tradejs/infra/logger");
11935
+ var import_logger11 = require("@tradejs/infra/logger");
11348
11936
  var createCloseAllOnGlobalProfitBeforeSignalsHook = ({
11349
11937
  getStrategyDefaultConfig = () => void 0,
11350
11938
  profitRiskMultiplier = DEFAULT_GLOBAL_UNREALIZED_PNL_TRIGGER_RISK_MULTIPLIER
@@ -11383,7 +11971,7 @@ var createCloseAllOnGlobalProfitBeforeSignalsHook = ({
11383
11971
  if (!Number.isFinite(unrealizedPnlThreshold) || unrealizedPnlThreshold <= 0 || totalUnrealizedPnl < unrealizedPnlThreshold) {
11384
11972
  return;
11385
11973
  }
11386
- import_logger10.logger.info(
11974
+ import_logger11.logger.info(
11387
11975
  "closing all positions before signals by global unrealized pnl threshold: totalPnl=%s threshold=%s positions=%s",
11388
11976
  totalUnrealizedPnl,
11389
11977
  unrealizedPnlThreshold,
@@ -11409,7 +11997,7 @@ var createCloseAllOnGlobalProfitBeforeSignalsHook = ({
11409
11997
  ];
11410
11998
  });
11411
11999
  if (failedClosures.length) {
11412
- import_logger10.logger.warn(
12000
+ import_logger11.logger.warn(
11413
12001
  "close-all before signals hook could not confirm closures for %s",
11414
12002
  failedClosures.join(", ")
11415
12003
  );
@@ -11441,6 +12029,7 @@ var createCloseAllOnGlobalProfitBeforeSignalsHook = ({
11441
12029
  enrichSignalWithAi,
11442
12030
  enrichSignalWithBinanceMarketContext,
11443
12031
  enrichSignalWithCoinMarketCapContext,
12032
+ enrichSignalWithHyperliquidWhaleContext,
11444
12033
  enrichSignalWithMl,
11445
12034
  enrichSignalWithMlAi,
11446
12035
  ensureAiStrategyPluginsLoaded,
@@ -11451,6 +12040,10 @@ var createCloseAllOnGlobalProfitBeforeSignalsHook = ({
11451
12040
  getBinanceBreadthUniverseSnapshot,
11452
12041
  getBinanceBreadthUniverses,
11453
12042
  getDeterministicAiGateContext,
12043
+ getHyperliquidPerpSymbols,
12044
+ getHyperliquidPerpUniverseSnapshot,
12045
+ getHyperliquidWhaleAddresses,
12046
+ getHyperliquidWhaleRegistrySnapshot,
11454
12047
  getOpenRouterModelKwargs,
11455
12048
  getOrderArrivalSnapshot,
11456
12049
  getPrimaryBinanceBreadthUniverse,
@@ -11459,9 +12052,12 @@ var createCloseAllOnGlobalProfitBeforeSignalsHook = ({
11459
12052
  getStrategyCreator,
11460
12053
  getStrategyManifest,
11461
12054
  isKnownStrategy,
12055
+ isTrackedHyperliquidPerp,
12056
+ isTrackedHyperliquidWhale,
11462
12057
  registerStrategyEntries,
11463
12058
  resetAiRuntimeCache,
11464
12059
  resetStrategyRegistryCache,
12060
+ resolveHyperliquidPerpFromSignalSymbol,
11465
12061
  resolveStrategyConfig,
11466
12062
  runAiPrompt,
11467
12063
  runAiPromptLocal,