@tradejs/core 2.0.17 → 2.0.19

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.
package/dist/backtest.js CHANGED
@@ -860,14 +860,13 @@ var getFormatted = (stat, key) => {
860
860
 
861
861
  // src/utils/timestamp.ts
862
862
  var import_date_fns2 = require("date-fns");
863
- var import_date_fns3 = require("date-fns");
864
863
  var TIMELINE_STEP = 864e5;
865
864
  var RUNTIME_STORAGE_DAY_OFFSET_MS = 6 * 60 * 60 * 1e3;
866
865
  var getTimestamp = (days = 0) => {
867
866
  if (days > 0) {
868
- return (0, import_date_fns3.getUnixTime)((0, import_date_fns3.subDays)(/* @__PURE__ */ new Date(), days)) * 1e3;
867
+ return (0, import_date_fns2.getUnixTime)((0, import_date_fns2.subDays)(/* @__PURE__ */ new Date(), days)) * 1e3;
869
868
  }
870
- return (0, import_date_fns3.getUnixTime)(/* @__PURE__ */ new Date()) * 1e3;
869
+ return (0, import_date_fns2.getUnixTime)(/* @__PURE__ */ new Date()) * 1e3;
871
870
  };
872
871
  var getTimeline = (start = getTimestamp(BACKTEST_DEFAULT_DAYS), end = getTimestamp(), step = TIMELINE_STEP) => {
873
872
  const res = new Array();
package/dist/backtest.mjs CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  import {
10
10
  compactOrderLog,
11
11
  getTimeline
12
- } from "./chunk-BOETNABM.mjs";
12
+ } from "./chunk-S4KHOAXM.mjs";
13
13
  import {
14
14
  TestThresholdsConfig
15
15
  } from "./chunk-MKCQSB4H.mjs";
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-M7QGVZ3J.mjs";
7
7
  import {
8
8
  toMs
9
- } from "./chunk-BOETNABM.mjs";
9
+ } from "./chunk-S4KHOAXM.mjs";
10
10
  import {
11
11
  CORRELATION_WINDOW,
12
12
  ML_BASE_CANDLES_WINDOW,
@@ -6860,7 +6860,7 @@ var calculateRecentRangeExpansionSeries = (candles, lookback) => calculateRecent
6860
6860
  (index) => calculateRangeExpansionAt(candles, index)
6861
6861
  );
6862
6862
 
