@tradejs/core 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.
@@ -6869,6 +6869,12 @@ var SESSION_WINDOWS = [
6869
6869
  var FUNDING_WINDOW_STEP_MINUTES = 8 * 60;
6870
6870
  var FUNDING_WINDOW_NEARBY_MINUTES = 60;
6871
6871
  var SESSION_WINDOW_EDGE_MINUTES = 60;
6872
+ var BASE_INTERVAL_MS = 15 * 6e4;
6873
+ var PSYCHOLOGICAL_LEVEL_WINDOWS = {
6874
+ m15: BASE_INTERVAL_MS,
6875
+ h1: 60 * 6e4,
6876
+ h4: 4 * 60 * 6e4
6877
+ };
6872
6878
  var isInsideSession = (minuteUtc, startMinuteUtc, endMinuteUtc) => startMinuteUtc <= endMinuteUtc ? minuteUtc >= startMinuteUtc && minuteUtc < endMinuteUtc : minuteUtc >= startMinuteUtc || minuteUtc < endMinuteUtc;
6873
6879
  var buildSessionContext = (timestamp) => {
6874
6880
  const date = new Date(timestamp);
@@ -6900,7 +6906,80 @@ var buildSessionContext = (timestamp) => {
6900
6906
  isWeekendUtc: dayOfWeekUtc >= 6
6901
6907
  };
6902
6908
  };
6909
+ var buildUnavailablePsychologicalLevelWindow = () => ({
6910
+ crossed: null,
6911
+ direction: "unknown",
6912
+ level: null,
6913
+ levelsCrossed: null,
6914
+ distanceBeyondLevelBps: null
6915
+ });
6916
+ var buildPsychologicalLevelWindow = (startPrice, endPrice, stepUsd) => {
6917
+ if (!Number.isFinite(startPrice) || !Number.isFinite(endPrice) || !Number.isFinite(stepUsd) || startPrice <= 0 || endPrice <= 0 || stepUsd <= 0) {
6918
+ return buildUnavailablePsychologicalLevelWindow();
6919
+ }
6920
+ if (endPrice === startPrice) {
6921
+ return {
6922
+ crossed: false,
6923
+ direction: "none",
6924
+ level: null,
6925
+ levelsCrossed: 0,
6926
+ distanceBeyondLevelBps: null
6927
+ };
6928
+ }
6929
+ const movingUp = endPrice > startPrice;
6930
+ const firstCrossedLevel = movingUp ? (Math.floor(startPrice / stepUsd) + 1) * stepUsd : (Math.ceil(startPrice / stepUsd) - 1) * stepUsd;
6931
+ const lastCrossedLevel = movingUp ? Math.floor(endPrice / stepUsd) * stepUsd : Math.ceil(endPrice / stepUsd) * stepUsd;
6932
+ const crossed = movingUp ? firstCrossedLevel <= lastCrossedLevel : firstCrossedLevel >= lastCrossedLevel;
6933
+ if (!crossed) {
6934
+ return {
6935
+ crossed: false,
6936
+ direction: "none",
6937
+ level: null,
6938
+ levelsCrossed: 0,
6939
+ distanceBeyondLevelBps: null
6940
+ };
6941
+ }
6942
+ const levelsCrossed = Math.round(Math.abs(lastCrossedLevel - firstCrossedLevel) / stepUsd) + 1;
6943
+ const distanceBeyondLevelBps = Math.abs(endPrice - lastCrossedLevel) / lastCrossedLevel * 1e4;
6944
+ return {
6945
+ crossed: true,
6946
+ direction: movingUp ? "up" : "down",
6947
+ level: lastCrossedLevel,
6948
+ levelsCrossed,
6949
+ distanceBeyondLevelBps
6950
+ };
6951
+ };
6952
+ var buildPsychologicalLevelAssetContext = (candles, stepUsd) => {
6953
+ const endCandle = candles[candles.length - 1];
6954
+ if (!endCandle) {
6955
+ return null;
6956
+ }
6957
+ const candlesByTimestamp = new Map(
6958
+ candles.map((item) => [item.timestamp, item])
6959
+ );
6960
+ const windows = Object.fromEntries(
6961
+ Object.entries(PSYCHOLOGICAL_LEVEL_WINDOWS).map(([window, durationMs]) => {
6962
+ const startCandle = candlesByTimestamp.get(
6963
+ endCandle.timestamp - durationMs
6964
+ );
6965
+ return [
6966
+ window,
6967
+ startCandle ? buildPsychologicalLevelWindow(
6968
+ startCandle.close,
6969
+ endCandle.close,
6970
+ stepUsd
6971
+ ) : buildUnavailablePsychologicalLevelWindow()
6972
+ ];
6973
+ })
6974
+ );
6975
+ return {
6976
+ source: "aligned_15m_ohlcv",
6977
+ stepUsd,
6978
+ windows
6979
+ };
6980
+ };
6903
6981
  var STRUCTURE_LOOKBACK = 80;
6982
+ var BASE_CONTEXT_CANDLE_WINDOW = 256;
6904
6983
  var PIVOT_LEFT_RIGHT = 2;
6905
6984
  var ZONE_ATR_FACTOR = 0.5;
6906
6985
  var PROFILE_BIN_COUNT = 24;
@@ -8324,12 +8403,12 @@ var buildBaseContextSnapshot = ({
8324
8403
  candle,
8325
8404
  prevCandle,
8326
8405
  baseResult,
8327
- candlesHistory,
8328
- btcCandlesHistory,
8329
- ethCandlesHistory = [],
8330
- closeSeries,
8331
- volumeSeries,
8332
- btcCloseSeries,
8406
+ candlesHistory: fullCandlesHistory,
8407
+ btcCandlesHistory: fullBtcCandlesHistory,
8408
+ ethCandlesHistory: fullEthCandlesHistory = [],
8409
+ closeSeries: fullCloseSeries,
8410
+ volumeSeries: fullVolumeSeries,
8411
+ btcCloseSeries: fullBtcCloseSeries,
8333
8412
  coinResampledCandles,
8334
8413
  btcResampledCandles,
8335
8414
  ethResampledCandles,
@@ -8344,6 +8423,16 @@ var buildBaseContextSnapshot = ({
8344
8423
  adaptiveChannel: precomputedAdaptiveChannel,
8345
8424
  psar: precomputedPsar
8346
8425
  }) => {
8426
+ const candlesHistory = fullCandlesHistory.slice(-BASE_CONTEXT_CANDLE_WINDOW);
8427
+ const btcCandlesHistory = fullBtcCandlesHistory.slice(
8428
+ -BASE_CONTEXT_CANDLE_WINDOW
8429
+ );
8430
+ const ethCandlesHistory = fullEthCandlesHistory.slice(
8431
+ -BASE_CONTEXT_CANDLE_WINDOW
8432
+ );
8433
+ const closeSeries = fullCloseSeries.slice(-BASE_CONTEXT_CANDLE_WINDOW);
8434
+ const volumeSeries = fullVolumeSeries.slice(-BASE_CONTEXT_CANDLE_WINDOW);
8435
+ const btcCloseSeries = fullBtcCloseSeries.slice(-BASE_CONTEXT_CANDLE_WINDOW);
8347
8436
  const atr2 = toNullable(baseResult.atr);
8348
8437
  const bbWidthPct = baseResult.bbUpper != null && baseResult.bbLower != null && baseResult.bbMiddle != null && baseResult.bbMiddle !== 0 ? (baseResult.bbUpper - baseResult.bbLower) / baseResult.bbMiddle * 100 : null;
8349
8438
  const atrPctSeries = materializeNumericHistory(
@@ -8501,6 +8590,18 @@ var buildBaseContextSnapshot = ({
8501
8590
  coinCandles: candlesHistory,
8502
8591
  ethCandles: ethCandlesHistory
8503
8592
  }) : null;
8593
+ const btcPsychologicalLevels = buildPsychologicalLevelAssetContext(
8594
+ btcCandlesHistory,
8595
+ 1e3
8596
+ );
8597
+ const ethPsychologicalLevels = buildPsychologicalLevelAssetContext(
8598
+ ethCandlesHistory,
8599
+ 100
8600
+ );
8601
+ const referencePsychologicalLevels = btcPsychologicalLevels != null || ethPsychologicalLevels != null ? {
8602
+ ...btcPsychologicalLevels != null ? { BTCUSDT: btcPsychologicalLevels } : {},
8603
+ ...ethPsychologicalLevels != null ? { ETHUSDT: ethPsychologicalLevels } : {}
8604
+ } : null;
8504
8605
  const relativeStrength1h = getRelativeChange(
8505
8606
  baseResult.price1hPcnt,
8506
8607
  btc1h.length >= 2 ? percentChange(
@@ -8875,7 +8976,8 @@ var buildBaseContextSnapshot = ({
8875
8976
  )
8876
8977
  },
8877
8978
  targetVsBtc,
8878
- ...targetVsEth != null ? { targetVsEth } : {}
8979
+ ...targetVsEth != null ? { targetVsEth } : {},
8980
+ ...referencePsychologicalLevels != null ? { referencePsychologicalLevels } : {}
8879
8981
  }
8880
8982
  };
8881
8983
  let cachedMtfSnapshot = null;
@@ -10722,19 +10824,19 @@ var createIndicators = (data, btcData = [], options = {}) => {
10722
10824
  volumeSeries: volumes,
10723
10825
  btcCloseSeries: btcCloses,
10724
10826
  coinResampledCandles: {
10725
- h1: coin1hCache.snapshot(),
10726
- h4: coin4hCache.snapshot(),
10727
- d1: coin1dCache.snapshot()
10827
+ h1: coin1hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10828
+ h4: coin4hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10829
+ d1: coin1dCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW)
10728
10830
  },
10729
10831
  btcResampledCandles: {
10730
- h1: btc1hCache.snapshot(),
10731
- h4: btc4hCache.snapshot(),
10732
- d1: btc1dCache.snapshot()
10832
+ h1: btc1hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10833
+ h4: btc4hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10834
+ d1: btc1dCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW)
10733
10835
  },
10734
10836
  ethResampledCandles: {
10735
- h1: eth1hCache.snapshot(),
10736
- h4: eth4hCache.snapshot(),
10737
- d1: eth1dCache.snapshot()
10837
+ h1: eth1hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10838
+ h4: eth4hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10839
+ d1: eth1dCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW)
10738
10840
  },
10739
10841
  indicatorHistory,
10740
10842
  indicatorPeriods,
@@ -6984,6 +6984,12 @@ var SESSION_WINDOWS = [
6984
6984
  var FUNDING_WINDOW_STEP_MINUTES = 8 * 60;
6985
6985
  var FUNDING_WINDOW_NEARBY_MINUTES = 60;
6986
6986
  var SESSION_WINDOW_EDGE_MINUTES = 60;
6987
+ var BASE_INTERVAL_MS = 15 * 6e4;
6988
+ var PSYCHOLOGICAL_LEVEL_WINDOWS = {
6989
+ m15: BASE_INTERVAL_MS,
6990
+ h1: 60 * 6e4,
6991
+ h4: 4 * 60 * 6e4
6992
+ };
6987
6993
  var isInsideSession = (minuteUtc, startMinuteUtc, endMinuteUtc) => startMinuteUtc <= endMinuteUtc ? minuteUtc >= startMinuteUtc && minuteUtc < endMinuteUtc : minuteUtc >= startMinuteUtc || minuteUtc < endMinuteUtc;
6988
6994
  var buildSessionContext = (timestamp) => {
6989
6995
  const date = new Date(timestamp);
@@ -7015,7 +7021,80 @@ var buildSessionContext = (timestamp) => {
7015
7021
  isWeekendUtc: dayOfWeekUtc >= 6
7016
7022
  };
7017
7023
  };
7024
+ var buildUnavailablePsychologicalLevelWindow = () => ({
7025
+ crossed: null,
7026
+ direction: "unknown",
7027
+ level: null,
7028
+ levelsCrossed: null,
7029
+ distanceBeyondLevelBps: null
7030
+ });
7031
+ var buildPsychologicalLevelWindow = (startPrice, endPrice, stepUsd) => {
7032
+ if (!Number.isFinite(startPrice) || !Number.isFinite(endPrice) || !Number.isFinite(stepUsd) || startPrice <= 0 || endPrice <= 0 || stepUsd <= 0) {
7033
+ return buildUnavailablePsychologicalLevelWindow();
7034
+ }
7035
+ if (endPrice === startPrice) {
7036
+ return {
7037
+ crossed: false,
7038
+ direction: "none",
7039
+ level: null,
7040
+ levelsCrossed: 0,
7041
+ distanceBeyondLevelBps: null
7042
+ };
7043
+ }
7044
+ const movingUp = endPrice > startPrice;
7045
+ const firstCrossedLevel = movingUp ? (Math.floor(startPrice / stepUsd) + 1) * stepUsd : (Math.ceil(startPrice / stepUsd) - 1) * stepUsd;
7046
+ const lastCrossedLevel = movingUp ? Math.floor(endPrice / stepUsd) * stepUsd : Math.ceil(endPrice / stepUsd) * stepUsd;
7047
+ const crossed = movingUp ? firstCrossedLevel <= lastCrossedLevel : firstCrossedLevel >= lastCrossedLevel;
7048
+ if (!crossed) {
7049
+ return {
7050
+ crossed: false,
7051
+ direction: "none",
7052
+ level: null,
7053
+ levelsCrossed: 0,
7054
+ distanceBeyondLevelBps: null
7055
+ };
7056
+ }
7057
+ const levelsCrossed = Math.round(Math.abs(lastCrossedLevel - firstCrossedLevel) / stepUsd) + 1;
7058
+ const distanceBeyondLevelBps = Math.abs(endPrice - lastCrossedLevel) / lastCrossedLevel * 1e4;
7059
+ return {
7060
+ crossed: true,
7061
+ direction: movingUp ? "up" : "down",
7062
+ level: lastCrossedLevel,
7063
+ levelsCrossed,
7064
+ distanceBeyondLevelBps
7065
+ };
7066
+ };
7067
+ var buildPsychologicalLevelAssetContext = (candles, stepUsd) => {
7068
+ const endCandle = candles[candles.length - 1];
7069
+ if (!endCandle) {
7070
+ return null;
7071
+ }
7072
+ const candlesByTimestamp = new Map(
7073
+ candles.map((item) => [item.timestamp, item])
7074
+ );
7075
+ const windows = Object.fromEntries(
7076
+ Object.entries(PSYCHOLOGICAL_LEVEL_WINDOWS).map(([window, durationMs]) => {
7077
+ const startCandle = candlesByTimestamp.get(
7078
+ endCandle.timestamp - durationMs
7079
+ );
7080
+ return [
7081
+ window,
7082
+ startCandle ? buildPsychologicalLevelWindow(
7083
+ startCandle.close,
7084
+ endCandle.close,
7085
+ stepUsd
7086
+ ) : buildUnavailablePsychologicalLevelWindow()
7087
+ ];
7088
+ })
7089
+ );
7090
+ return {
7091
+ source: "aligned_15m_ohlcv",
7092
+ stepUsd,
7093
+ windows
7094
+ };
7095
+ };
7018
7096
  var STRUCTURE_LOOKBACK = 80;
7097
+ var BASE_CONTEXT_CANDLE_WINDOW = 256;
7019
7098
  var PIVOT_LEFT_RIGHT = 2;
7020
7099
  var ZONE_ATR_FACTOR = 0.5;
7021
7100
  var PROFILE_BIN_COUNT = 24;
@@ -8439,12 +8518,12 @@ var buildBaseContextSnapshot = ({
8439
8518
  candle,
8440
8519
  prevCandle,
8441
8520
  baseResult,
8442
- candlesHistory,
8443
- btcCandlesHistory,
8444
- ethCandlesHistory = [],
8445
- closeSeries,
8446
- volumeSeries,
8447
- btcCloseSeries,
8521
+ candlesHistory: fullCandlesHistory,
8522
+ btcCandlesHistory: fullBtcCandlesHistory,
8523
+ ethCandlesHistory: fullEthCandlesHistory = [],
8524
+ closeSeries: fullCloseSeries,
8525
+ volumeSeries: fullVolumeSeries,
8526
+ btcCloseSeries: fullBtcCloseSeries,
8448
8527
  coinResampledCandles,
8449
8528
  btcResampledCandles,
8450
8529
  ethResampledCandles,
@@ -8459,6 +8538,16 @@ var buildBaseContextSnapshot = ({
8459
8538
  adaptiveChannel: precomputedAdaptiveChannel,
8460
8539
  psar: precomputedPsar
8461
8540
  }) => {
8541
+ const candlesHistory = fullCandlesHistory.slice(-BASE_CONTEXT_CANDLE_WINDOW);
8542
+ const btcCandlesHistory = fullBtcCandlesHistory.slice(
8543
+ -BASE_CONTEXT_CANDLE_WINDOW
8544
+ );
8545
+ const ethCandlesHistory = fullEthCandlesHistory.slice(
8546
+ -BASE_CONTEXT_CANDLE_WINDOW
8547
+ );
8548
+ const closeSeries = fullCloseSeries.slice(-BASE_CONTEXT_CANDLE_WINDOW);
8549
+ const volumeSeries = fullVolumeSeries.slice(-BASE_CONTEXT_CANDLE_WINDOW);
8550
+ const btcCloseSeries = fullBtcCloseSeries.slice(-BASE_CONTEXT_CANDLE_WINDOW);
8462
8551
  const atr2 = toNullable(baseResult.atr);
8463
8552
  const bbWidthPct = baseResult.bbUpper != null && baseResult.bbLower != null && baseResult.bbMiddle != null && baseResult.bbMiddle !== 0 ? (baseResult.bbUpper - baseResult.bbLower) / baseResult.bbMiddle * 100 : null;
8464
8553
  const atrPctSeries = materializeNumericHistory(
@@ -8616,6 +8705,18 @@ var buildBaseContextSnapshot = ({
8616
8705
  coinCandles: candlesHistory,
8617
8706
  ethCandles: ethCandlesHistory
8618
8707
  }) : null;
8708
+ const btcPsychologicalLevels = buildPsychologicalLevelAssetContext(
8709
+ btcCandlesHistory,
8710
+ 1e3
8711
+ );
8712
+ const ethPsychologicalLevels = buildPsychologicalLevelAssetContext(
8713
+ ethCandlesHistory,
8714
+ 100
8715
+ );
8716
+ const referencePsychologicalLevels = btcPsychologicalLevels != null || ethPsychologicalLevels != null ? {
8717
+ ...btcPsychologicalLevels != null ? { BTCUSDT: btcPsychologicalLevels } : {},
8718
+ ...ethPsychologicalLevels != null ? { ETHUSDT: ethPsychologicalLevels } : {}
8719
+ } : null;
8619
8720
  const relativeStrength1h = getRelativeChange(
8620
8721
  baseResult.price1hPcnt,
8621
8722
  btc1h.length >= 2 ? percentChange(
@@ -8990,7 +9091,8 @@ var buildBaseContextSnapshot = ({
8990
9091
  )
8991
9092
  },
8992
9093
  targetVsBtc,
8993
- ...targetVsEth != null ? { targetVsEth } : {}
9094
+ ...targetVsEth != null ? { targetVsEth } : {},
9095
+ ...referencePsychologicalLevels != null ? { referencePsychologicalLevels } : {}
8994
9096
  }
8995
9097
  };
8996
9098
  let cachedMtfSnapshot = null;
@@ -10837,19 +10939,19 @@ var createIndicators = (data, btcData = [], options = {}) => {
10837
10939
  volumeSeries: volumes,
10838
10940
  btcCloseSeries: btcCloses,
10839
10941
  coinResampledCandles: {
10840
- h1: coin1hCache.snapshot(),
10841
- h4: coin4hCache.snapshot(),
10842
- d1: coin1dCache.snapshot()
10942
+ h1: coin1hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10943
+ h4: coin4hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10944
+ d1: coin1dCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW)
10843
10945
  },
10844
10946
  btcResampledCandles: {
10845
- h1: btc1hCache.snapshot(),
10846
- h4: btc4hCache.snapshot(),
10847
- d1: btc1dCache.snapshot()
10947
+ h1: btc1hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10948
+ h4: btc4hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10949
+ d1: btc1dCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW)
10848
10950
  },
10849
10951
  ethResampledCandles: {
10850
- h1: eth1hCache.snapshot(),
10851
- h4: eth4hCache.snapshot(),
10852
- d1: eth1dCache.snapshot()
10952
+ h1: eth1hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10953
+ h4: eth4hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10954
+ d1: eth1dCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW)
10853
10955
  },
10854
10956
  indicatorHistory,
10855
10957
  indicatorPeriods,
@@ -39,7 +39,7 @@ import {
39
39
  toArrayData,
40
40
  toCoinalyzeTimestampMs,
41
41
  toFiniteNumber
42
- } from "./chunk-HM7WDSPT.mjs";
42
+ } from "./chunk-HVCNGDPT.mjs";
43
43
  import "./chunk-AYC2QVKI.mjs";
44
44
  import "./chunk-M7QGVZ3J.mjs";
45
45
  import "./chunk-BOETNABM.mjs";
@@ -104,8 +104,14 @@ interface CreateStrategyAPIParams {
104
104
  isConfigFromBacktest?: Signal['isConfigFromBacktest'];
105
105
  sharedReplayKey?: string;
106
106
  getSharedReplayState?: StrategySharedReplayStateGetter;
107
+ loadDecisionBaseContext?: (params: {
108
+ baseContext: BaseStrategyContextSnapshot | undefined;
109
+ candle: KlineChartData[number];
110
+ symbol: Signal['symbol'];
111
+ interval: Signal['interval'];
112
+ }) => Promise<BaseStrategyContextSnapshot | undefined>;
107
113
  }
108
- declare const createStrategyAPI: <TIndicators = IndicatorsHistorySnapshot | Record<string, unknown>>({ strategy, symbol, interval, env, connector, cachedData, indicatorsState, isConfigFromBacktest, sharedReplayKey, getSharedReplayState, }: CreateStrategyAPIParams) => StrategyAPI<TIndicators>;
114
+ declare const createStrategyAPI: <TIndicators = IndicatorsHistorySnapshot | Record<string, unknown>>({ strategy, symbol, interval, env, connector, cachedData, indicatorsState, isConfigFromBacktest, sharedReplayKey, getSharedReplayState, loadDecisionBaseContext, }: CreateStrategyAPIParams) => StrategyAPI<TIndicators>;
109
115
 
110
116
  declare const getSharedStrategyReplayState: <TState>(key: string | undefined, createState: () => TState) => TState;
111
117
  declare const releaseStrategyReplayCache: (keyPrefix: string) => void;
@@ -104,8 +104,14 @@ interface CreateStrategyAPIParams {
104
104
  isConfigFromBacktest?: Signal['isConfigFromBacktest'];
105
105
  sharedReplayKey?: string;
106
106
  getSharedReplayState?: StrategySharedReplayStateGetter;
107
+ loadDecisionBaseContext?: (params: {
108
+ baseContext: BaseStrategyContextSnapshot | undefined;
109
+ candle: KlineChartData[number];
110
+ symbol: Signal['symbol'];
111
+ interval: Signal['interval'];
112
+ }) => Promise<BaseStrategyContextSnapshot | undefined>;
107
113
  }
108
- declare const createStrategyAPI: <TIndicators = IndicatorsHistorySnapshot | Record<string, unknown>>({ strategy, symbol, interval, env, connector, cachedData, indicatorsState, isConfigFromBacktest, sharedReplayKey, getSharedReplayState, }: CreateStrategyAPIParams) => StrategyAPI<TIndicators>;
114
+ declare const createStrategyAPI: <TIndicators = IndicatorsHistorySnapshot | Record<string, unknown>>({ strategy, symbol, interval, env, connector, cachedData, indicatorsState, isConfigFromBacktest, sharedReplayKey, getSharedReplayState, loadDecisionBaseContext, }: CreateStrategyAPIParams) => StrategyAPI<TIndicators>;
109
115
 
110
116
  declare const getSharedStrategyReplayState: <TState>(key: string | undefined, createState: () => TState) => TState;
111
117
  declare const releaseStrategyReplayCache: (keyPrefix: string) => void;
@@ -6416,6 +6416,12 @@ var SESSION_WINDOWS = [
6416
6416
  var FUNDING_WINDOW_STEP_MINUTES = 8 * 60;
6417
6417
  var FUNDING_WINDOW_NEARBY_MINUTES = 60;
6418
6418
  var SESSION_WINDOW_EDGE_MINUTES = 60;
6419
+ var BASE_INTERVAL_MS = 15 * 6e4;
6420
+ var PSYCHOLOGICAL_LEVEL_WINDOWS = {
6421
+ m15: BASE_INTERVAL_MS,
6422
+ h1: 60 * 6e4,
6423
+ h4: 4 * 60 * 6e4
6424
+ };
6419
6425
  var isInsideSession = (minuteUtc, startMinuteUtc, endMinuteUtc) => startMinuteUtc <= endMinuteUtc ? minuteUtc >= startMinuteUtc && minuteUtc < endMinuteUtc : minuteUtc >= startMinuteUtc || minuteUtc < endMinuteUtc;
6420
6426
  var buildSessionContext = (timestamp) => {
6421
6427
  const date = new Date(timestamp);
@@ -6447,7 +6453,80 @@ var buildSessionContext = (timestamp) => {
6447
6453
  isWeekendUtc: dayOfWeekUtc >= 6
6448
6454
  };
6449
6455
  };
6456
+ var buildUnavailablePsychologicalLevelWindow = () => ({
6457
+ crossed: null,
6458
+ direction: "unknown",
6459
+ level: null,
6460
+ levelsCrossed: null,
6461
+ distanceBeyondLevelBps: null
6462
+ });
6463
+ var buildPsychologicalLevelWindow = (startPrice, endPrice, stepUsd) => {
6464
+ if (!Number.isFinite(startPrice) || !Number.isFinite(endPrice) || !Number.isFinite(stepUsd) || startPrice <= 0 || endPrice <= 0 || stepUsd <= 0) {
6465
+ return buildUnavailablePsychologicalLevelWindow();
6466
+ }
6467
+ if (endPrice === startPrice) {
6468
+ return {
6469
+ crossed: false,
6470
+ direction: "none",
6471
+ level: null,
6472
+ levelsCrossed: 0,
6473
+ distanceBeyondLevelBps: null
6474
+ };
6475
+ }
6476
+ const movingUp = endPrice > startPrice;
6477
+ const firstCrossedLevel = movingUp ? (Math.floor(startPrice / stepUsd) + 1) * stepUsd : (Math.ceil(startPrice / stepUsd) - 1) * stepUsd;
6478
+ const lastCrossedLevel = movingUp ? Math.floor(endPrice / stepUsd) * stepUsd : Math.ceil(endPrice / stepUsd) * stepUsd;
6479
+ const crossed = movingUp ? firstCrossedLevel <= lastCrossedLevel : firstCrossedLevel >= lastCrossedLevel;
6480
+ if (!crossed) {
6481
+ return {
6482
+ crossed: false,
6483
+ direction: "none",
6484
+ level: null,
6485
+ levelsCrossed: 0,
6486
+ distanceBeyondLevelBps: null
6487
+ };
6488
+ }
6489
+ const levelsCrossed = Math.round(Math.abs(lastCrossedLevel - firstCrossedLevel) / stepUsd) + 1;
6490
+ const distanceBeyondLevelBps = Math.abs(endPrice - lastCrossedLevel) / lastCrossedLevel * 1e4;
6491
+ return {
6492
+ crossed: true,
6493
+ direction: movingUp ? "up" : "down",
6494
+ level: lastCrossedLevel,
6495
+ levelsCrossed,
6496
+ distanceBeyondLevelBps
6497
+ };
6498
+ };
6499
+ var buildPsychologicalLevelAssetContext = (candles, stepUsd) => {
6500
+ const endCandle = candles[candles.length - 1];
6501
+ if (!endCandle) {
6502
+ return null;
6503
+ }
6504
+ const candlesByTimestamp = new Map(
6505
+ candles.map((item) => [item.timestamp, item])
6506
+ );
6507
+ const windows = Object.fromEntries(
6508
+ Object.entries(PSYCHOLOGICAL_LEVEL_WINDOWS).map(([window, durationMs]) => {
6509
+ const startCandle = candlesByTimestamp.get(
6510
+ endCandle.timestamp - durationMs
6511
+ );
6512
+ return [
6513
+ window,
6514
+ startCandle ? buildPsychologicalLevelWindow(
6515
+ startCandle.close,
6516
+ endCandle.close,
6517
+ stepUsd
6518
+ ) : buildUnavailablePsychologicalLevelWindow()
6519
+ ];
6520
+ })
6521
+ );
6522
+ return {
6523
+ source: "aligned_15m_ohlcv",
6524
+ stepUsd,
6525
+ windows
6526
+ };
6527
+ };
6450
6528
  var STRUCTURE_LOOKBACK = 80;
6529
+ var BASE_CONTEXT_CANDLE_WINDOW = 256;
6451
6530
  var PIVOT_LEFT_RIGHT = 2;
6452
6531
  var ZONE_ATR_FACTOR = 0.5;
6453
6532
  var PROFILE_BIN_COUNT = 24;
@@ -7871,12 +7950,12 @@ var buildBaseContextSnapshot = ({
7871
7950
  candle,
7872
7951
  prevCandle,
7873
7952
  baseResult,
7874
- candlesHistory,
7875
- btcCandlesHistory,
7876
- ethCandlesHistory = [],
7877
- closeSeries,
7878
- volumeSeries,
7879
- btcCloseSeries,
7953
+ candlesHistory: fullCandlesHistory,
7954
+ btcCandlesHistory: fullBtcCandlesHistory,
7955
+ ethCandlesHistory: fullEthCandlesHistory = [],
7956
+ closeSeries: fullCloseSeries,
7957
+ volumeSeries: fullVolumeSeries,
7958
+ btcCloseSeries: fullBtcCloseSeries,
7880
7959
  coinResampledCandles,
7881
7960
  btcResampledCandles,
7882
7961
  ethResampledCandles,
@@ -7891,6 +7970,16 @@ var buildBaseContextSnapshot = ({
7891
7970
  adaptiveChannel: precomputedAdaptiveChannel,
7892
7971
  psar: precomputedPsar
7893
7972
  }) => {
7973
+ const candlesHistory = fullCandlesHistory.slice(-BASE_CONTEXT_CANDLE_WINDOW);
7974
+ const btcCandlesHistory = fullBtcCandlesHistory.slice(
7975
+ -BASE_CONTEXT_CANDLE_WINDOW
7976
+ );
7977
+ const ethCandlesHistory = fullEthCandlesHistory.slice(
7978
+ -BASE_CONTEXT_CANDLE_WINDOW
7979
+ );
7980
+ const closeSeries = fullCloseSeries.slice(-BASE_CONTEXT_CANDLE_WINDOW);
7981
+ const volumeSeries = fullVolumeSeries.slice(-BASE_CONTEXT_CANDLE_WINDOW);
7982
+ const btcCloseSeries = fullBtcCloseSeries.slice(-BASE_CONTEXT_CANDLE_WINDOW);
7894
7983
  const atr2 = toNullable(baseResult.atr);
7895
7984
  const bbWidthPct = baseResult.bbUpper != null && baseResult.bbLower != null && baseResult.bbMiddle != null && baseResult.bbMiddle !== 0 ? (baseResult.bbUpper - baseResult.bbLower) / baseResult.bbMiddle * 100 : null;
7896
7985
  const atrPctSeries = materializeNumericHistory(
@@ -8048,6 +8137,18 @@ var buildBaseContextSnapshot = ({
8048
8137
  coinCandles: candlesHistory,
8049
8138
  ethCandles: ethCandlesHistory
8050
8139
  }) : null;
8140
+ const btcPsychologicalLevels = buildPsychologicalLevelAssetContext(
8141
+ btcCandlesHistory,
8142
+ 1e3
8143
+ );
8144
+ const ethPsychologicalLevels = buildPsychologicalLevelAssetContext(
8145
+ ethCandlesHistory,
8146
+ 100
8147
+ );
8148
+ const referencePsychologicalLevels = btcPsychologicalLevels != null || ethPsychologicalLevels != null ? {
8149
+ ...btcPsychologicalLevels != null ? { BTCUSDT: btcPsychologicalLevels } : {},
8150
+ ...ethPsychologicalLevels != null ? { ETHUSDT: ethPsychologicalLevels } : {}
8151
+ } : null;
8051
8152
  const relativeStrength1h = getRelativeChange(
8052
8153
  baseResult.price1hPcnt,
8053
8154
  btc1h.length >= 2 ? percentChange(
@@ -8422,7 +8523,8 @@ var buildBaseContextSnapshot = ({
8422
8523
  )
8423
8524
  },
8424
8525
  targetVsBtc,
8425
- ...targetVsEth != null ? { targetVsEth } : {}
8526
+ ...targetVsEth != null ? { targetVsEth } : {},
8527
+ ...referencePsychologicalLevels != null ? { referencePsychologicalLevels } : {}
8426
8528
  }
8427
8529
  };
8428
8530
  let cachedMtfSnapshot = null;
@@ -10136,19 +10238,19 @@ var createIndicators = (data, btcData = [], options = {}) => {
10136
10238
  volumeSeries: volumes,
10137
10239
  btcCloseSeries: btcCloses,
10138
10240
  coinResampledCandles: {
10139
- h1: coin1hCache.snapshot(),
10140
- h4: coin4hCache.snapshot(),
10141
- d1: coin1dCache.snapshot()
10241
+ h1: coin1hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10242
+ h4: coin4hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10243
+ d1: coin1dCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW)
10142
10244
  },
10143
10245
  btcResampledCandles: {
10144
- h1: btc1hCache.snapshot(),
10145
- h4: btc4hCache.snapshot(),
10146
- d1: btc1dCache.snapshot()
10246
+ h1: btc1hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10247
+ h4: btc4hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10248
+ d1: btc1dCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW)
10147
10249
  },
10148
10250
  ethResampledCandles: {
10149
- h1: eth1hCache.snapshot(),
10150
- h4: eth4hCache.snapshot(),
10151
- d1: eth1dCache.snapshot()
10251
+ h1: eth1hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10252
+ h4: eth4hCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW),
10253
+ d1: eth1dCache.snapshot().slice(-ML_BASE_CANDLES_WINDOW)
10152
10254
  },
10153
10255
  indicatorHistory,
10154
10256
  indicatorPeriods,
@@ -10835,6 +10937,7 @@ var createStrategyIndicatorsState = ({
10835
10937
  // Lazy bootstrap for live mode: initialize on history before current bar and then apply current bar once.
10836
10938
  ensureInitializedWithCurrentBar: ensureControllerInitialized,
10837
10939
  snapshot: (options) => ensureControllerInitialized().snapshot(options),
10940
+ latestSnapshot: () => ensureControllerInitialized().latestSnapshot(),
10838
10941
  latestNumber: (key) => ensureControllerInitialized().latestNumber(key)
10839
10942
  };
10840
10943
  };
@@ -11236,6 +11339,7 @@ var pushWhen = (items, condition, item) => {
11236
11339
  items.push(item);
11237
11340
  }
11238
11341
  };
11342
+ var HYPERLIQUID_WHALE_GATE_MIN_NOTIONAL_USD = 5e4;
11239
11343
  var buildBaseContextGateFeatures = ({
11240
11344
  baseContext,
11241
11345
  direction,
@@ -11253,6 +11357,7 @@ var buildBaseContextGateFeatures = ({
11253
11357
  const volume = baseContext.participation?.volume;
11254
11358
  const delta = baseContext.participation?.delta;
11255
11359
  const tradeFlow = baseContext.participation?.tradeFlow;
11360
+ const hyperliquidWhales = baseContext.participation?.hyperliquidWhales;
11256
11361
  const volumeStructure = baseContext.participation?.volumeStructure;
11257
11362
  const relative = baseContext.relative?.benchmark;
11258
11363
  const marketBreadth = baseContext.relative?.marketBreadth;
@@ -11300,10 +11405,36 @@ var buildBaseContextGateFeatures = ({
11300
11405
  const referenceTradeFlowBuyPressurePct = asFiniteNumberOrNull(
11301
11406
  primaryReferenceTradeFlow?.buyPressurePct
11302
11407
  );
11408
+ const rawHyperliquidWhaleBuySharePct = asFiniteNumberOrNull(
11409
+ hyperliquidWhales?.buySharePct
11410
+ );
11411
+ const rawHyperliquidWhaleNetNotionalUsd = asFiniteNumberOrNull(
11412
+ hyperliquidWhales?.netNotionalUsd
11413
+ );
11414
+ const rawHyperliquidWhaleUniqueCount = asFiniteNumberOrNull(
11415
+ hyperliquidWhales?.uniqueWhales
11416
+ );
11417
+ const hyperliquidWhaleCoveredCount = asFiniteNumberOrNull(
11418
+ hyperliquidWhales?.coveredWhales
11419
+ );
11420
+ const hyperliquidWhaleExpectedCount = asFiniteNumberOrNull(
11421
+ hyperliquidWhales?.expectedWhales
11422
+ );
11423
+ const hyperliquidWhaleCoveragePct = asFiniteNumberOrNull(
11424
+ hyperliquidWhales?.coveragePct
11425
+ );
11426
+ const hyperliquidWhaleCoverageSufficient = typeof hyperliquidWhales?.coverageSufficient === "boolean" ? hyperliquidWhales.coverageSufficient : null;
11427
+ const hyperliquidWhaleBuySharePct = hyperliquidWhaleCoverageSufficient === true ? rawHyperliquidWhaleBuySharePct : null;
11428
+ const hyperliquidWhaleNetNotionalUsd = hyperliquidWhaleCoverageSufficient === true ? rawHyperliquidWhaleNetNotionalUsd : null;
11429
+ const hyperliquidWhaleUniqueCount = hyperliquidWhaleCoverageSufficient === true ? rawHyperliquidWhaleUniqueCount : null;
11430
+ const hyperliquidWhaleNotionalUsd = hyperliquidWhaleCoverageSufficient === true ? (asFiniteNumberOrNull(hyperliquidWhales?.buyNotionalUsd) ?? 0) + (asFiniteNumberOrNull(hyperliquidWhales?.sellNotionalUsd) ?? 0) : null;
11431
+ const hyperliquidWhaleSufficientActivity = hyperliquidWhales == null || hyperliquidWhales.stale || hyperliquidWhaleCoverageSufficient !== true ? null : (hyperliquidWhaleNotionalUsd ?? 0) >= HYPERLIQUID_WHALE_GATE_MIN_NOTIONAL_USD;
11303
11432
  const deltaDivergenceVsPrice = asStringOrNull(delta?.deltaDivergenceVsPrice);
11304
11433
  const deltaBias = deltaDivergenceVsPrice === "bullish" || deltaDivergenceVsPrice === "bearish" ? deltaDivergenceVsPrice === "bullish" ? "bull" : "bear" : toPressureBias(buyPressurePct);
11305
11434
  const tradeFlowBias = tradeFlow?.stale ? "unknown" : toPressureBias(tradeFlowBuyPressurePct);
11306
11435
  const referenceTradeFlowBias = primaryReferenceTradeFlow?.stale ? "unknown" : toPressureBias(referenceTradeFlowBuyPressurePct);
11436
+ const hyperliquidWhaleFlowStale = typeof hyperliquidWhales?.stale === "boolean" ? hyperliquidWhales.stale : null;
11437
+ const hyperliquidWhaleFlowBias = hyperliquidWhaleSufficientActivity !== true ? "unknown" : toPressureBias(hyperliquidWhaleBuySharePct);
11307
11438
  const deltaAligned = toBiasAligned({ direction, bias: deltaBias });
11308
11439
  const tradeFlowAligned = toBiasAligned({
11309
11440
  direction,
@@ -11313,6 +11444,10 @@ var buildBaseContextGateFeatures = ({
11313
11444
  direction,
11314
11445
  bias: referenceTradeFlowBias
11315
11446
  });
11447
+ const hyperliquidWhaleFlowAligned = toBiasAligned({
11448
+ direction,
11449
+ bias: hyperliquidWhaleFlowBias
11450
+ });
11316
11451
  const benchmarkTrendAlignment = relative?.trendAlignment ?? "unknown";
11317
11452
  const relativeStrength1h = asFiniteNumberOrNull(relative?.relativeStrength1h);
11318
11453
  const relativeStrengthBucket = toRelativeStrengthBucket({
@@ -11420,6 +11555,11 @@ var buildBaseContextGateFeatures = ({
11420
11555
  pushWhen(confirmations, (volumeRel20 ?? 0) >= 1.5, "volume_expansion");
11421
11556
  pushWhen(confirmations, deltaAligned === true, "delta_aligned");
11422
11557
  pushWhen(confirmations, tradeFlowAligned === true, "trade_flow_aligned");
11558
+ pushWhen(
11559
+ confirmations,
11560
+ hyperliquidWhaleFlowAligned === true,
11561
+ "hyperliquid_whales_aligned"
11562
+ );
11423
11563
  pushWhen(
11424
11564
  confirmations,
11425
11565
  referenceTradeFlowAligned === true,
@@ -11494,6 +11634,11 @@ var buildBaseContextGateFeatures = ({
11494
11634
  pushWhen(conflicts, btcAltRegimeAligned === false, "btc_alt_regime_against");
11495
11635
  pushWhen(conflicts, deltaAligned === false, "delta_against");
11496
11636
  pushWhen(conflicts, tradeFlowAligned === false, "trade_flow_against");
11637
+ pushWhen(
11638
+ conflicts,
11639
+ hyperliquidWhaleFlowAligned === false,
11640
+ "hyperliquid_whales_against"
11641
+ );
11497
11642
  pushWhen(
11498
11643
  conflicts,
11499
11644
  referenceTradeFlowAligned === false,
@@ -11519,6 +11664,7 @@ var buildBaseContextGateFeatures = ({
11519
11664
  volumeRel20 == null ? null : volumeRel20 >= 1.5,
11520
11665
  deltaAligned,
11521
11666
  tradeFlowAligned,
11667
+ hyperliquidWhaleFlowAligned,
11522
11668
  referenceTradeFlowAligned,
11523
11669
  volumeStructureAligned
11524
11670
  ]),
@@ -11624,6 +11770,17 @@ var buildBaseContextGateFeatures = ({
11624
11770
  deltaAligned,
11625
11771
  tradeFlowBuyPressurePct,
11626
11772
  tradeFlowAligned,
11773
+ hyperliquidWhaleBuySharePct,
11774
+ hyperliquidWhaleNetNotionalUsd,
11775
+ hyperliquidWhaleUniqueCount,
11776
+ hyperliquidWhaleCoveredCount,
11777
+ hyperliquidWhaleExpectedCount,
11778
+ hyperliquidWhaleCoveragePct,
11779
+ hyperliquidWhaleCoverageSufficient,
11780
+ hyperliquidWhaleNotionalUsd,
11781
+ hyperliquidWhaleSufficientActivity,
11782
+ hyperliquidWhaleFlowAligned,
11783
+ hyperliquidWhaleFlowStale,
11627
11784
  referenceTradeFlowBuyPressurePct,
11628
11785
  referenceTradeFlowAligned,
11629
11786
  volumeStructureAligned
@@ -11836,7 +11993,8 @@ var createStrategyAPI = ({
11836
11993
  indicatorsState,
11837
11994
  isConfigFromBacktest,
11838
11995
  sharedReplayKey,
11839
- getSharedReplayState
11996
+ getSharedReplayState,
11997
+ loadDecisionBaseContext
11840
11998
  }) => {
11841
11999
  const isBacktestEnv = env === "BACKTEST";
11842
12000
  const barCache = {
@@ -11844,6 +12002,7 @@ var createStrategyAPI = ({
11844
12002
  currentPosition: void 0
11845
12003
  };
11846
12004
  let currentIndicatorsContextCache;
12005
+ let decisionBaseContextCache;
11847
12006
  const getCurrentBarTimestamp = () => {
11848
12007
  const lastCandle = cachedData[cachedData.length - 1];
11849
12008
  return typeof lastCandle?.timestamp === "number" ? lastCandle.timestamp : null;
@@ -11875,6 +12034,7 @@ var createStrategyAPI = ({
11875
12034
  barCache.timestamp = currentBarTimestamp;
11876
12035
  barCache.currentPosition = void 0;
11877
12036
  currentIndicatorsContextCache = void 0;
12037
+ decisionBaseContextCache = void 0;
11878
12038
  };
11879
12039
  const getCurrentPosition = () => {
11880
12040
  if (!isBacktestEnv) {
@@ -11911,7 +12071,44 @@ var createStrategyAPI = ({
11911
12071
  };
11912
12072
  return context;
11913
12073
  };
11914
- const getBaseContext = () => getCurrentIndicatorsContext().baseContext;
12074
+ const getBaseContext = () => {
12075
+ ensureBarCache();
12076
+ const cacheKey = getCurrentIndicatorsCacheKey();
12077
+ if (currentIndicatorsContextCache?.key === cacheKey) {
12078
+ return currentIndicatorsContextCache.context.baseContext;
12079
+ }
12080
+ if (!indicatorsState?.latestSnapshot) {
12081
+ return getCurrentIndicatorsContext().baseContext;
12082
+ }
12083
+ indicatorsState?.onBar();
12084
+ const latestBaseContext = getBaseContextFromIndicators(
12085
+ indicatorsState.latestSnapshot()
12086
+ );
12087
+ return latestBaseContext ?? getCurrentIndicatorsContext().baseContext;
12088
+ };
12089
+ const getDecisionBaseContext = () => {
12090
+ ensureBarCache();
12091
+ const baseContext = getBaseContext();
12092
+ if (!loadDecisionBaseContext) {
12093
+ return Promise.resolve(baseContext);
12094
+ }
12095
+ const candle = cachedData[cachedData.length - 1];
12096
+ if (!candle) {
12097
+ return Promise.resolve(baseContext);
12098
+ }
12099
+ const cacheKey = getCurrentIndicatorsCacheKey();
12100
+ if (decisionBaseContextCache?.key === cacheKey) {
12101
+ return decisionBaseContextCache.context;
12102
+ }
12103
+ const context = loadDecisionBaseContext({
12104
+ baseContext,
12105
+ candle,
12106
+ symbol,
12107
+ interval
12108
+ });
12109
+ decisionBaseContextCache = { key: cacheKey, context };
12110
+ return context;
12111
+ };
11915
12112
  const resolveDecisionPriceContext = () => {
11916
12113
  const candle = cachedData[cachedData.length - 1];
11917
12114
  if (!candle || !isFiniteNumber3(candle.timestamp) || !isFiniteNumber3(candle.close)) {
@@ -12001,6 +12198,7 @@ var createStrategyAPI = ({
12001
12198
  }),
12002
12199
  getCurrentIndicatorsContext,
12003
12200
  getBaseContext,
12201
+ getDecisionBaseContext,
12004
12202
  getDecisionPriceContext,
12005
12203
  getCurrentPosition,
12006
12204
  getDirectionalTpSlPrices: (params) => getDirectionalTpSlPrices(params),
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createIndicators,
3
3
  getRequiredControllerSeedWindow
4
- } from "./chunk-HM7WDSPT.mjs";
4
+ } from "./chunk-HVCNGDPT.mjs";
5
5
  import "./chunk-AYC2QVKI.mjs";
6
6
  import "./chunk-M7QGVZ3J.mjs";
7
7
  import {
@@ -297,6 +297,7 @@ var createStrategyIndicatorsState = ({
297
297
  // Lazy bootstrap for live mode: initialize on history before current bar and then apply current bar once.
298
298
  ensureInitializedWithCurrentBar: ensureControllerInitialized,
299
299
  snapshot: (options) => ensureControllerInitialized().snapshot(options),
300
+ latestSnapshot: () => ensureControllerInitialized().latestSnapshot(),
300
301
  latestNumber: (key) => ensureControllerInitialized().latestNumber(key)
301
302
  };
302
303
  };
@@ -691,6 +692,7 @@ var pushWhen = (items, condition, item) => {
691
692
  items.push(item);
692
693
  }
693
694
  };
695
+ var HYPERLIQUID_WHALE_GATE_MIN_NOTIONAL_USD = 5e4;
694
696
  var buildBaseContextGateFeatures = ({
695
697
  baseContext,
696
698
  direction,
@@ -708,6 +710,7 @@ var buildBaseContextGateFeatures = ({
708
710
  const volume = baseContext.participation?.volume;
709
711
  const delta = baseContext.participation?.delta;
710
712
  const tradeFlow = baseContext.participation?.tradeFlow;
713
+ const hyperliquidWhales = baseContext.participation?.hyperliquidWhales;
711
714
  const volumeStructure = baseContext.participation?.volumeStructure;
712
715
  const relative = baseContext.relative?.benchmark;
713
716
  const marketBreadth = baseContext.relative?.marketBreadth;
@@ -755,10 +758,36 @@ var buildBaseContextGateFeatures = ({
755
758
  const referenceTradeFlowBuyPressurePct = asFiniteNumberOrNull(
756
759
  primaryReferenceTradeFlow?.buyPressurePct
757
760
  );
761
+ const rawHyperliquidWhaleBuySharePct = asFiniteNumberOrNull(
762
+ hyperliquidWhales?.buySharePct
763
+ );
764
+ const rawHyperliquidWhaleNetNotionalUsd = asFiniteNumberOrNull(
765
+ hyperliquidWhales?.netNotionalUsd
766
+ );
767
+ const rawHyperliquidWhaleUniqueCount = asFiniteNumberOrNull(
768
+ hyperliquidWhales?.uniqueWhales
769
+ );
770
+ const hyperliquidWhaleCoveredCount = asFiniteNumberOrNull(
771
+ hyperliquidWhales?.coveredWhales
772
+ );
773
+ const hyperliquidWhaleExpectedCount = asFiniteNumberOrNull(
774
+ hyperliquidWhales?.expectedWhales
775
+ );
776
+ const hyperliquidWhaleCoveragePct = asFiniteNumberOrNull(
777
+ hyperliquidWhales?.coveragePct
778
+ );
779
+ const hyperliquidWhaleCoverageSufficient = typeof hyperliquidWhales?.coverageSufficient === "boolean" ? hyperliquidWhales.coverageSufficient : null;
780
+ const hyperliquidWhaleBuySharePct = hyperliquidWhaleCoverageSufficient === true ? rawHyperliquidWhaleBuySharePct : null;
781
+ const hyperliquidWhaleNetNotionalUsd = hyperliquidWhaleCoverageSufficient === true ? rawHyperliquidWhaleNetNotionalUsd : null;
782
+ const hyperliquidWhaleUniqueCount = hyperliquidWhaleCoverageSufficient === true ? rawHyperliquidWhaleUniqueCount : null;
783
+ const hyperliquidWhaleNotionalUsd = hyperliquidWhaleCoverageSufficient === true ? (asFiniteNumberOrNull(hyperliquidWhales?.buyNotionalUsd) ?? 0) + (asFiniteNumberOrNull(hyperliquidWhales?.sellNotionalUsd) ?? 0) : null;
784
+ const hyperliquidWhaleSufficientActivity = hyperliquidWhales == null || hyperliquidWhales.stale || hyperliquidWhaleCoverageSufficient !== true ? null : (hyperliquidWhaleNotionalUsd ?? 0) >= HYPERLIQUID_WHALE_GATE_MIN_NOTIONAL_USD;
758
785
  const deltaDivergenceVsPrice = asStringOrNull(delta?.deltaDivergenceVsPrice);
759
786
  const deltaBias = deltaDivergenceVsPrice === "bullish" || deltaDivergenceVsPrice === "bearish" ? deltaDivergenceVsPrice === "bullish" ? "bull" : "bear" : toPressureBias(buyPressurePct);
760
787
  const tradeFlowBias = tradeFlow?.stale ? "unknown" : toPressureBias(tradeFlowBuyPressurePct);
761
788
  const referenceTradeFlowBias = primaryReferenceTradeFlow?.stale ? "unknown" : toPressureBias(referenceTradeFlowBuyPressurePct);
789
+ const hyperliquidWhaleFlowStale = typeof hyperliquidWhales?.stale === "boolean" ? hyperliquidWhales.stale : null;
790
+ const hyperliquidWhaleFlowBias = hyperliquidWhaleSufficientActivity !== true ? "unknown" : toPressureBias(hyperliquidWhaleBuySharePct);
762
791
  const deltaAligned = toBiasAligned({ direction, bias: deltaBias });
763
792
  const tradeFlowAligned = toBiasAligned({
764
793
  direction,
@@ -768,6 +797,10 @@ var buildBaseContextGateFeatures = ({
768
797
  direction,
769
798
  bias: referenceTradeFlowBias
770
799
  });
800
+ const hyperliquidWhaleFlowAligned = toBiasAligned({
801
+ direction,
802
+ bias: hyperliquidWhaleFlowBias
803
+ });
771
804
  const benchmarkTrendAlignment = relative?.trendAlignment ?? "unknown";
772
805
  const relativeStrength1h = asFiniteNumberOrNull(relative?.relativeStrength1h);
773
806
  const relativeStrengthBucket = toRelativeStrengthBucket({
@@ -875,6 +908,11 @@ var buildBaseContextGateFeatures = ({
875
908
  pushWhen(confirmations, (volumeRel20 ?? 0) >= 1.5, "volume_expansion");
876
909
  pushWhen(confirmations, deltaAligned === true, "delta_aligned");
877
910
  pushWhen(confirmations, tradeFlowAligned === true, "trade_flow_aligned");
911
+ pushWhen(
912
+ confirmations,
913
+ hyperliquidWhaleFlowAligned === true,
914
+ "hyperliquid_whales_aligned"
915
+ );
878
916
  pushWhen(
879
917
  confirmations,
880
918
  referenceTradeFlowAligned === true,
@@ -949,6 +987,11 @@ var buildBaseContextGateFeatures = ({
949
987
  pushWhen(conflicts, btcAltRegimeAligned === false, "btc_alt_regime_against");
950
988
  pushWhen(conflicts, deltaAligned === false, "delta_against");
951
989
  pushWhen(conflicts, tradeFlowAligned === false, "trade_flow_against");
990
+ pushWhen(
991
+ conflicts,
992
+ hyperliquidWhaleFlowAligned === false,
993
+ "hyperliquid_whales_against"
994
+ );
952
995
  pushWhen(
953
996
  conflicts,
954
997
  referenceTradeFlowAligned === false,
@@ -974,6 +1017,7 @@ var buildBaseContextGateFeatures = ({
974
1017
  volumeRel20 == null ? null : volumeRel20 >= 1.5,
975
1018
  deltaAligned,
976
1019
  tradeFlowAligned,
1020
+ hyperliquidWhaleFlowAligned,
977
1021
  referenceTradeFlowAligned,
978
1022
  volumeStructureAligned
979
1023
  ]),
@@ -1079,6 +1123,17 @@ var buildBaseContextGateFeatures = ({
1079
1123
  deltaAligned,
1080
1124
  tradeFlowBuyPressurePct,
1081
1125
  tradeFlowAligned,
1126
+ hyperliquidWhaleBuySharePct,
1127
+ hyperliquidWhaleNetNotionalUsd,
1128
+ hyperliquidWhaleUniqueCount,
1129
+ hyperliquidWhaleCoveredCount,
1130
+ hyperliquidWhaleExpectedCount,
1131
+ hyperliquidWhaleCoveragePct,
1132
+ hyperliquidWhaleCoverageSufficient,
1133
+ hyperliquidWhaleNotionalUsd,
1134
+ hyperliquidWhaleSufficientActivity,
1135
+ hyperliquidWhaleFlowAligned,
1136
+ hyperliquidWhaleFlowStale,
1082
1137
  referenceTradeFlowBuyPressurePct,
1083
1138
  referenceTradeFlowAligned,
1084
1139
  volumeStructureAligned
@@ -1291,7 +1346,8 @@ var createStrategyAPI = ({
1291
1346
  indicatorsState,
1292
1347
  isConfigFromBacktest,
1293
1348
  sharedReplayKey,
1294
- getSharedReplayState
1349
+ getSharedReplayState,
1350
+ loadDecisionBaseContext
1295
1351
  }) => {
1296
1352
  const isBacktestEnv = env === "BACKTEST";
1297
1353
  const barCache = {
@@ -1299,6 +1355,7 @@ var createStrategyAPI = ({
1299
1355
  currentPosition: void 0
1300
1356
  };
1301
1357
  let currentIndicatorsContextCache;
1358
+ let decisionBaseContextCache;
1302
1359
  const getCurrentBarTimestamp = () => {
1303
1360
  const lastCandle = cachedData[cachedData.length - 1];
1304
1361
  return typeof lastCandle?.timestamp === "number" ? lastCandle.timestamp : null;
@@ -1330,6 +1387,7 @@ var createStrategyAPI = ({
1330
1387
  barCache.timestamp = currentBarTimestamp;
1331
1388
  barCache.currentPosition = void 0;
1332
1389
  currentIndicatorsContextCache = void 0;
1390
+ decisionBaseContextCache = void 0;
1333
1391
  };
1334
1392
  const getCurrentPosition = () => {
1335
1393
  if (!isBacktestEnv) {
@@ -1366,7 +1424,44 @@ var createStrategyAPI = ({
1366
1424
  };
1367
1425
  return context;
1368
1426
  };
1369
- const getBaseContext = () => getCurrentIndicatorsContext().baseContext;
1427
+ const getBaseContext = () => {
1428
+ ensureBarCache();
1429
+ const cacheKey = getCurrentIndicatorsCacheKey();
1430
+ if (currentIndicatorsContextCache?.key === cacheKey) {
1431
+ return currentIndicatorsContextCache.context.baseContext;
1432
+ }
1433
+ if (!indicatorsState?.latestSnapshot) {
1434
+ return getCurrentIndicatorsContext().baseContext;
1435
+ }
1436
+ indicatorsState?.onBar();
1437
+ const latestBaseContext = getBaseContextFromIndicators(
1438
+ indicatorsState.latestSnapshot()
1439
+ );
1440
+ return latestBaseContext ?? getCurrentIndicatorsContext().baseContext;
1441
+ };
1442
+ const getDecisionBaseContext = () => {
1443
+ ensureBarCache();
1444
+ const baseContext = getBaseContext();
1445
+ if (!loadDecisionBaseContext) {
1446
+ return Promise.resolve(baseContext);
1447
+ }
1448
+ const candle = cachedData[cachedData.length - 1];
1449
+ if (!candle) {
1450
+ return Promise.resolve(baseContext);
1451
+ }
1452
+ const cacheKey = getCurrentIndicatorsCacheKey();
1453
+ if (decisionBaseContextCache?.key === cacheKey) {
1454
+ return decisionBaseContextCache.context;
1455
+ }
1456
+ const context = loadDecisionBaseContext({
1457
+ baseContext,
1458
+ candle,
1459
+ symbol,
1460
+ interval
1461
+ });
1462
+ decisionBaseContextCache = { key: cacheKey, context };
1463
+ return context;
1464
+ };
1370
1465
  const resolveDecisionPriceContext = () => {
1371
1466
  const candle = cachedData[cachedData.length - 1];
1372
1467
  if (!candle || !isFiniteNumber(candle.timestamp) || !isFiniteNumber(candle.close)) {
@@ -1456,6 +1551,7 @@ var createStrategyAPI = ({
1456
1551
  }),
1457
1552
  getCurrentIndicatorsContext,
1458
1553
  getBaseContext,
1554
+ getDecisionBaseContext,
1459
1555
  getDecisionPriceContext,
1460
1556
  getCurrentPosition,
1461
1557
  getDirectionalTpSlPrices: (params) => getDirectionalTpSlPrices(params),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradejs/core",
3
- "version": "2.0.12",
3
+ "version": "2.0.14",
4
4
  "description": "MIT-licensed browser-safe API for TradeJS config, strategy authoring, figures, and shared helpers.",
5
5
  "keywords": [
6
6
  "tradejs",
@@ -100,7 +100,7 @@
100
100
  }
101
101
  },
102
102
  "dependencies": {
103
- "@tradejs/types": "^2.0.12",
103
+ "@tradejs/types": "^2.0.14",
104
104
  "date-fns": "^3.6.0",
105
105
  "fast-technical-indicators": "^1.1.4",
106
106
  "klinecharts": "10.0.0-alpha9",