@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.
@@ -6407,7 +6407,7 @@ var calculateRecentRangeExpansionSeries = (candles, lookback) => calculateRecent
6407
6407
  (index) => calculateRangeExpansionAt(candles, index)
6408
6408
  );
6409
6409
 
6410
- // src/utils/indicatorBaseContext.ts
6410
+ // src/utils/indicatorBaseContextRelative.ts
6411
6411
  var SESSION_WINDOWS = [
6412
6412
  { name: "asia", startMinuteUtc: 0, endMinuteUtc: 8 * 60 },
6413
6413
  { name: "europe", startMinuteUtc: 7 * 60, endMinuteUtc: 16 * 60 },
@@ -6416,28 +6416,24 @@ 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
6419
  var PSYCHOLOGICAL_LEVEL_WINDOWS = {
6421
- m15: BASE_INTERVAL_MS,
6420
+ m15: 15 * 6e4,
6422
6421
  h1: 60 * 6e4,
6423
6422
  h4: 4 * 60 * 6e4
6424
6423
  };
6425
- var isInsideSession = (minuteUtc, startMinuteUtc, endMinuteUtc) => startMinuteUtc <= endMinuteUtc ? minuteUtc >= startMinuteUtc && minuteUtc < endMinuteUtc : minuteUtc >= startMinuteUtc || minuteUtc < endMinuteUtc;
6426
6424
  var buildSessionContext = (timestamp) => {
6427
6425
  const date = new Date(timestamp);
6428
- const utcHour = date.getUTCHours();
6429
- const utcMinute = date.getUTCMinutes();
6430
- const minuteUtc = utcHour * 60 + utcMinute;
6426
+ const minuteUtc = date.getUTCHours() * 60 + date.getUTCMinutes();
6431
6427
  const dayOfWeekUtc = date.getUTCDay() || 7;
6432
6428
  const activeSessions = SESSION_WINDOWS.filter(
6433
- (session) => isInsideSession(minuteUtc, session.startMinuteUtc, session.endMinuteUtc)
6434
- ).map((session) => session.name);
6429
+ ({ startMinuteUtc, endMinuteUtc }) => startMinuteUtc <= endMinuteUtc ? minuteUtc >= startMinuteUtc && minuteUtc < endMinuteUtc : minuteUtc >= startMinuteUtc || minuteUtc < endMinuteUtc
6430
+ ).map(({ name }) => name);
6435
6431
  const sessionPhase = activeSessions.includes("us") ? "us" : activeSessions.includes("europe") ? "europe" : activeSessions.includes("asia") ? "asia" : "off_hours";
6436
6432
  const primaryWindow = SESSION_WINDOWS.find(
6437
- (session) => session.name === sessionPhase
6433
+ ({ name }) => name === sessionPhase
6438
6434
  );
6439
- const minutesFromSessionOpen = primaryWindow != null ? minuteUtc - primaryWindow.startMinuteUtc : null;
6440
- const minutesToSessionClose = primaryWindow != null ? primaryWindow.endMinuteUtc - minuteUtc : null;
6435
+ const minutesFromSessionOpen = primaryWindow ? minuteUtc - primaryWindow.startMinuteUtc : null;
6436
+ const minutesToSessionClose = primaryWindow ? primaryWindow.endMinuteUtc - minuteUtc : null;
6441
6437
  const sessionWindowPhase = primaryWindow == null || minutesFromSessionOpen == null ? "off_hours" : minutesFromSessionOpen < SESSION_WINDOW_EDGE_MINUTES ? "opening" : minutesToSessionClose != null && minutesToSessionClose <= SESSION_WINDOW_EDGE_MINUTES ? "closing" : "active";
6442
6438
  const minutesToFundingWindow = (FUNDING_WINDOW_STEP_MINUTES - minuteUtc % FUNDING_WINDOW_STEP_MINUTES) % FUNDING_WINDOW_STEP_MINUTES;
6443
6439
  return {
@@ -6453,7 +6449,7 @@ var buildSessionContext = (timestamp) => {
6453
6449
  isWeekendUtc: dayOfWeekUtc >= 6
6454
6450
  };
6455
6451
  };
6456
- var buildUnavailablePsychologicalLevelWindow = () => ({
6452
+ var unavailablePsychologicalLevelWindow = () => ({
6457
6453
  crossed: null,
6458
6454
  direction: "unknown",
6459
6455
  level: null,
@@ -6462,7 +6458,7 @@ var buildUnavailablePsychologicalLevelWindow = () => ({
6462
6458
  });
6463
6459
  var buildPsychologicalLevelWindow = (startPrice, endPrice, stepUsd) => {
6464
6460
  if (!Number.isFinite(startPrice) || !Number.isFinite(endPrice) || !Number.isFinite(stepUsd) || startPrice <= 0 || endPrice <= 0 || stepUsd <= 0) {
6465
- return buildUnavailablePsychologicalLevelWindow();
6461
+ return unavailablePsychologicalLevelWindow();
6466
6462
  }
6467
6463
  if (endPrice === startPrice) {
6468
6464
  return {
@@ -6486,21 +6482,17 @@ var buildPsychologicalLevelWindow = (startPrice, endPrice, stepUsd) => {
6486
6482
  distanceBeyondLevelBps: null
6487
6483
  };
6488
6484
  }
6489
- const levelsCrossed = Math.round(Math.abs(lastCrossedLevel - firstCrossedLevel) / stepUsd) + 1;
6490
- const distanceBeyondLevelBps = Math.abs(endPrice - lastCrossedLevel) / lastCrossedLevel * 1e4;
6491
6485
  return {
6492
6486
  crossed: true,
6493
6487
  direction: movingUp ? "up" : "down",
6494
6488
  level: lastCrossedLevel,
6495
- levelsCrossed,
6496
- distanceBeyondLevelBps
6489
+ levelsCrossed: Math.round(Math.abs(lastCrossedLevel - firstCrossedLevel) / stepUsd) + 1,
6490
+ distanceBeyondLevelBps: Math.abs(endPrice - lastCrossedLevel) / lastCrossedLevel * 1e4
6497
6491
  };
6498
6492
  };
6499
6493
  var buildPsychologicalLevelAssetContext = (candles, stepUsd) => {
6500
6494
  const endCandle = candles[candles.length - 1];
6501
- if (!endCandle) {
6502
- return null;
6503
- }
6495
+ if (!endCandle) return null;
6504
6496
  const candlesByTimestamp = new Map(
6505
6497
  candles.map((item) => [item.timestamp, item])
6506
6498
  );
@@ -6515,104 +6507,70 @@ var buildPsychologicalLevelAssetContext = (candles, stepUsd) => {
6515
6507
  startCandle.close,
6516
6508
  endCandle.close,
6517
6509
  stepUsd
6518
- ) : buildUnavailablePsychologicalLevelWindow()
6510
+ ) : unavailablePsychologicalLevelWindow()
6519
6511
  ];
6520
6512
  })
6521
6513
  );
6522
- return {
6523
- source: "aligned_15m_ohlcv",
6524
- stepUsd,
6525
- windows
6526
- };
6514
+ return { source: "aligned_15m_ohlcv", stepUsd, windows };
6527
6515
  };
6528
- var STRUCTURE_LOOKBACK = 80;
6529
- var BASE_CONTEXT_CANDLE_WINDOW = 256;
6530
- var PIVOT_LEFT_RIGHT = 2;
6531
- var ZONE_ATR_FACTOR = 0.5;
6532
- var PROFILE_BIN_COUNT = 24;
6533
- var SR_ZONE_PIVOT_PERIOD = 9;
6534
- var SR_ZONE_MIN_STRENGTH = 2;
6535
- var SR_ZONE_MAX_PIVOTS = 15;
6536
- var SR_ZONE_CHANNEL_WIDTH_PCT = 8;
6537
- var SR_ZONE_MAX_LEVELS = 6;
6538
- var VOLUME_STRUCTURE_CALC_BARS = 180;
6539
- var VOLUME_STRUCTURE_ROW_COUNT = 20;
6540
- var LIQUIDITY_ZONE_LOOKBACK = 15;
6541
- var LIQUIDITY_ZONE_MAX_AGE = 120;
6542
- var LIQUIDITY_TAIL_ATR_LENGTH = 14;
6543
- var LIQUIDITY_TAIL_ATR_MULT = 0.8;
6544
- var LIQUIDITY_TAIL_MIN_WICK_RATIO = 1.3;
6545
- var LIQUIDITY_TAIL_WICK_DOMINANCE = 1.2;
6546
- var LIQUIDITY_TAIL_MIN_GAP = 5;
6547
- var LIQUIDITY_TAIL_MAX_AGE = 120;
6548
- var TREND_FOLLOW_PIVOT_LENGTH = 10;
6549
- var TREND_FOLLOW_ATR_LENGTH = 14;
6550
- var TREND_FOLLOW_ATR_MULT = 4;
6551
- var ADAPTIVE_CHANNEL_REGRESSION_BARS = 7;
6552
- var ADAPTIVE_CHANNEL_ENVELOPE_BARS = 2;
6553
- var ADAPTIVE_CHANNEL_ATR_STRETCH = 2;
6554
- var ADAPTIVE_CHANNEL_VOLATILITY_LOOKBACK = 100;
6555
- var ADAPTIVE_CHANNEL_CALC_LOOKBACK = 220;
6556
- var STRUCTURE_ZONES_ZONE_WIDTH_ATR = 0.5;
6557
- var STRUCTURE_ZONES_ACCEPT_BARS = 2;
6558
- var calculateReturnPctFromCandles = (candles) => {
6516
+ var returnPct = (candles) => {
6559
6517
  if (candles.length < 2) return null;
6560
- const previous = candles[candles.length - 2];
6561
- const current = candles[candles.length - 1];
6562
- return percentChange(current.close, previous.close);
6563
- };
6564
- var calculateRatioReturnPct = (coinCandles, btcCandles) => {
6565
- if (coinCandles.length < 2 || btcCandles.length < 2) return null;
6566
- const currentCoin = coinCandles[coinCandles.length - 1];
6567
- const previousCoin = coinCandles[coinCandles.length - 2];
6568
- const currentBtc = btcCandles[btcCandles.length - 1];
6569
- const previousBtc = btcCandles[btcCandles.length - 2];
6570
- if (currentBtc.close <= 0 || previousBtc.close <= 0) return null;
6571
6518
  return percentChange(
6572
- currentCoin.close / currentBtc.close,
6573
- previousCoin.close / previousBtc.close
6519
+ candles[candles.length - 1].close,
6520
+ candles[candles.length - 2].close
6574
6521
  );
6575
6522
  };
6576
- var alignRecentCandlesByTimestamp = (coinCandles, btcCandles) => {
6577
- const alignedCoinCandles = [];
6578
- const alignedBtcCandles = [];
6579
- let coinIndex = Math.max(0, coinCandles.length - 80);
6580
- let btcIndex = Math.max(0, btcCandles.length - 80);
6581
- while (coinIndex < coinCandles.length && btcIndex < btcCandles.length) {
6582
- const coinTimestamp = coinCandles[coinIndex].timestamp;
6583
- const btcTimestamp = btcCandles[btcIndex].timestamp;
6584
- if (coinTimestamp === btcTimestamp) {
6585
- alignedCoinCandles.push(coinCandles[coinIndex]);
6586
- alignedBtcCandles.push(btcCandles[btcIndex]);
6587
- coinIndex += 1;
6588
- btcIndex += 1;
6589
- } else if (coinTimestamp < btcTimestamp) {
6590
- coinIndex += 1;
6523
+ var ratioReturnPct = (target, reference) => {
6524
+ if (target.length < 2 || reference.length < 2) return null;
6525
+ const targetCurrent = target[target.length - 1];
6526
+ const targetPrevious = target[target.length - 2];
6527
+ const referenceCurrent = reference[reference.length - 1];
6528
+ const referencePrevious = reference[reference.length - 2];
6529
+ if (referenceCurrent.close <= 0 || referencePrevious.close <= 0) return null;
6530
+ return percentChange(
6531
+ targetCurrent.close / referenceCurrent.close,
6532
+ targetPrevious.close / referencePrevious.close
6533
+ );
6534
+ };
6535
+ var alignRecentCandles = (target, reference) => {
6536
+ const alignedTarget = [];
6537
+ const alignedReference = [];
6538
+ let targetIndex = Math.max(0, target.length - 80);
6539
+ let referenceIndex = Math.max(0, reference.length - 80);
6540
+ while (targetIndex < target.length && referenceIndex < reference.length) {
6541
+ const targetTimestamp = target[targetIndex].timestamp;
6542
+ const referenceTimestamp = reference[referenceIndex].timestamp;
6543
+ if (targetTimestamp === referenceTimestamp) {
6544
+ alignedTarget.push(target[targetIndex]);
6545
+ alignedReference.push(reference[referenceIndex]);
6546
+ targetIndex += 1;
6547
+ referenceIndex += 1;
6548
+ } else if (targetTimestamp < referenceTimestamp) {
6549
+ targetIndex += 1;
6591
6550
  } else {
6592
- btcIndex += 1;
6551
+ referenceIndex += 1;
6593
6552
  }
6594
6553
  }
6595
- return { alignedCoinCandles, alignedBtcCandles };
6554
+ return { alignedTarget, alignedReference };
6596
6555
  };
6597
- var buildReturnPctSeries = (candles, limit) => {
6556
+ var returnSeries = (candles, limit) => {
6598
6557
  const returns = [];
6599
- const startIndex = Math.max(1, candles.length - limit);
6600
- for (let index = startIndex; index < candles.length; index += 1) {
6558
+ for (let index = Math.max(1, candles.length - limit); index < candles.length; index += 1) {
6601
6559
  const previous = candles[index - 1];
6602
6560
  const current = candles[index];
6603
6561
  if (previous.close <= 0) continue;
6604
- const ret = percentChange(current.close, previous.close);
6605
- if (ret != null && Number.isFinite(ret)) returns.push(ret);
6562
+ const value = percentChange(current.close, previous.close);
6563
+ if (value != null && Number.isFinite(value)) returns.push(value);
6606
6564
  }
6607
6565
  return returns;
6608
6566
  };
6609
- var calculateBetaToReference = (targetReturns, referenceReturns) => {
6567
+ var beta = (targetReturns, referenceReturns) => {
6610
6568
  const length = Math.min(targetReturns.length, referenceReturns.length);
6611
6569
  if (length < 2) return null;
6612
6570
  const target = targetReturns.slice(-length);
6613
6571
  const reference = referenceReturns.slice(-length);
6614
- const referenceMean = reference.reduce((sum2, value) => sum2 + value, 0) / reference.length;
6615
- const targetMean = target.reduce((sum2, value) => sum2 + value, 0) / target.length;
6572
+ const referenceMean = reference.reduce((sum2, value) => sum2 + value, 0) / length;
6573
+ const targetMean = target.reduce((sum2, value) => sum2 + value, 0) / length;
6616
6574
  let covariance = 0;
6617
6575
  let referenceVariance = 0;
6618
6576
  for (let index = 0; index < length; index += 1) {
@@ -6629,16 +6587,6 @@ var classifyRatioTrend = (ratioReturn24h, ratioReturn4h) => {
6629
6587
  if (value < -0.15) return "down";
6630
6588
  return "flat";
6631
6589
  };
6632
- var hasDistinctReferenceCandles = (coinCandles, referenceCandles) => {
6633
- const coinLast = coinCandles[coinCandles.length - 1];
6634
- const referenceLast = referenceCandles[referenceCandles.length - 1];
6635
- const coinPrev = coinCandles[coinCandles.length - 2];
6636
- const referencePrev = referenceCandles[referenceCandles.length - 2];
6637
- if (!coinLast || !referenceLast || !coinPrev || !referencePrev) {
6638
- return false;
6639
- }
6640
- return coinLast.timestamp !== referenceLast.timestamp || coinLast.close !== referenceLast.close || coinPrev.timestamp !== referencePrev.timestamp || coinPrev.close !== referencePrev.close;
6641
- };
6642
6590
  var buildTargetVsBtcContext = ({
6643
6591
  coin1h,
6644
6592
  btc1h,
@@ -6649,19 +6597,21 @@ var buildTargetVsBtcContext = ({
6649
6597
  coinCandles,
6650
6598
  btcCandles
6651
6599
  }) => {
6652
- const ratioReturn1h = calculateRatioReturnPct(coin1h, btc1h);
6653
- const ratioReturn4h = calculateRatioReturnPct(coin4h, btc4h);
6654
- const ratioReturn24h = calculateRatioReturnPct(coin1d, btc1d);
6655
- const coinReturn1h = calculateReturnPctFromCandles(coin1h);
6656
- const coinReturn4h = calculateReturnPctFromCandles(coin4h);
6657
- const coinReturn24h = calculateReturnPctFromCandles(coin1d);
6658
- const btcReturn1h = calculateReturnPctFromCandles(btc1h);
6659
- const btcReturn4h = calculateReturnPctFromCandles(btc4h);
6660
- const btcReturn24h = calculateReturnPctFromCandles(btc1d);
6661
- const { alignedCoinCandles, alignedBtcCandles } = alignRecentCandlesByTimestamp(coinCandles, btcCandles);
6662
- const coinReturns20 = buildReturnPctSeries(alignedCoinCandles, 21).slice(-20);
6663
- const btcReturns20 = buildReturnPctSeries(alignedBtcCandles, 21).slice(-20);
6664
- const correlationToBtc20 = coinReturns20.length === btcReturns20.length && coinReturns20.length >= 2 ? calculatePearsonCorrelation(coinReturns20, btcReturns20) : null;
6600
+ const ratioReturn1h = ratioReturnPct(coin1h, btc1h);
6601
+ const ratioReturn4h = ratioReturnPct(coin4h, btc4h);
6602
+ const ratioReturn24h = ratioReturnPct(coin1d, btc1d);
6603
+ const coinReturn1h = returnPct(coin1h);
6604
+ const coinReturn4h = returnPct(coin4h);
6605
+ const coinReturn24h = returnPct(coin1d);
6606
+ const btcReturn1h = returnPct(btc1h);
6607
+ const btcReturn4h = returnPct(btc4h);
6608
+ const btcReturn24h = returnPct(btc1d);
6609
+ const { alignedTarget, alignedReference } = alignRecentCandles(
6610
+ coinCandles,
6611
+ btcCandles
6612
+ );
6613
+ const coinReturns20 = returnSeries(alignedTarget, 21).slice(-20);
6614
+ const btcReturns20 = returnSeries(alignedReference, 21).slice(-20);
6665
6615
  return {
6666
6616
  source: "aligned_ohlcv",
6667
6617
  ratioReturn1h,
@@ -6670,11 +6620,21 @@ var buildTargetVsBtcContext = ({
6670
6620
  alphaVsBtc1h: coinReturn1h == null || btcReturn1h == null ? null : coinReturn1h - btcReturn1h,
6671
6621
  alphaVsBtc4h: coinReturn4h == null || btcReturn4h == null ? null : coinReturn4h - btcReturn4h,
6672
6622
  alphaVsBtc24h: coinReturn24h == null || btcReturn24h == null ? null : coinReturn24h - btcReturn24h,
6673
- betaToBtc20: calculateBetaToReference(coinReturns20, btcReturns20),
6674
- correlationToBtc20,
6623
+ betaToBtc20: beta(coinReturns20, btcReturns20),
6624
+ correlationToBtc20: coinReturns20.length === btcReturns20.length && coinReturns20.length >= 2 ? calculatePearsonCorrelation(coinReturns20, btcReturns20) : null,
6675
6625
  ratioTrend: classifyRatioTrend(ratioReturn24h, ratioReturn4h)
6676
6626
  };
6677
6627
  };
6628
+ var hasDistinctReferenceCandles = (target, reference) => {
6629
+ const targetLast = target[target.length - 1];
6630
+ const referenceLast = reference[reference.length - 1];
6631
+ const targetPrevious = target[target.length - 2];
6632
+ const referencePrevious = reference[reference.length - 2];
6633
+ if (!targetLast || !referenceLast || !targetPrevious || !referencePrevious) {
6634
+ return false;
6635
+ }
6636
+ return targetLast.timestamp !== referenceLast.timestamp || targetLast.close !== referenceLast.close || targetPrevious.timestamp !== referencePrevious.timestamp || targetPrevious.close !== referencePrevious.close;
6637
+ };
6678
6638
  var buildTargetVsEthContext = ({
6679
6639
  coin1h,
6680
6640
  eth1h,
@@ -6685,9 +6645,7 @@ var buildTargetVsEthContext = ({
6685
6645
  coinCandles,
6686
6646
  ethCandles
6687
6647
  }) => {
6688
- if (!hasDistinctReferenceCandles(coinCandles, ethCandles)) {
6689
- return null;
6690
- }
6648
+ if (!hasDistinctReferenceCandles(coinCandles, ethCandles)) return null;
6691
6649
  const context = buildTargetVsBtcContext({
6692
6650
  coin1h,
6693
6651
  btc1h: eth1h,
@@ -6711,6 +6669,38 @@ var buildTargetVsEthContext = ({
6711
6669
  ratioTrend: context.ratioTrend
6712
6670
  };
6713
6671
  };
6672
+
6673
+ // src/utils/indicatorBaseContext.ts
6674
+ var STRUCTURE_LOOKBACK = 80;
6675
+ var BASE_CONTEXT_CANDLE_WINDOW = 256;
6676
+ var PIVOT_LEFT_RIGHT = 2;
6677
+ var ZONE_ATR_FACTOR = 0.5;
6678
+ var PROFILE_BIN_COUNT = 24;
6679
+ var SR_ZONE_PIVOT_PERIOD = 9;
6680
+ var SR_ZONE_MIN_STRENGTH = 2;
6681
+ var SR_ZONE_MAX_PIVOTS = 15;
6682
+ var SR_ZONE_CHANNEL_WIDTH_PCT = 8;
6683
+ var SR_ZONE_MAX_LEVELS = 6;
6684
+ var VOLUME_STRUCTURE_CALC_BARS = 180;
6685
+ var VOLUME_STRUCTURE_ROW_COUNT = 20;
6686
+ var LIQUIDITY_ZONE_LOOKBACK = 15;
6687
+ var LIQUIDITY_ZONE_MAX_AGE = 120;
6688
+ var LIQUIDITY_TAIL_ATR_LENGTH = 14;
6689
+ var LIQUIDITY_TAIL_ATR_MULT = 0.8;
6690
+ var LIQUIDITY_TAIL_MIN_WICK_RATIO = 1.3;
6691
+ var LIQUIDITY_TAIL_WICK_DOMINANCE = 1.2;
6692
+ var LIQUIDITY_TAIL_MIN_GAP = 5;
6693
+ var LIQUIDITY_TAIL_MAX_AGE = 120;
6694
+ var TREND_FOLLOW_PIVOT_LENGTH = 10;
6695
+ var TREND_FOLLOW_ATR_LENGTH = 14;
6696
+ var TREND_FOLLOW_ATR_MULT = 4;
6697
+ var ADAPTIVE_CHANNEL_REGRESSION_BARS = 7;
6698
+ var ADAPTIVE_CHANNEL_ENVELOPE_BARS = 2;
6699
+ var ADAPTIVE_CHANNEL_ATR_STRETCH = 2;
6700
+ var ADAPTIVE_CHANNEL_VOLATILITY_LOOKBACK = 100;
6701
+ var ADAPTIVE_CHANNEL_CALC_LOOKBACK = 220;
6702
+ var STRUCTURE_ZONES_ZONE_WIDTH_ATR = 0.5;
6703
+ var STRUCTURE_ZONES_ACCEPT_BARS = 2;
6714
6704
  var BASE_CONTEXT_MA_LAYER_PERIODS = [
6715
6705
  [5, 12],
6716
6706
  [9, 13],
@@ -10701,13 +10691,12 @@ var buildIndicatorSeriesByTimeframes = (candles, periods, sourcePrefix = "") =>
10701
10691
 
10702
10692
  // src/utils/timestamp.ts
10703
10693
  var import_date_fns = require("date-fns");
10704
- var import_date_fns2 = require("date-fns");
10705
10694
  var RUNTIME_STORAGE_DAY_OFFSET_MS = 6 * 60 * 60 * 1e3;
10706
10695
  var getTimestamp = (days = 0) => {
10707
10696
  if (days > 0) {
10708
- return (0, import_date_fns2.getUnixTime)((0, import_date_fns2.subDays)(/* @__PURE__ */ new Date(), days)) * 1e3;
10697
+ return (0, import_date_fns.getUnixTime)((0, import_date_fns.subDays)(/* @__PURE__ */ new Date(), days)) * 1e3;
10709
10698
  }
10710
- return (0, import_date_fns2.getUnixTime)(/* @__PURE__ */ new Date()) * 1e3;
10699
+ return (0, import_date_fns.getUnixTime)(/* @__PURE__ */ new Date()) * 1e3;
10711
10700
  };
10712
10701
 
10713
10702
  // src/utils/strategyHelpers/indicators.ts
@@ -11234,11 +11223,14 @@ var createStrategyStateControllerFactory = ({
11234
11223
  };
11235
11224
 
11236
11225
  // src/utils/uuid.ts
11237
- var import_node_crypto = require("crypto");
11238
- var uuid = (len = 12) => {
11239
- const uuid2 = (0, import_node_crypto.randomUUID)();
11240
- return uuid2.slice(-len);
11226
+ var randomUuid = () => {
11227
+ if (!globalThis.crypto?.randomUUID) {
11228
+ throw new Error("crypto.randomUUID is not available in this runtime");
11229
+ }
11230
+ return globalThis.crypto.randomUUID();
11241
11231
  };
11232
+ var createIdGenerator = (generateUuid = randomUuid) => (length = 12) => generateUuid().slice(-length);
11233
+ var uuid = createIdGenerator();
11242
11234
 
11243
11235
  // src/utils/strategyHelpers/signalBuilders.ts
11244
11236
  var COMPACT_MTF_CANDLE_LIMIT = 3;
@@ -11922,13 +11914,14 @@ var buildEntrySignalDecision = ({
11922
11914
  additionalIndicators,
11923
11915
  signalId,
11924
11916
  orderPlan,
11925
- runtime
11917
+ runtime,
11918
+ generateId = uuid
11926
11919
  }) => ({
11927
11920
  kind: "entry",
11928
11921
  code,
11929
11922
  entryContext,
11930
11923
  signal: buildStrategySignal({
11931
- signalId: signalId ?? uuid(),
11924
+ signalId: signalId ?? generateId(),
11932
11925
  strategy: entryContext.strategy,
11933
11926
  symbol: entryContext.symbol,
11934
11927
  interval: entryContext.interval,
@@ -11943,7 +11936,7 @@ var buildEntrySignalDecision = ({
11943
11936
  orderPlan,
11944
11937
  runtime
11945
11938
  });
11946
- var isFiniteNumber3 = (value) => typeof value === "number" && Number.isFinite(value);
11939
+ var isFiniteNumber2 = (value) => typeof value === "number" && Number.isFinite(value);
11947
11940
  var toDefaultEntryCode = (strategy, direction) => `${strategy.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toUpperCase()}_${direction}_ENTRY`;
11948
11941
  var toDefaultExitCode = (strategy, direction) => `${strategy.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toUpperCase()}_${direction}_EXIT`;
11949
11942
  var toDefaultProtectCode = (strategy, direction) => `${strategy.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toUpperCase()}_${direction}_PROTECT`;
@@ -11954,7 +11947,7 @@ var resolveTakeProfitPrice = ({
11954
11947
  if (!Array.isArray(takeProfits) || takeProfits.length === 0) {
11955
11948
  throw new Error("strategyApi.entry requires at least one takeProfit");
11956
11949
  }
11957
- const prices = takeProfits.map((tp) => tp?.price).filter((price) => isFiniteNumber3(price));
11950
+ const prices = takeProfits.map((tp) => tp?.price).filter((price) => isFiniteNumber2(price));
11958
11951
  if (prices.length === 0) {
11959
11952
  throw new Error("strategyApi.entry requires finite takeProfit prices");
11960
11953
  }
@@ -11971,6 +11964,7 @@ var createStrategyAPI = ({
11971
11964
  isConfigFromBacktest,
11972
11965
  sharedReplayKey,
11973
11966
  getSharedReplayState,
11967
+ generateId,
11974
11968
  loadDecisionBaseContext
11975
11969
  }) => {
11976
11970
  const isBacktestEnv = env === "BACKTEST";
@@ -12088,7 +12082,7 @@ var createStrategyAPI = ({
12088
12082
  };
12089
12083
  const resolveDecisionPriceContext = () => {
12090
12084
  const candle = cachedData[cachedData.length - 1];
12091
- if (!candle || !isFiniteNumber3(candle.timestamp) || !isFiniteNumber3(candle.close)) {
12085
+ if (!candle || !isFiniteNumber2(candle.timestamp) || !isFiniteNumber2(candle.close)) {
12092
12086
  throw new Error(
12093
12087
  "strategyApi.getDecisionPriceContext requires a current closed candle"
12094
12088
  );
@@ -12120,7 +12114,7 @@ var createStrategyAPI = ({
12120
12114
  direction,
12121
12115
  takeProfits: orderPlan.takeProfits
12122
12116
  });
12123
- if (!isFiniteNumber3(stopLossPrice)) {
12117
+ if (!isFiniteNumber2(stopLossPrice)) {
12124
12118
  throw new Error(
12125
12119
  "strategyApi.entry requires finite orderPlan.stopLossPrice"
12126
12120
  );
@@ -12153,7 +12147,8 @@ var createStrategyAPI = ({
12153
12147
  additionalIndicators,
12154
12148
  signalId,
12155
12149
  orderPlan,
12156
- runtime
12150
+ runtime,
12151
+ generateId
12157
12152
  });
12158
12153
  },
12159
12154
  exit: async ({ code, direction }) => {
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  createIndicators,
3
3
  getRequiredControllerSeedWindow
4
- } from "./chunk-NN7Z3GIK.mjs";
4
+ } from "./chunk-Q3OFPRVV.mjs";
5
5
  import "./chunk-AYC2QVKI.mjs";
6
6
  import "./chunk-M7QGVZ3J.mjs";
7
7
  import {
8
8
  uuid
9
- } from "./chunk-AJK4NS7Y.mjs";
9
+ } from "./chunk-U3GDILUZ.mjs";
10
10
  import {
11
11
  getTimestamp
12
- } from "./chunk-BOETNABM.mjs";
12
+ } from "./chunk-S4KHOAXM.mjs";
13
13
  import {
14
14
  FEE_PERCENT
15
15
  } from "./chunk-MKCQSB4H.mjs";
@@ -1219,13 +1219,14 @@ var buildEntrySignalDecision = ({
1219
1219
  additionalIndicators,
1220
1220
  signalId,
1221
1221
  orderPlan,
1222
- runtime
1222
+ runtime,
1223
+ generateId = uuid
1223
1224
  }) => ({
1224
1225
  kind: "entry",
1225
1226
  code,
1226
1227
  entryContext,
1227
1228
  signal: buildStrategySignal({
1228
- signalId: signalId ?? uuid(),
1229
+ signalId: signalId ?? generateId(),
1229
1230
  strategy: entryContext.strategy,
1230
1231
  symbol: entryContext.symbol,
1231
1232
  interval: entryContext.interval,
@@ -1268,6 +1269,7 @@ var createStrategyAPI = ({
1268
1269
  isConfigFromBacktest,
1269
1270
  sharedReplayKey,
1270
1271
  getSharedReplayState,
1272
+ generateId,
1271
1273
  loadDecisionBaseContext
1272
1274
  }) => {
1273
1275
  const isBacktestEnv = env === "BACKTEST";
@@ -1450,7 +1452,8 @@ var createStrategyAPI = ({
1450
1452
  additionalIndicators,
1451
1453
  signalId,
1452
1454
  orderPlan,
1453
- runtime
1455
+ runtime,
1456
+ generateId
1454
1457
  });
1455
1458
  },
1456
1459
  exit: async ({ code, direction }) => {
package/dist/time.js CHANGED
@@ -33,7 +33,6 @@ module.exports = __toCommonJS(time_exports);
33
33
 
34
34
  // src/utils/timestamp.ts
35
35
  var import_date_fns = require("date-fns");
36
- var import_date_fns2 = require("date-fns");
37
36
 
38
37
  // src/constants/index.ts
39
38
  var BACKTEST_EXECUTION_DELAY_MS = 5 * 6e4;
@@ -59,9 +58,9 @@ var RUNTIME_STORAGE_DAY_OFFSET_MS = 6 * 60 * 60 * 1e3;
59
58
  var toMs = (ts) => ts < 1e12 ? ts * 1e3 : ts;
60
59
  var getTimestamp = (days = 0) => {
61
60
  if (days > 0) {
62
- return (0, import_date_fns2.getUnixTime)((0, import_date_fns2.subDays)(/* @__PURE__ */ new Date(), days)) * 1e3;
61
+ return (0, import_date_fns.getUnixTime)((0, import_date_fns.subDays)(/* @__PURE__ */ new Date(), days)) * 1e3;
63
62
  }
64
- return (0, import_date_fns2.getUnixTime)(/* @__PURE__ */ new Date()) * 1e3;
63
+ return (0, import_date_fns.getUnixTime)(/* @__PURE__ */ new Date()) * 1e3;
65
64
  };
66
65
  var getItemTimestamp = (item) => item.timestamp;
67
66
  var getDataTimestamp = (data) => {
package/dist/time.mjs CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  getRuntimeStorageDayKeys,
8
8
  getTimestamp,
9
9
  toMs
10
- } from "./chunk-BOETNABM.mjs";
10
+ } from "./chunk-S4KHOAXM.mjs";
11
11
  import "./chunk-MKCQSB4H.mjs";
12
12
  export {
13
13
  formatUnix,
@@ -0,0 +1,3 @@
1
+ type IdGenerator = (length?: number) => string;
2
+
3
+ export type { IdGenerator as I };
@@ -0,0 +1,3 @@
1
+ type IdGenerator = (length?: number) => string;
2
+
3
+ export type { IdGenerator as I };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradejs/core",
3
- "version": "2.0.17",
3
+ "version": "2.0.19",
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.17",
103
+ "@tradejs/types": "^2.0.19",
104
104
  "date-fns": "^3.6.0",
105
105
  "fast-technical-indicators": "^1.1.4",
106
106
  "klinecharts": "10.0.0-alpha9",
@@ -1,10 +0,0 @@
1
- // src/utils/uuid.ts
2
- import { randomUUID } from "crypto";
3
- var uuid = (len = 12) => {
4
- const uuid2 = randomUUID();
5
- return uuid2.slice(-len);
6
- };
7
-
8
- export {
9
- uuid
10
- };