6863
- // src/utils/indicatorBaseContext.ts
6863
+ // src/utils/indicatorBaseContextRelative.ts
6864
6864
  var SESSION_WINDOWS = [
6865
6865
  { name: "asia", startMinuteUtc: 0, endMinuteUtc: 8 * 60 },
6866
6866
  { name: "europe", startMinuteUtc: 7 * 60, endMinuteUtc: 16 * 60 },
@@ -6869,28 +6869,24 @@ 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
6872
  var PSYCHOLOGICAL_LEVEL_WINDOWS = {
6874
- m15: BASE_INTERVAL_MS,
6873
+ m15: 15 * 6e4,
6875
6874
  h1: 60 * 6e4,
6876
6875
  h4: 4 * 60 * 6e4
6877
6876
  };
6878
- var isInsideSession = (minuteUtc, startMinuteUtc, endMinuteUtc) => startMinuteUtc <= endMinuteUtc ? minuteUtc >= startMinuteUtc && minuteUtc < endMinuteUtc : minuteUtc >= startMinuteUtc || minuteUtc < endMinuteUtc;
6879
6877
  var buildSessionContext = (timestamp) => {
6880
6878
  const date = new Date(timestamp);
6881
- const utcHour = date.getUTCHours();
6882
- const utcMinute = date.getUTCMinutes();
6883
- const minuteUtc = utcHour * 60 + utcMinute;
6879
+ const minuteUtc = date.getUTCHours() * 60 + date.getUTCMinutes();
6884
6880
  const dayOfWeekUtc = date.getUTCDay() || 7;
6885
6881
  const activeSessions = SESSION_WINDOWS.filter(
6886
- (session) => isInsideSession(minuteUtc, session.startMinuteUtc, session.endMinuteUtc)
6887
- ).map((session) => session.name);
6882
+ ({ startMinuteUtc, endMinuteUtc }) => startMinuteUtc <= endMinuteUtc ? minuteUtc >= startMinuteUtc && minuteUtc < endMinuteUtc : minuteUtc >= startMinuteUtc || minuteUtc < endMinuteUtc
6883
+ ).map(({ name }) => name);
6888
6884
  const sessionPhase = activeSessions.includes("us") ? "us" : activeSessions.includes("europe") ? "europe" : activeSessions.includes("asia") ? "asia" : "off_hours";
6889
6885
  const primaryWindow = SESSION_WINDOWS.find(
6890
- (session) => session.name === sessionPhase
6886
+ ({ name }) => name === sessionPhase
6891
6887
  );
6892
- const minutesFromSessionOpen = primaryWindow != null ? minuteUtc - primaryWindow.startMinuteUtc : null;
6893
- const minutesToSessionClose = primaryWindow != null ? primaryWindow.endMinuteUtc - minuteUtc : null;
6888
+ const minutesFromSessionOpen = primaryWindow ? minuteUtc - primaryWindow.startMinuteUtc : null;
6889
+ const minutesToSessionClose = primaryWindow ? primaryWindow.endMinuteUtc - minuteUtc : null;
6894
6890
  const sessionWindowPhase = primaryWindow == null || minutesFromSessionOpen == null ? "off_hours" : minutesFromSessionOpen < SESSION_WINDOW_EDGE_MINUTES ? "opening" : minutesToSessionClose != null && minutesToSessionClose <= SESSION_WINDOW_EDGE_MINUTES ? "closing" : "active";
6895
6891
  const minutesToFundingWindow = (FUNDING_WINDOW_STEP_MINUTES - minuteUtc % FUNDING_WINDOW_STEP_MINUTES) % FUNDING_WINDOW_STEP_MINUTES;
6896
6892
  return {
@@ -6906,7 +6902,7 @@ var buildSessionContext = (timestamp) => {
6906
6902
  isWeekendUtc: dayOfWeekUtc >= 6
6907
6903
  };
6908
6904
  };
6909
- var buildUnavailablePsychologicalLevelWindow = () => ({
6905
+ var unavailablePsychologicalLevelWindow = () => ({
6910
6906
  crossed: null,
6911
6907
  direction: "unknown",
6912
6908
  level: null,
@@ -6915,7 +6911,7 @@ var buildUnavailablePsychologicalLevelWindow = () => ({
6915
6911
  });
6916
6912
  var buildPsychologicalLevelWindow = (startPrice, endPrice, stepUsd) => {
6917
6913
  if (!Number.isFinite(startPrice) || !Number.isFinite(endPrice) || !Number.isFinite(stepUsd) || startPrice <= 0 || endPrice <= 0 || stepUsd <= 0) {
6918
- return buildUnavailablePsychologicalLevelWindow();
6914
+ return unavailablePsychologicalLevelWindow();
6919
6915
  }
6920
6916
  if (endPrice === startPrice) {
6921
6917
  return {
@@ -6939,21 +6935,17 @@ var buildPsychologicalLevelWindow = (startPrice, endPrice, stepUsd) => {
6939
6935
  distanceBeyondLevelBps: null
6940
6936
  };
6941
6937
  }
6942
- const levelsCrossed = Math.round(Math.abs(lastCrossedLevel - firstCrossedLevel) / stepUsd) + 1;
6943
- const distanceBeyondLevelBps = Math.abs(endPrice - lastCrossedLevel) / lastCrossedLevel * 1e4;
6944
6938
  return {
6945
6939
  crossed: true,
6946
6940
  direction: movingUp ? "up" : "down",
6947
6941
  level: lastCrossedLevel,
6948
- levelsCrossed,
6949
- distanceBeyondLevelBps
6942
+ levelsCrossed: Math.round(Math.abs(lastCrossedLevel - firstCrossedLevel) / stepUsd) + 1,
6943
+ distanceBeyondLevelBps: Math.abs(endPrice - lastCrossedLevel) / lastCrossedLevel * 1e4
6950
6944
  };
6951
6945
  };
6952
6946
  var buildPsychologicalLevelAssetContext = (candles, stepUsd) => {
6953
6947
  const endCandle = candles[candles.length - 1];
6954
- if (!endCandle) {
6955
- return null;
6956
- }
6948
+ if (!endCandle) return null;
6957
6949
  const candlesByTimestamp = new Map(
6958
6950
  candles.map((item) => [item.timestamp, item])
6959
6951
  );
@@ -6968,104 +6960,70 @@ var buildPsychologicalLevelAssetContext = (candles, stepUsd) => {
6968
6960
  startCandle.close,
6969
6961
  endCandle.close,
6970
6962
  stepUsd
6971
- ) : buildUnavailablePsychologicalLevelWindow()
6963
+ ) : unavailablePsychologicalLevelWindow()
6972
6964
  ];
6973
6965
  })
6974
6966
  );
6975
- return {
6976
- source: "aligned_15m_ohlcv",
6977
- stepUsd,
6978
- windows
6979
- };
6967
+ return { source: "aligned_15m_ohlcv", stepUsd, windows };
6980
6968
  };
6981
- var STRUCTURE_LOOKBACK = 80;
6982
- var BASE_CONTEXT_CANDLE_WINDOW = 256;
6983
- var PIVOT_LEFT_RIGHT = 2;
6984
- var ZONE_ATR_FACTOR = 0.5;
6985
- var PROFILE_BIN_COUNT = 24;
6986
- var SR_ZONE_PIVOT_PERIOD = 9;
6987
- var SR_ZONE_MIN_STRENGTH = 2;
6988
- var SR_ZONE_MAX_PIVOTS = 15;
6989
- var SR_ZONE_CHANNEL_WIDTH_PCT = 8;
6990
- var SR_ZONE_MAX_LEVELS = 6;
6991
- var VOLUME_STRUCTURE_CALC_BARS = 180;
6992
- var VOLUME_STRUCTURE_ROW_COUNT = 20;
6993
- var LIQUIDITY_ZONE_LOOKBACK = 15;
6994
- var LIQUIDITY_ZONE_MAX_AGE = 120;
6995
- var LIQUIDITY_TAIL_ATR_LENGTH = 14;
6996
- var LIQUIDITY_TAIL_ATR_MULT = 0.8;
6997
- var LIQUIDITY_TAIL_MIN_WICK_RATIO = 1.3;
6998
- var LIQUIDITY_TAIL_WICK_DOMINANCE = 1.2;
6999
- var LIQUIDITY_TAIL_MIN_GAP = 5;
7000
- var LIQUIDITY_TAIL_MAX_AGE = 120;
7001
- var TREND_FOLLOW_PIVOT_LENGTH = 10;
7002
- var TREND_FOLLOW_ATR_LENGTH = 14;
7003
- var TREND_FOLLOW_ATR_MULT = 4;
7004
- var ADAPTIVE_CHANNEL_REGRESSION_BARS = 7;
7005
- var ADAPTIVE_CHANNEL_ENVELOPE_BARS = 2;
7006
- var ADAPTIVE_CHANNEL_ATR_STRETCH = 2;
7007
- var ADAPTIVE_CHANNEL_VOLATILITY_LOOKBACK = 100;
7008
- var ADAPTIVE_CHANNEL_CALC_LOOKBACK = 220;
7009
- var STRUCTURE_ZONES_ZONE_WIDTH_ATR = 0.5;
7010
- var STRUCTURE_ZONES_ACCEPT_BARS = 2;
7011
- var calculateReturnPctFromCandles = (candles) => {
6969
+ var returnPct = (candles) => {
7012
6970
  if (candles.length < 2) return null;
7013
- const previous = candles[candles.length - 2];
7014
- const current = candles[candles.length - 1];
7015
- return percentChange(current.close, previous.close);
7016
- };
7017
- var calculateRatioReturnPct = (coinCandles, btcCandles) => {
7018
- if (coinCandles.length < 2 || btcCandles.length < 2) return null;
7019
- const currentCoin = coinCandles[coinCandles.length - 1];
7020
- const previousCoin = coinCandles[coinCandles.length - 2];
7021
- const currentBtc = btcCandles[btcCandles.length - 1];
7022
- const previousBtc = btcCandles[btcCandles.length - 2];
7023
- if (currentBtc.close <= 0 || previousBtc.close <= 0) return null;
7024
6971
  return percentChange(
7025
- currentCoin.close / currentBtc.close,
7026
- previousCoin.close / previousBtc.close
6972
+ candles[candles.length - 1].close,
6973
+ candles[candles.length - 2].close
7027
6974
  );
7028
6975
  };
7029
- var alignRecentCandlesByTimestamp = (coinCandles, btcCandles) => {
7030
- const alignedCoinCandles = [];
7031
- const alignedBtcCandles = [];
7032
- let coinIndex = Math.max(0, coinCandles.length - 80);
7033
- let btcIndex = Math.max(0, btcCandles.length - 80);
7034
- while (coinIndex < coinCandles.length && btcIndex < btcCandles.length) {
7035
- const coinTimestamp = coinCandles[coinIndex].timestamp;
7036
- const btcTimestamp = btcCandles[btcIndex].timestamp;
7037
- if (coinTimestamp === btcTimestamp) {
7038
- alignedCoinCandles.push(coinCandles[coinIndex]);
7039
- alignedBtcCandles.push(btcCandles[btcIndex]);
7040
- coinIndex += 1;
7041
- btcIndex += 1;
7042
- } else if (coinTimestamp < btcTimestamp) {
7043
- coinIndex += 1;
6976
+ var ratioReturnPct = (target, reference) => {
6977
+ if (target.length < 2 || reference.length < 2) return null;
6978
+ const targetCurrent = target[target.length - 1];
6979
+ const targetPrevious = target[target.length - 2];
6980
+ const referenceCurrent = reference[reference.length - 1];
6981
+ const referencePrevious = reference[reference.length - 2];
6982
+ if (referenceCurrent.close <= 0 || referencePrevious.close <= 0) return null;
6983
+ return percentChange(
6984
+ targetCurrent.close / referenceCurrent.close,
6985
+ targetPrevious.close / referencePrevious.close
6986
+ );
6987
+ };
6988
+ var alignRecentCandles = (target, reference) => {
6989
+ const alignedTarget = [];
6990
+ const alignedReference = [];
6991
+ let targetIndex = Math.max(0, target.length - 80);
6992
+ let referenceIndex = Math.max(0, reference.length - 80);
6993
+ while (targetIndex < target.length && referenceIndex < reference.length) {
6994
+ const targetTimestamp = target[targetIndex].timestamp;
6995
+ const referenceTimestamp = reference[referenceIndex].timestamp;
6996
+ if (targetTimestamp === referenceTimestamp) {
6997
+ alignedTarget.push(target[targetIndex]);
6998
+ alignedReference.push(reference[referenceIndex]);
6999
+ targetIndex += 1;
7000
+ referenceIndex += 1;
7001
+ } else if (targetTimestamp < referenceTimestamp) {
7002
+ targetIndex += 1;
7044
7003
  } else {
7045
- btcIndex += 1;
7004
+ referenceIndex += 1;
7046
7005
  }
7047
7006
  }
7048
- return { alignedCoinCandles, alignedBtcCandles };
7007
+ return { alignedTarget, alignedReference };
7049
7008
  };
7050
- var buildReturnPctSeries = (candles, limit) => {
7009
+ var returnSeries = (candles, limit) => {
7051
7010
  const returns = [];
7052
- const startIndex = Math.max(1, candles.length - limit);
7053
- for (let index = startIndex; index < candles.length; index += 1) {
7011
+ for (let index = Math.max(1, candles.length - limit); index < candles.length; index += 1) {
7054
7012
  const previous = candles[index - 1];
7055
7013
  const current = candles[index];
7056
7014
  if (previous.close <= 0) continue;
7057
- const ret = percentChange(current.close, previous.close);
7058
- if (ret != null && Number.isFinite(ret)) returns.push(ret);
7015
+ const value = percentChange(current.close, previous.close);
7016
+ if (value != null && Number.isFinite(value)) returns.push(value);
7059
7017
  }
7060
7018
  return returns;
7061
7019
  };
7062
- var calculateBetaToReference = (targetReturns, referenceReturns) => {
7020
+ var beta = (targetReturns, referenceReturns) => {
7063
7021
  const length = Math.min(targetReturns.length, referenceReturns.length);
7064
7022
  if (length < 2) return null;
7065
7023
  const target = targetReturns.slice(-length);
7066
7024
  const reference = referenceReturns.slice(-length);
7067
- const referenceMean = reference.reduce((sum2, value) => sum2 + value, 0) / reference.length;
7068
- const targetMean = target.reduce((sum2, value) => sum2 + value, 0) / target.length;
7025
+ const referenceMean = reference.reduce((sum2, value) => sum2 + value, 0) / length;
7026
+ const targetMean = target.reduce((sum2, value) => sum2 + value, 0) / length;
7069
7027
  let covariance = 0;
7070
7028
  let referenceVariance = 0;
7071
7029
  for (let index = 0; index < length; index += 1) {
@@ -7082,16 +7040,6 @@ var classifyRatioTrend = (ratioReturn24h, ratioReturn4h) => {
7082
7040
  if (value < -0.15) return "down";
7083
7041
  return "flat";
7084
7042
  };
7085
- var hasDistinctReferenceCandles = (coinCandles, referenceCandles) => {
7086
- const coinLast = coinCandles[coinCandles.length - 1];
7087
- const referenceLast = referenceCandles[referenceCandles.length - 1];
7088
- const coinPrev = coinCandles[coinCandles.length - 2];
7089
- const referencePrev = referenceCandles[referenceCandles.length - 2];
7090
- if (!coinLast || !referenceLast || !coinPrev || !referencePrev) {
7091
- return false;
7092
- }
7093
- return coinLast.timestamp !== referenceLast.timestamp || coinLast.close !== referenceLast.close || coinPrev.timestamp !== referencePrev.timestamp || coinPrev.close !== referencePrev.close;
7094
- };
7095
7043
  var buildTargetVsBtcContext = ({
7096
7044
  coin1h,
7097
7045
  btc1h,
@@ -7102,19 +7050,21 @@ var buildTargetVsBtcContext = ({
7102
7050
  coinCandles,
7103
7051
  btcCandles
7104
7052
  }) => {
7105
- const ratioReturn1h = calculateRatioReturnPct(coin1h, btc1h);
7106
- const ratioReturn4h = calculateRatioReturnPct(coin4h, btc4h);
7107
- const ratioReturn24h = calculateRatioReturnPct(coin1d, btc1d);
7108
- const coinReturn1h = calculateReturnPctFromCandles(coin1h);
7109
- const coinReturn4h = calculateReturnPctFromCandles(coin4h);
7110
- const coinReturn24h = calculateReturnPctFromCandles(coin1d);
7111
- const btcReturn1h = calculateReturnPctFromCandles(btc1h);
7112
- const btcReturn4h = calculateReturnPctFromCandles(btc4h);
7113
- const btcReturn24h = calculateReturnPctFromCandles(btc1d);
7114
- const { alignedCoinCandles, alignedBtcCandles } = alignRecentCandlesByTimestamp(coinCandles, btcCandles);
7115
- const coinReturns20 = buildReturnPctSeries(alignedCoinCandles, 21).slice(-20);
7116
- const btcReturns20 = buildReturnPctSeries(alignedBtcCandles, 21).slice(-20);
7117
- const correlationToBtc20 = coinReturns20.length === btcReturns20.length && coinReturns20.length >= 2 ? calculatePearsonCorrelation(coinReturns20, btcReturns20) : null;
7053
+ const ratioReturn1h = ratioReturnPct(coin1h, btc1h);
7054
+ const ratioReturn4h = ratioReturnPct(coin4h, btc4h);
7055
+ const ratioReturn24h = ratioReturnPct(coin1d, btc1d);
7056
+ const coinReturn1h = returnPct(coin1h);
7057
+ const coinReturn4h = returnPct(coin4h);
7058
+ const coinReturn24h = returnPct(coin1d);
7059
+ const btcReturn1h = returnPct(btc1h);
7060
+ const btcReturn4h = returnPct(btc4h);
7061
+ const btcReturn24h = returnPct(btc1d);
7062
+ const { alignedTarget, alignedReference } = alignRecentCandles(
7063
+ coinCandles,
7064
+ btcCandles
7065
+ );
7066
+ const coinReturns20 = returnSeries(alignedTarget, 21).slice(-20);
7067
+ const btcReturns20 = returnSeries(alignedReference, 21).slice(-20);
7118
7068
  return {
7119
7069
  source: "aligned_ohlcv",
7120
7070
  ratioReturn1h,
@@ -7123,11 +7073,21 @@ var buildTargetVsBtcContext = ({
7123
7073
  alphaVsBtc1h: coinReturn1h == null || btcReturn1h == null ? null : coinReturn1h - btcReturn1h,
7124
7074
  alphaVsBtc4h: coinReturn4h == null || btcReturn4h == null ? null : coinReturn4h - btcReturn4h,
7125
7075
  alphaVsBtc24h: coinReturn24h == null || btcReturn24h == null ? null : coinReturn24h - btcReturn24h,
7126
- betaToBtc20: calculateBetaToReference(coinReturns20, btcReturns20),
7127
- correlationToBtc20,
7076
+ betaToBtc20: beta(coinReturns20, btcReturns20),
7077
+ correlationToBtc20: coinReturns20.length === btcReturns20.length && coinReturns20.length >= 2 ? calculatePearsonCorrelation(coinReturns20, btcReturns20) : null,
7128
7078
  ratioTrend: classifyRatioTrend(ratioReturn24h, ratioReturn4h)
7129
7079
  };
7130
7080
  };
7081
+ var hasDistinctReferenceCandles = (target, reference) => {
7082
+ const targetLast = target[target.length - 1];
7083
+ const referenceLast = reference[reference.length - 1];
7084
+ const targetPrevious = target[target.length - 2];
7085
+ const referencePrevious = reference[reference.length - 2];
7086
+ if (!targetLast || !referenceLast || !targetPrevious || !referencePrevious) {
7087
+ return false;
7088
+ }
7089
+ return targetLast.timestamp !== referenceLast.timestamp || targetLast.close !== referenceLast.close || targetPrevious.timestamp !== referencePrevious.timestamp || targetPrevious.close !== referencePrevious.close;
7090
+ };
7131
7091
  var buildTargetVsEthContext = ({
7132
7092
  coin1h,
7133
7093
  eth1h,
@@ -7138,9 +7098,7 @@ var buildTargetVsEthContext = ({
7138
7098
  coinCandles,
7139
7099
  ethCandles
7140
7100
  }) => {
7141
- if (!hasDistinctReferenceCandles(coinCandles, ethCandles)) {
7142
- return null;
7143
- }
7101
+ if (!hasDistinctReferenceCandles(coinCandles, ethCandles)) return null;
7144
7102
  const context = buildTargetVsBtcContext({
7145
7103
  coin1h,
7146
7104
  btc1h: eth1h,
@@ -7164,6 +7122,38 @@ var buildTargetVsEthContext = ({
7164
7122
  ratioTrend: context.ratioTrend
7165
7123
  };
7166
7124
  };
7125
+
7126
+ // src/utils/indicatorBaseContext.ts
7127
+ var STRUCTURE_LOOKBACK = 80;
7128
+ var BASE_CONTEXT_CANDLE_WINDOW = 256;
7129
+ var PIVOT_LEFT_RIGHT = 2;
7130
+ var ZONE_ATR_FACTOR = 0.5;
7131
+ var PROFILE_BIN_COUNT = 24;
7132
+ var SR_ZONE_PIVOT_PERIOD = 9;
7133
+ var SR_ZONE_MIN_STRENGTH = 2;
7134
+ var SR_ZONE_MAX_PIVOTS = 15;
7135
+ var SR_ZONE_CHANNEL_WIDTH_PCT = 8;
7136
+ var SR_ZONE_MAX_LEVELS = 6;
7137
+ var VOLUME_STRUCTURE_CALC_BARS = 180;
7138
+ var VOLUME_STRUCTURE_ROW_COUNT = 20;
7139
+ var LIQUIDITY_ZONE_LOOKBACK = 15;
7140
+ var LIQUIDITY_ZONE_MAX_AGE = 120;
7141
+ var LIQUIDITY_TAIL_ATR_LENGTH = 14;
7142
+ var LIQUIDITY_TAIL_ATR_MULT = 0.8;
7143
+ var LIQUIDITY_TAIL_MIN_WICK_RATIO = 1.3;
7144
+ var LIQUIDITY_TAIL_WICK_DOMINANCE = 1.2;
7145
+ var LIQUIDITY_TAIL_MIN_GAP = 5;
7146
+ var LIQUIDITY_TAIL_MAX_AGE = 120;
7147
+ var TREND_FOLLOW_PIVOT_LENGTH = 10;
7148
+ var TREND_FOLLOW_ATR_LENGTH = 14;
7149
+ var TREND_FOLLOW_ATR_MULT = 4;
7150
+ var ADAPTIVE_CHANNEL_REGRESSION_BARS = 7;
7151
+ var ADAPTIVE_CHANNEL_ENVELOPE_BARS = 2;
7152
+ var ADAPTIVE_CHANNEL_ATR_STRETCH = 2;
7153
+ var ADAPTIVE_CHANNEL_VOLATILITY_LOOKBACK = 100;
7154
+ var ADAPTIVE_CHANNEL_CALC_LOOKBACK = 220;
7155
+ var STRUCTURE_ZONES_ZONE_WIDTH_ATR = 0.5;
7156
+ var STRUCTURE_ZONES_ACCEPT_BARS = 2;
7167
7157
  var BASE_CONTEXT_MA_LAYER_PERIODS = [
7168
7158
  [5, 12],
7169
7159
  [9, 13],
@@ -4,8 +4,7 @@ import {
4
4
  } from "./chunk-MKCQSB4H.mjs";
5
5
 
6
6
  // src/utils/timestamp.ts
7
- import { format } from "date-fns";
8
- import { getUnixTime, subDays } from "date-fns";
7
+ import { format, getUnixTime, subDays } from "date-fns";
9
8
  var TIMELINE_STEP = 864e5;
10
9
  var DAY_MS = 864e5;
11
10
  var RUNTIME_STORAGE_DAY_OFFSET_MS = 6 * 60 * 60 * 1e3;
@@ -0,0 +1,13 @@
1
+ // src/utils/uuid.ts
2
+ var randomUuid = () => {
3
+ if (!globalThis.crypto?.randomUUID) {
4
+ throw new Error("crypto.randomUUID is not available in this runtime");
5
+ }
6
+ return globalThis.crypto.randomUUID();
7
+ };
8
+ var createIdGenerator = (generateUuid = randomUuid) => (length = 12) => generateUuid().slice(-length);
9
+ var uuid = createIdGenerator();
10
+
11
+ export {
12
+ uuid
13
+ };
package/dist/grid.d.mts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { StrategyConfigGrid, Interval, TestSuite, StrategyConfig } from '@tradejs/types';
2
+ import { I as IdGenerator } from './uuid-DMoErO_1.mjs';
2
3
 
3
4
  type GenericConfig = StrategyConfig;
4
5
  declare const generateParamGrid: <T extends StrategyConfig>(paramOptions: StrategyConfigGrid) => T[];
5
- declare const generateName: (prefix: string) => string;
6
+ declare const generateName: (prefix: string, generateId?: IdGenerator) => string;
6
7
  declare const mergeConfigs: (configs: GenericConfig[]) => Record<string, unknown[]>;
7
- declare const createTestSuite: (userName: string, tickers: string[], strategyName: string, backtestConfig: StrategyConfigGrid, connectorName: string, interval?: Interval) => TestSuite;
8
+ declare const createTestSuite: (userName: string, tickers: string[], strategyName: string, backtestConfig: StrategyConfigGrid, connectorName: string, interval?: Interval, generateId?: IdGenerator) => TestSuite;
8
9
 
9
10
  export { createTestSuite, generateName, generateParamGrid, mergeConfigs };
package/dist/grid.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { StrategyConfigGrid, Interval, TestSuite, StrategyConfig } from '@tradejs/types';
2
+ import { I as IdGenerator } from './uuid-DMoErO_1.js';
2
3
 
3
4
  type GenericConfig = StrategyConfig;
4
5
  declare const generateParamGrid: <T extends StrategyConfig>(paramOptions: StrategyConfigGrid) => T[];
5
- declare const generateName: (prefix: string) => string;
6
+ declare const generateName: (prefix: string, generateId?: IdGenerator) => string;
6
7
  declare const mergeConfigs: (configs: GenericConfig[]) => Record<string, unknown[]>;
7
- declare const createTestSuite: (userName: string, tickers: string[], strategyName: string, backtestConfig: StrategyConfigGrid, connectorName: string, interval?: Interval) => TestSuite;
8
+ declare const createTestSuite: (userName: string, tickers: string[], strategyName: string, backtestConfig: StrategyConfigGrid, connectorName: string, interval?: Interval, generateId?: IdGenerator) => TestSuite;
8
9
 
9
10
  export { createTestSuite, generateName, generateParamGrid, mergeConfigs };
package/dist/grid.js CHANGED
@@ -60,13 +60,12 @@ var DERIVATIVES_CONTEXT_REFERENCE_SYMBOLS = [
60
60
 
61
61
  // src/utils/timestamp.ts
62
62
  var import_date_fns = require("date-fns");
63
- var import_date_fns2 = require("date-fns");
64
63
  var RUNTIME_STORAGE_DAY_OFFSET_MS = 6 * 60 * 60 * 1e3;
65
64
  var getTimestamp = (days = 0) => {
66
65
  if (days > 0) {
67
- return (0, import_date_fns2.getUnixTime)((0, import_date_fns2.subDays)(/* @__PURE__ */ new Date(), days)) * 1e3;
66
+ return (0, import_date_fns.getUnixTime)((0, import_date_fns.subDays)(/* @__PURE__ */ new Date(), days)) * 1e3;
68
67
  }
69
- return (0, import_date_fns2.getUnixTime)(/* @__PURE__ */ new Date()) * 1e3;
68
+ return (0, import_date_fns.getUnixTime)(/* @__PURE__ */ new Date()) * 1e3;
70
69
  };
71
70
 
72
71
  // src/utils/toJson.ts
@@ -75,11 +74,14 @@ var toJson = (data, stringify = false) => {
75
74
  };
76
75
 
77
76
  // src/utils/uuid.ts
78
- var import_node_crypto = require("crypto");
79
- var uuid = (len = 12) => {
80
- const uuid2 = (0, import_node_crypto.randomUUID)();
81
- return uuid2.slice(-len);
77
+ var randomUuid = () => {
78
+ if (!globalThis.crypto?.randomUUID) {
79
+ throw new Error("crypto.randomUUID is not available in this runtime");
80
+ }
81
+ return globalThis.crypto.randomUUID();
82
82
  };
83
+ var createIdGenerator = (generateUuid = randomUuid) => (length = 12) => generateUuid().slice(-length);
84
+ var uuid = createIdGenerator();
83
85
 
84
86
  // src/utils/grid.ts
85
87
  var generateParamGrid = (paramOptions) => {
@@ -102,7 +104,7 @@ var generateParamGrid = (paramOptions) => {
102
104
  helper();
103
105
  return combinations;
104
106
  };
105
- var generateName = (prefix) => `${prefix}_${uuid(6)}`;
107
+ var generateName = (prefix, generateId = uuid) => `${prefix}_${generateId(6)}`;
106
108
  var toBase36Hash = (value) => {
107
109
  let hash = 0;
108
110
  for (let index = 0; index < value.length; index += 1) {
@@ -134,14 +136,14 @@ var mergeConfigs = (configs) => {
134
136
  }
135
137
  return result;
136
138
  };
137
- var createTestSuite = (userName, tickers, strategyName, backtestConfig, connectorName, interval = "15") => {
139
+ var createTestSuite = (userName, tickers, strategyName, backtestConfig, connectorName, interval = "15", generateId = uuid) => {
138
140
  const start = getTimestamp(BACKTEST_DEFAULT_DAYS);
139
141
  const end = getTimestamp();
140
- const testSuiteId = uuid(6);
142
+ const testSuiteId = generateId(6);
141
143
  const paramGrid = generateParamGrid(backtestConfig);
142
144
  return tickers.flatMap(
143
145
  (symbol) => paramGrid.map((params) => {
144
- const testId = uuid(6);
146
+ const testId = generateId(6);
145
147
  const configId = buildConfigTestId(params);
146
148
  return {
147
149
  userName,
package/dist/grid.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  uuid
3
- } from "./chunk-AJK4NS7Y.mjs";
3
+ } from "./chunk-U3GDILUZ.mjs";
4
4
  import {
5
5
  getTimestamp
6
- } from "./chunk-BOETNABM.mjs";
6
+ } from "./chunk-S4KHOAXM.mjs";
7
7
  import {
8
8
  BACKTEST_DEFAULT_DAYS
9
9
  } from "./chunk-MKCQSB4H.mjs";
@@ -33,7 +33,7 @@ var generateParamGrid = (paramOptions) => {
33
33
  helper();
34
34
  return combinations;
35
35
  };
36
- var generateName = (prefix) => `${prefix}_${uuid(6)}`;
36
+ var generateName = (prefix, generateId = uuid) => `${prefix}_${generateId(6)}`;
37
37
  var toBase36Hash = (value) => {
38
38
  let hash = 0;
39
39
  for (let index = 0; index < value.length; index += 1) {
@@ -65,14 +65,14 @@ var mergeConfigs = (configs) => {
65
65
  }
66
66
  return result;
67
67
  };
68
- var createTestSuite = (userName, tickers, strategyName, backtestConfig, connectorName, interval = "15") => {
68
+ var createTestSuite = (userName, tickers, strategyName, backtestConfig, connectorName, interval = "15", generateId = uuid) => {
69
69
  const start = getTimestamp(BACKTEST_DEFAULT_DAYS);
70
70
  const end = getTimestamp();
71
- const testSuiteId = uuid(6);
71
+ const testSuiteId = generateId(6);
72
72
  const paramGrid = generateParamGrid(backtestConfig);
73
73
  return tickers.flatMap(
74
74
  (symbol) => paramGrid.map((params) => {
75
- const testId = uuid(6);
75
+ const testId = generateId(6);
76
76
  const configId = buildConfigTestId(params);
77
77
  return {
78
78
  userName,