@tradejs/core 2.0.15 → 2.0.17
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/{chunk-HVCNGDPT.mjs → chunk-NN7Z3GIK.mjs} +437 -391
- package/dist/{indicators-Da_i06-8.d.mts → indicators-C4AaiFrs.d.mts} +1 -0
- package/dist/{indicators-Da_i06-8.d.ts → indicators-C4AaiFrs.d.ts} +1 -0
- package/dist/indicators.d.mts +1 -1
- package/dist/indicators.d.ts +1 -1
- package/dist/indicators.js +437 -391
- package/dist/indicators.mjs +1 -1
- package/dist/strategies.d.mts +1 -1
- package/dist/strategies.d.ts +1 -1
- package/dist/strategies.js +481 -504
- package/dist/strategies.mjs +47 -126
- package/package.json +2 -2
|
@@ -8435,19 +8435,9 @@ var buildBaseContextSnapshot = ({
|
|
|
8435
8435
|
const btcCloseSeries = fullBtcCloseSeries.slice(-BASE_CONTEXT_CANDLE_WINDOW);
|
|
8436
8436
|
const atr2 = toNullable(baseResult.atr);
|
|
8437
8437
|
const bbWidthPct = baseResult.bbUpper != null && baseResult.bbLower != null && baseResult.bbMiddle != null && baseResult.bbMiddle !== 0 ? (baseResult.bbUpper - baseResult.bbLower) / baseResult.bbMiddle * 100 : null;
|
|
8438
|
-
const atrPctSeries = materializeNumericHistory(
|
|
8439
|
-
indicatorHistory.atrPct ?? createNumericHistoryBuffer()
|
|
8440
|
-
);
|
|
8441
|
-
const macdHistogramSeries = materializeNumericHistory(
|
|
8442
|
-
indicatorHistory.macdHistogram ?? createNumericHistoryBuffer()
|
|
8443
|
-
);
|
|
8444
|
-
const spreadSeries = materializeNumericHistory(
|
|
8445
|
-
indicatorHistory.spread ?? createNumericHistoryBuffer()
|
|
8446
|
-
);
|
|
8447
8438
|
const recent20 = candlesHistory.slice(-20);
|
|
8448
8439
|
const prior20 = candlesHistory.slice(-21, -1);
|
|
8449
8440
|
const structureWindow = candlesHistory.slice(-STRUCTURE_LOOKBACK);
|
|
8450
|
-
const session = buildSessionContext(candle.timestamp);
|
|
8451
8441
|
const recent20High = recent20.length > 0 ? Math.max(...recent20.map((item) => item.high)) : null;
|
|
8452
8442
|
const recent20Low = recent20.length > 0 ? Math.min(...recent20.map((item) => item.low)) : null;
|
|
8453
8443
|
const avgVolume20 = recent20.length > 0 ? recent20.reduce((sum2, item) => sum2 + item.volume, 0) / recent20.length : null;
|
|
@@ -8476,38 +8466,7 @@ var buildBaseContextSnapshot = ({
|
|
|
8476
8466
|
);
|
|
8477
8467
|
const maStackScore = baseResult.maFast == null || baseResult.maMedium == null || baseResult.maSlow == null ? null : Math.sign(baseResult.maFast - baseResult.maMedium) + Math.sign(baseResult.maMedium - baseResult.maSlow);
|
|
8478
8468
|
const trendBias = maStackScore == null ? "neutral" : maStackScore > 0 ? "bull" : maStackScore < 0 ? "bear" : "neutral";
|
|
8479
|
-
const persistenceWindow = closeSeries.slice(-10);
|
|
8480
|
-
const directionalMoves = persistenceWindow.slice(1).map((value, index) => value - persistenceWindow[index]);
|
|
8481
|
-
const persistence = directionalMoves.length === 0 ? null : directionalMoves.filter(
|
|
8482
|
-
(delta) => trendBias === "bull" ? delta > 0 : trendBias === "bear" ? delta < 0 : delta === 0
|
|
8483
|
-
).length / directionalMoves.length;
|
|
8484
|
-
const atrPctZScore = calculateZScore(
|
|
8485
|
-
atrPctSeries,
|
|
8486
|
-
toNullable(baseResult.atrPct)
|
|
8487
|
-
);
|
|
8488
|
-
const atrSlope = calculateLineSlope(atrPctSeries, 5);
|
|
8489
|
-
const compressionScore = safeDivide(
|
|
8490
|
-
toNullable(baseResult.atrPct),
|
|
8491
|
-
getLastFiniteValue(atrPctSeries.slice(0, -1))
|
|
8492
|
-
);
|
|
8493
|
-
const expansionScore = compressionScore == null || compressionScore === 0 ? null : 1 / compressionScore;
|
|
8494
|
-
const bbWidthPctSeries = calculateRecentBbWidthPctSeries(closeSeries, 100);
|
|
8495
|
-
const rawAtrPctSeries = calculateRecentAtrPctSeries(candlesHistory, 100);
|
|
8496
|
-
const rawAtrPct = safeDivide(atr2, candle.close);
|
|
8497
|
-
const realizedVolatility = calculateRealizedVolatility(closeSeries);
|
|
8498
|
-
const realizedVolatilitySeries = calculateRecentRealizedVolatilitySeries(
|
|
8499
|
-
closeSeries,
|
|
8500
|
-
100
|
|
8501
|
-
);
|
|
8502
|
-
const rangeExpansionSeries = calculateRecentRangeExpansionSeries(
|
|
8503
|
-
candlesHistory,
|
|
8504
|
-
20
|
|
8505
|
-
);
|
|
8506
|
-
const rangeExpansion = rangeExpansionSeries[rangeExpansionSeries.length - 1] ?? null;
|
|
8507
|
-
const volatilityState = compressionScore == null ? "unknown" : compressionScore <= 0.9 ? "compressed" : compressionScore >= 1.1 ? "expanded" : "normal";
|
|
8508
8469
|
const highLowRange = candle.high - candle.low;
|
|
8509
|
-
const bodyStrength = highLowRange > 0 ? Math.abs(candle.close - candle.open) / highLowRange : null;
|
|
8510
|
-
const closeLocationInRange = highLowRange > 0 ? (candle.close - candle.low) / highLowRange : null;
|
|
8511
8470
|
const breakoutState = baseResult.highLevel == null || baseResult.lowLevel == null ? "unknown" : candle.close > baseResult.highLevel ? prevCandle != null && prevCandle.close <= baseResult.highLevel ? "above_high_level" : "failed_high_breakout" : candle.close < baseResult.lowLevel ? prevCandle != null && prevCandle.close >= baseResult.lowLevel ? "below_low_level" : "failed_low_breakout" : "inside_range";
|
|
8512
8471
|
const touchTolerance = atr2 != null && Number.isFinite(atr2) && atr2 > 0 ? atr2 * 0.15 : null;
|
|
8513
8472
|
const highLevel = baseResult.highLevel;
|
|
@@ -8540,253 +8499,347 @@ var buildBaseContextSnapshot = ({
|
|
|
8540
8499
|
distanceScore * 0.45 + wickSupport * 0.25 + closeAcceptance * 0.3
|
|
8541
8500
|
);
|
|
8542
8501
|
})();
|
|
8543
|
-
const recentFalseBreakoutDensity = highLevel == null || lowLevel == null || recent20.length < 2 ? null : recent20.reduce((count, item, index) => {
|
|
8544
|
-
if (index === 0) {
|
|
8545
|
-
return count;
|
|
8546
|
-
}
|
|
8547
|
-
const prevItem = recent20[index - 1];
|
|
8548
|
-
if (!prevItem) {
|
|
8549
|
-
return count;
|
|
8550
|
-
}
|
|
8551
|
-
if (prevItem.close > highLevel && item.close <= highLevel) {
|
|
8552
|
-
return count + 1;
|
|
8553
|
-
}
|
|
8554
|
-
if (prevItem.close < lowLevel && item.close >= lowLevel) {
|
|
8555
|
-
return count + 1;
|
|
8556
|
-
}
|
|
8557
|
-
return count;
|
|
8558
|
-
}, 0) / (recent20.length - 1);
|
|
8559
8502
|
const rejectionWickScore = trendBias === "bull" ? lowerWick : trendBias === "bear" ? upperWick : Math.max(upperWick ?? 0, lowerWick ?? 0);
|
|
8560
|
-
const adxContext = buildAdxContext(adxValue) ?? calculateAdxContext(candlesHistory);
|
|
8561
|
-
const rsiContext = buildRsiContext(rsiValue) ?? calculateRsiContext(closeSeries);
|
|
8562
|
-
const benchmarkMaFast = averageLastN(btcCloseSeries, indicatorPeriods.maFast);
|
|
8563
|
-
const benchmarkMaSlow = averageLastN(btcCloseSeries, indicatorPeriods.maSlow);
|
|
8564
|
-
const coin1h = coinResampledCandles.h1;
|
|
8565
|
-
const btc1h = btcResampledCandles.h1;
|
|
8566
|
-
const btc4h = btcResampledCandles.h4;
|
|
8567
|
-
const btc1d = btcResampledCandles.d1;
|
|
8568
|
-
const eth1h = ethResampledCandles?.h1 ?? [];
|
|
8569
|
-
const eth4h = ethResampledCandles?.h4 ?? [];
|
|
8570
|
-
const eth1d = ethResampledCandles?.d1 ?? [];
|
|
8571
8503
|
const coin4h = coinResampledCandles.h4;
|
|
8572
8504
|
const coin1d = coinResampledCandles.d1;
|
|
8573
|
-
const
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
|
|
8580
|
-
|
|
8581
|
-
|
|
8582
|
-
|
|
8583
|
-
|
|
8584
|
-
|
|
8585
|
-
|
|
8586
|
-
|
|
8587
|
-
|
|
8588
|
-
|
|
8589
|
-
|
|
8590
|
-
|
|
8591
|
-
|
|
8592
|
-
|
|
8593
|
-
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
|
|
8613
|
-
|
|
8614
|
-
|
|
8615
|
-
|
|
8616
|
-
|
|
8617
|
-
|
|
8618
|
-
|
|
8619
|
-
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
|
|
8624
|
-
|
|
8625
|
-
|
|
8626
|
-
|
|
8627
|
-
|
|
8628
|
-
|
|
8629
|
-
|
|
8630
|
-
)
|
|
8631
|
-
|
|
8632
|
-
|
|
8633
|
-
|
|
8634
|
-
|
|
8635
|
-
|
|
8636
|
-
|
|
8637
|
-
|
|
8638
|
-
|
|
8639
|
-
|
|
8640
|
-
|
|
8641
|
-
|
|
8642
|
-
|
|
8643
|
-
|
|
8644
|
-
|
|
8645
|
-
|
|
8646
|
-
|
|
8647
|
-
|
|
8648
|
-
|
|
8649
|
-
|
|
8650
|
-
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
|
|
8654
|
-
|
|
8655
|
-
|
|
8656
|
-
|
|
8657
|
-
|
|
8658
|
-
|
|
8659
|
-
|
|
8660
|
-
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
totalStructureVolume
|
|
8664
|
-
);
|
|
8665
|
-
const supportVolumeShare = safeDivide(
|
|
8666
|
-
nearestSupport?.volume ?? null,
|
|
8667
|
-
totalStructureVolume
|
|
8668
|
-
);
|
|
8669
|
-
const sweepState = nearestResistance == null && nearestSupport == null ? "unknown" : nearestResistance != null && candle.high > nearestResistance.upper && candle.close < nearestResistance.level ? "swept_high" : nearestSupport != null && candle.low < nearestSupport.lower && candle.close > nearestSupport.level ? "swept_low" : nearestResistance != null && candle.close > nearestResistance.upper ? "broken_high" : nearestSupport != null && candle.close < nearestSupport.lower ? "broken_low" : "none";
|
|
8670
|
-
const liquiditySide = sweepState === "swept_high" || sweepState === "broken_high" ? "high" : sweepState === "swept_low" || sweepState === "broken_low" ? "low" : null;
|
|
8671
|
-
const referenceZoneSide = liquiditySide === "high" ? "resistance" : liquiditySide === "low" ? "support" : null;
|
|
8672
|
-
const prior20High = prior20.length > 0 ? Math.max(...prior20.map((item) => item.high)) : null;
|
|
8673
|
-
const prior20Low = prior20.length > 0 ? Math.min(...prior20.map((item) => item.low)) : null;
|
|
8674
|
-
const sweepHigh20 = prior20High == null ? null : candle.high > prior20High && candle.close < prior20High;
|
|
8675
|
-
const sweepLow20 = prior20Low == null ? null : candle.low < prior20Low && candle.close > prior20Low;
|
|
8676
|
-
const closeBackInsideRange = sweepHigh20 == null && sweepLow20 == null ? null : Boolean(sweepHigh20 || sweepLow20);
|
|
8677
|
-
const stopRunDirection = sweepHigh20 ? "up" : sweepLow20 ? "down" : null;
|
|
8678
|
-
const sweepWickPct = stopRunDirection === "up" ? upperWick : stopRunDirection === "down" ? lowerWick : null;
|
|
8679
|
-
const recent3 = candlesHistory.slice(-3);
|
|
8680
|
-
const recent5 = candlesHistory.slice(-5);
|
|
8681
|
-
const closesAboveHighLevel3 = highLevel == null ? null : recent3.filter((item) => item.close > highLevel).length;
|
|
8682
|
-
const closesBelowLowLevel3 = lowLevel == null ? null : recent3.filter((item) => item.close < lowLevel).length;
|
|
8683
|
-
const failedAcceptanceBars = highLevel == null || lowLevel == null ? null : recent5.filter(
|
|
8684
|
-
(item) => item.high > highLevel && item.close <= highLevel || item.low < lowLevel && item.close >= lowLevel
|
|
8685
|
-
).length;
|
|
8686
|
-
const acceptanceScore = closesAboveHighLevel3 == null || closesBelowLowLevel3 == null ? null : (closesAboveHighLevel3 - closesBelowLowLevel3) / Math.max(1, recent3.length);
|
|
8687
|
-
const breakoutBodyAtr = safeDivide(Math.abs(candle.close - candle.open), atr2);
|
|
8688
|
-
const priceVolumeProfile = buildPriceVolumeProfileContext(
|
|
8689
|
-
structureWindow,
|
|
8690
|
-
candle.close,
|
|
8691
|
-
atr2
|
|
8692
|
-
);
|
|
8693
|
-
const volumeStructure = buildVolumeStructureContext(
|
|
8694
|
-
candlesHistory,
|
|
8695
|
-
candle.close,
|
|
8696
|
-
atr2
|
|
8697
|
-
);
|
|
8698
|
-
const srZones = buildSrZonesContext(
|
|
8699
|
-
structureWindow,
|
|
8700
|
-
candle.close,
|
|
8701
|
-
prevCandle?.close ?? null,
|
|
8702
|
-
atr2
|
|
8703
|
-
);
|
|
8704
|
-
const liquidityZones = buildLiquidityZonesContext(
|
|
8705
|
-
candlesHistory.slice(-180),
|
|
8706
|
-
candle.close,
|
|
8707
|
-
prevCandle?.close ?? null,
|
|
8708
|
-
atr2
|
|
8709
|
-
);
|
|
8710
|
-
const liquidityTails = buildLiquidityTailsContext(
|
|
8711
|
-
candlesHistory.slice(-180),
|
|
8712
|
-
candle.close,
|
|
8713
|
-
atr2
|
|
8714
|
-
);
|
|
8715
|
-
const trendFollow = buildTrendFollowContext(
|
|
8716
|
-
candlesHistory.slice(-220),
|
|
8717
|
-
candle.close,
|
|
8718
|
-
atr2
|
|
8719
|
-
);
|
|
8720
|
-
const structureZonesContext = buildStructureZonesContext(
|
|
8721
|
-
swingContext,
|
|
8722
|
-
pivotContext,
|
|
8723
|
-
candle.close,
|
|
8724
|
-
atr2,
|
|
8725
|
-
structureWindow
|
|
8726
|
-
);
|
|
8727
|
-
const hl2Series = precomputedMaLayers === void 0 ? candlesHistory.map((item) => (item.high + item.low) / 2) : [];
|
|
8728
|
-
const maLayers = buildMaLayersContext(hl2Series, precomputedMaLayers);
|
|
8729
|
-
const contextMa = buildContextMaContext(
|
|
8730
|
-
closeSeries,
|
|
8731
|
-
candle.close,
|
|
8732
|
-
atr2,
|
|
8733
|
-
precomputedContextMa
|
|
8734
|
-
);
|
|
8735
|
-
const adaptiveChannel = buildAdaptiveChannelContext(
|
|
8736
|
-
candlesHistory,
|
|
8737
|
-
candle.close,
|
|
8738
|
-
atr2,
|
|
8739
|
-
precomputedAdaptiveChannel
|
|
8740
|
-
);
|
|
8741
|
-
const deltaContext = buildDeltaContext(structureWindow);
|
|
8742
|
-
const snapshot = {
|
|
8743
|
-
candle,
|
|
8744
|
-
prevCandle,
|
|
8745
|
-
raw: {
|
|
8746
|
-
trend: {
|
|
8747
|
-
maFast: baseResult.maFast,
|
|
8748
|
-
maMedium: baseResult.maMedium,
|
|
8749
|
-
maSlow: baseResult.maSlow
|
|
8505
|
+
const buildRelativeSnapshot = () => {
|
|
8506
|
+
const spreadSeries = materializeNumericHistory(
|
|
8507
|
+
indicatorHistory.spread ?? createNumericHistoryBuffer()
|
|
8508
|
+
);
|
|
8509
|
+
const benchmarkMaFast = averageLastN(
|
|
8510
|
+
btcCloseSeries,
|
|
8511
|
+
indicatorPeriods.maFast
|
|
8512
|
+
);
|
|
8513
|
+
const benchmarkMaSlow = averageLastN(
|
|
8514
|
+
btcCloseSeries,
|
|
8515
|
+
indicatorPeriods.maSlow
|
|
8516
|
+
);
|
|
8517
|
+
const coin1h = coinResampledCandles.h1;
|
|
8518
|
+
const btc1h = btcResampledCandles.h1;
|
|
8519
|
+
const btc4h = btcResampledCandles.h4;
|
|
8520
|
+
const btc1d = btcResampledCandles.d1;
|
|
8521
|
+
const eth1h = ethResampledCandles?.h1 ?? [];
|
|
8522
|
+
const eth4h = ethResampledCandles?.h4 ?? [];
|
|
8523
|
+
const eth1d = ethResampledCandles?.d1 ?? [];
|
|
8524
|
+
const targetVsBtc = buildTargetVsBtcContext({
|
|
8525
|
+
coin1h,
|
|
8526
|
+
btc1h,
|
|
8527
|
+
coin4h,
|
|
8528
|
+
btc4h,
|
|
8529
|
+
coin1d,
|
|
8530
|
+
btc1d,
|
|
8531
|
+
coinCandles: candlesHistory,
|
|
8532
|
+
btcCandles: btcCandlesHistory
|
|
8533
|
+
});
|
|
8534
|
+
const targetVsEth = ethCandlesHistory.length >= 2 ? buildTargetVsEthContext({
|
|
8535
|
+
coin1h,
|
|
8536
|
+
eth1h,
|
|
8537
|
+
coin4h,
|
|
8538
|
+
eth4h,
|
|
8539
|
+
coin1d,
|
|
8540
|
+
eth1d,
|
|
8541
|
+
coinCandles: candlesHistory,
|
|
8542
|
+
ethCandles: ethCandlesHistory
|
|
8543
|
+
}) : null;
|
|
8544
|
+
const btcPsychologicalLevels = buildPsychologicalLevelAssetContext(
|
|
8545
|
+
btcCandlesHistory,
|
|
8546
|
+
1e3
|
|
8547
|
+
);
|
|
8548
|
+
const ethPsychologicalLevels = buildPsychologicalLevelAssetContext(
|
|
8549
|
+
ethCandlesHistory,
|
|
8550
|
+
100
|
|
8551
|
+
);
|
|
8552
|
+
const referencePsychologicalLevels = btcPsychologicalLevels != null || ethPsychologicalLevels != null ? {
|
|
8553
|
+
...btcPsychologicalLevels != null ? { BTCUSDT: btcPsychologicalLevels } : {},
|
|
8554
|
+
...ethPsychologicalLevels != null ? { ETHUSDT: ethPsychologicalLevels } : {}
|
|
8555
|
+
} : null;
|
|
8556
|
+
const relativeStrength1h = getRelativeChange(
|
|
8557
|
+
baseResult.price1hPcnt,
|
|
8558
|
+
btc1h.length >= 2 ? percentChange(
|
|
8559
|
+
btc1h[btc1h.length - 1].close,
|
|
8560
|
+
btc1h[Math.max(0, btc1h.length - 2)].close
|
|
8561
|
+
) : null
|
|
8562
|
+
);
|
|
8563
|
+
const relativeStrength4h = getRelativeChange(
|
|
8564
|
+
coin4h.length >= 2 ? percentChange(
|
|
8565
|
+
coin4h[coin4h.length - 1].close,
|
|
8566
|
+
coin4h[coin4h.length - 2].close
|
|
8567
|
+
) : null,
|
|
8568
|
+
btc4h.length >= 2 ? percentChange(
|
|
8569
|
+
btc4h[btc4h.length - 1].close,
|
|
8570
|
+
btc4h[btc4h.length - 2].close
|
|
8571
|
+
) : null
|
|
8572
|
+
);
|
|
8573
|
+
const relativeStrength1d = getRelativeChange(
|
|
8574
|
+
coin1d.length >= 2 ? percentChange(
|
|
8575
|
+
coin1d[coin1d.length - 1].close,
|
|
8576
|
+
coin1d[coin1d.length - 2].close
|
|
8577
|
+
) : null,
|
|
8578
|
+
btc1d.length >= 2 ? percentChange(
|
|
8579
|
+
btc1d[btc1d.length - 1].close,
|
|
8580
|
+
btc1d[btc1d.length - 2].close
|
|
8581
|
+
) : null
|
|
8582
|
+
);
|
|
8583
|
+
const benchmarkBias = btc1h.length >= 2 ? btc1h[btc1h.length - 1].close > btc1h[btc1h.length - 2].close ? "bull" : btc1h[btc1h.length - 1].close < btc1h[btc1h.length - 2].close ? "bear" : "neutral" : "neutral";
|
|
8584
|
+
const trendAlignment = trendBias === "neutral" || benchmarkBias === "neutral" ? "neutral" : trendBias === benchmarkBias ? trendBias === "bull" ? "aligned_bull" : "aligned_bear" : "against_benchmark";
|
|
8585
|
+
const benchmarkTrendBias = benchmarkMaFast == null || benchmarkMaSlow == null ? "neutral" : benchmarkMaFast > benchmarkMaSlow ? "bull" : benchmarkMaFast < benchmarkMaSlow ? "bear" : "neutral";
|
|
8586
|
+
return {
|
|
8587
|
+
benchmark: {
|
|
8588
|
+
maFast: benchmarkMaFast,
|
|
8589
|
+
maSlow: benchmarkMaSlow,
|
|
8590
|
+
bias: benchmarkTrendBias,
|
|
8591
|
+
relativeStrength1h,
|
|
8592
|
+
relativeStrength4h,
|
|
8593
|
+
relativeStrength1d,
|
|
8594
|
+
trendAlignment
|
|
8750
8595
|
},
|
|
8751
|
-
|
|
8752
|
-
|
|
8753
|
-
|
|
8754
|
-
|
|
8755
|
-
|
|
8756
|
-
|
|
8757
|
-
bbWidthPct
|
|
8596
|
+
execution: {
|
|
8597
|
+
venueSpread: baseResult.spread,
|
|
8598
|
+
venueSpreadZScore: calculateZScore(
|
|
8599
|
+
spreadSeries,
|
|
8600
|
+
toNullable(baseResult.spread)
|
|
8601
|
+
)
|
|
8758
8602
|
},
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
|
|
8603
|
+
targetVsBtc,
|
|
8604
|
+
...targetVsEth != null ? { targetVsEth } : {},
|
|
8605
|
+
...referencePsychologicalLevels != null ? { referencePsychologicalLevels } : {}
|
|
8606
|
+
};
|
|
8607
|
+
};
|
|
8608
|
+
const buildStructureSnapshot = () => {
|
|
8609
|
+
const structurePivots = detectConfirmedPivots(structureWindow, atr2);
|
|
8610
|
+
const structureZones = buildPriceZones(
|
|
8611
|
+
structureWindow,
|
|
8612
|
+
structurePivots,
|
|
8613
|
+
atr2
|
|
8614
|
+
);
|
|
8615
|
+
const swingContext = buildSwingContext(structurePivots);
|
|
8616
|
+
const pivotContext = buildPivotContext(
|
|
8617
|
+
structurePivots,
|
|
8618
|
+
structureWindow.length,
|
|
8619
|
+
atr2
|
|
8620
|
+
);
|
|
8621
|
+
const nearestSupport = getNearestZone(
|
|
8622
|
+
structureZones,
|
|
8623
|
+
"support",
|
|
8624
|
+
candle.close
|
|
8625
|
+
);
|
|
8626
|
+
const nearestResistance = getNearestZone(
|
|
8627
|
+
structureZones,
|
|
8628
|
+
"resistance",
|
|
8629
|
+
candle.close
|
|
8630
|
+
);
|
|
8631
|
+
const totalStructureVolume = structureWindow.reduce(
|
|
8632
|
+
(sum2, item) => sum2 + item.volume,
|
|
8633
|
+
0
|
|
8634
|
+
);
|
|
8635
|
+
const priceInSupportZone = nearestSupport == null ? null : candle.close >= nearestSupport.lower && candle.close <= nearestSupport.upper;
|
|
8636
|
+
const priceInResistanceZone = nearestResistance == null ? null : candle.close >= nearestResistance.lower && candle.close <= nearestResistance.upper;
|
|
8637
|
+
const activeZoneType = priceInSupportZone ? "support" : priceInResistanceZone ? "resistance" : null;
|
|
8638
|
+
const priceInZone = priceInSupportZone == null && priceInResistanceZone == null ? null : Boolean(priceInSupportZone || priceInResistanceZone);
|
|
8639
|
+
const resistanceVolumeShare = safeDivide(
|
|
8640
|
+
nearestResistance?.volume ?? null,
|
|
8641
|
+
totalStructureVolume
|
|
8642
|
+
);
|
|
8643
|
+
const supportVolumeShare = safeDivide(
|
|
8644
|
+
nearestSupport?.volume ?? null,
|
|
8645
|
+
totalStructureVolume
|
|
8646
|
+
);
|
|
8647
|
+
const sweepState = nearestResistance == null && nearestSupport == null ? "unknown" : nearestResistance != null && candle.high > nearestResistance.upper && candle.close < nearestResistance.level ? "swept_high" : nearestSupport != null && candle.low < nearestSupport.lower && candle.close > nearestSupport.level ? "swept_low" : nearestResistance != null && candle.close > nearestResistance.upper ? "broken_high" : nearestSupport != null && candle.close < nearestSupport.lower ? "broken_low" : "none";
|
|
8648
|
+
const liquiditySide = sweepState === "swept_high" || sweepState === "broken_high" ? "high" : sweepState === "swept_low" || sweepState === "broken_low" ? "low" : null;
|
|
8649
|
+
const referenceZoneSide = liquiditySide === "high" ? "resistance" : liquiditySide === "low" ? "support" : null;
|
|
8650
|
+
const prior20High = prior20.length > 0 ? Math.max(...prior20.map((item) => item.high)) : null;
|
|
8651
|
+
const prior20Low = prior20.length > 0 ? Math.min(...prior20.map((item) => item.low)) : null;
|
|
8652
|
+
const sweepHigh20 = prior20High == null ? null : candle.high > prior20High && candle.close < prior20High;
|
|
8653
|
+
const sweepLow20 = prior20Low == null ? null : candle.low < prior20Low && candle.close > prior20Low;
|
|
8654
|
+
const closeBackInsideRange = sweepHigh20 == null && sweepLow20 == null ? null : Boolean(sweepHigh20 || sweepLow20);
|
|
8655
|
+
const stopRunDirection = sweepHigh20 ? "up" : sweepLow20 ? "down" : null;
|
|
8656
|
+
const sweepWickPct = stopRunDirection === "up" ? upperWick : stopRunDirection === "down" ? lowerWick : null;
|
|
8657
|
+
const recent3 = candlesHistory.slice(-3);
|
|
8658
|
+
const recent5 = candlesHistory.slice(-5);
|
|
8659
|
+
const closesAboveHighLevel3 = highLevel == null ? null : recent3.filter((item) => item.close > highLevel).length;
|
|
8660
|
+
const closesBelowLowLevel3 = lowLevel == null ? null : recent3.filter((item) => item.close < lowLevel).length;
|
|
8661
|
+
const failedAcceptanceBars = highLevel == null || lowLevel == null ? null : recent5.filter(
|
|
8662
|
+
(item) => item.high > highLevel && item.close <= highLevel || item.low < lowLevel && item.close >= lowLevel
|
|
8663
|
+
).length;
|
|
8664
|
+
const acceptanceScore = closesAboveHighLevel3 == null || closesBelowLowLevel3 == null ? null : (closesAboveHighLevel3 - closesBelowLowLevel3) / Math.max(1, recent3.length);
|
|
8665
|
+
const breakoutBodyAtr = safeDivide(
|
|
8666
|
+
Math.abs(candle.close - candle.open),
|
|
8667
|
+
atr2
|
|
8668
|
+
);
|
|
8669
|
+
const srZones = buildSrZonesContext(
|
|
8670
|
+
structureWindow,
|
|
8671
|
+
candle.close,
|
|
8672
|
+
prevCandle?.close ?? null,
|
|
8673
|
+
atr2
|
|
8674
|
+
);
|
|
8675
|
+
const liquidityZones = buildLiquidityZonesContext(
|
|
8676
|
+
candlesHistory.slice(-180),
|
|
8677
|
+
candle.close,
|
|
8678
|
+
prevCandle?.close ?? null,
|
|
8679
|
+
atr2
|
|
8680
|
+
);
|
|
8681
|
+
const liquidityTails = buildLiquidityTailsContext(
|
|
8682
|
+
candlesHistory.slice(-180),
|
|
8683
|
+
candle.close,
|
|
8684
|
+
atr2
|
|
8685
|
+
);
|
|
8686
|
+
const structureZonesContext = buildStructureZonesContext(
|
|
8687
|
+
swingContext,
|
|
8688
|
+
pivotContext,
|
|
8689
|
+
candle.close,
|
|
8690
|
+
atr2,
|
|
8691
|
+
structureWindow
|
|
8692
|
+
);
|
|
8693
|
+
return {
|
|
8694
|
+
swing: swingContext,
|
|
8695
|
+
zones: {
|
|
8696
|
+
support: {
|
|
8697
|
+
level: nearestSupport?.level ?? null,
|
|
8698
|
+
lower: nearestSupport?.lower ?? null,
|
|
8699
|
+
upper: nearestSupport?.upper ?? null,
|
|
8700
|
+
touches: nearestSupport?.touches ?? null,
|
|
8701
|
+
ageBars: nearestSupport?.ageBars ?? null,
|
|
8702
|
+
volumeShare: supportVolumeShare,
|
|
8703
|
+
distanceAtr: safeDivide(
|
|
8704
|
+
nearestSupport == null ? null : candle.close - nearestSupport.level,
|
|
8705
|
+
atr2
|
|
8706
|
+
)
|
|
8707
|
+
},
|
|
8708
|
+
resistance: {
|
|
8709
|
+
level: nearestResistance?.level ?? null,
|
|
8710
|
+
lower: nearestResistance?.lower ?? null,
|
|
8711
|
+
upper: nearestResistance?.upper ?? null,
|
|
8712
|
+
touches: nearestResistance?.touches ?? null,
|
|
8713
|
+
ageBars: nearestResistance?.ageBars ?? null,
|
|
8714
|
+
volumeShare: resistanceVolumeShare,
|
|
8715
|
+
distanceAtr: safeDivide(
|
|
8716
|
+
nearestResistance == null ? null : nearestResistance.level - candle.close,
|
|
8717
|
+
atr2
|
|
8718
|
+
)
|
|
8719
|
+
},
|
|
8720
|
+
active: {
|
|
8721
|
+
side: activeZoneType,
|
|
8722
|
+
priceInZone
|
|
8723
|
+
}
|
|
8763
8724
|
},
|
|
8764
|
-
|
|
8765
|
-
|
|
8766
|
-
|
|
8767
|
-
|
|
8768
|
-
|
|
8769
|
-
|
|
8770
|
-
|
|
8725
|
+
srZones,
|
|
8726
|
+
liquidity: {
|
|
8727
|
+
sweepState,
|
|
8728
|
+
side: liquiditySide,
|
|
8729
|
+
referenceZoneSide,
|
|
8730
|
+
sweepHigh20,
|
|
8731
|
+
sweepLow20,
|
|
8732
|
+
closeBackInsideRange,
|
|
8733
|
+
stopRunDirection,
|
|
8734
|
+
sweepWickPct
|
|
8771
8735
|
},
|
|
8772
|
-
|
|
8773
|
-
|
|
8774
|
-
|
|
8775
|
-
|
|
8776
|
-
|
|
8777
|
-
|
|
8778
|
-
|
|
8779
|
-
|
|
8736
|
+
liquidityZones,
|
|
8737
|
+
liquidityTails,
|
|
8738
|
+
structureZones: structureZonesContext,
|
|
8739
|
+
pivots: pivotContext,
|
|
8740
|
+
acceptance: {
|
|
8741
|
+
closesAboveHighLevel3,
|
|
8742
|
+
closesBelowLowLevel3,
|
|
8743
|
+
failedAcceptanceBars,
|
|
8744
|
+
acceptanceScore,
|
|
8745
|
+
breakoutBodyAtr
|
|
8746
|
+
},
|
|
8747
|
+
localRange: {
|
|
8748
|
+
rangePosition20: calculateRangePosition(
|
|
8749
|
+
candle.close,
|
|
8750
|
+
recent20Low,
|
|
8751
|
+
recent20High
|
|
8752
|
+
),
|
|
8753
|
+
distanceToHighLevelAtr,
|
|
8754
|
+
distanceToLowLevelAtr,
|
|
8755
|
+
breakoutState,
|
|
8756
|
+
barsSinceBreakout: breakoutRuntimeState.barsSinceBreakout,
|
|
8757
|
+
breakoutRetestQuality
|
|
8780
8758
|
},
|
|
8781
8759
|
levels: {
|
|
8782
|
-
|
|
8783
|
-
|
|
8760
|
+
highTouchCount20,
|
|
8761
|
+
lowTouchCount20,
|
|
8762
|
+
dominantTouchCount20
|
|
8784
8763
|
},
|
|
8785
|
-
|
|
8786
|
-
|
|
8764
|
+
candleQuality: {
|
|
8765
|
+
upperWickPct: upperWick,
|
|
8766
|
+
lowerWickPct: lowerWick,
|
|
8767
|
+
rejectionWickScore
|
|
8787
8768
|
}
|
|
8788
|
-
}
|
|
8789
|
-
|
|
8769
|
+
};
|
|
8770
|
+
};
|
|
8771
|
+
const buildRegimeSnapshot = () => {
|
|
8772
|
+
const atrPctSeries = materializeNumericHistory(
|
|
8773
|
+
indicatorHistory.atrPct ?? createNumericHistoryBuffer()
|
|
8774
|
+
);
|
|
8775
|
+
const macdHistogramSeries = materializeNumericHistory(
|
|
8776
|
+
indicatorHistory.macdHistogram ?? createNumericHistoryBuffer()
|
|
8777
|
+
);
|
|
8778
|
+
const persistenceWindow = closeSeries.slice(-10);
|
|
8779
|
+
const directionalMoves = persistenceWindow.slice(1).map((value, index) => value - persistenceWindow[index]);
|
|
8780
|
+
const persistence = directionalMoves.length === 0 ? null : directionalMoves.filter(
|
|
8781
|
+
(delta) => trendBias === "bull" ? delta > 0 : trendBias === "bear" ? delta < 0 : delta === 0
|
|
8782
|
+
).length / directionalMoves.length;
|
|
8783
|
+
const atrPctZScore = calculateZScore(
|
|
8784
|
+
atrPctSeries,
|
|
8785
|
+
toNullable(baseResult.atrPct)
|
|
8786
|
+
);
|
|
8787
|
+
const atrSlope = calculateLineSlope(atrPctSeries, 5);
|
|
8788
|
+
const compressionScore = safeDivide(
|
|
8789
|
+
toNullable(baseResult.atrPct),
|
|
8790
|
+
getLastFiniteValue(atrPctSeries.slice(0, -1))
|
|
8791
|
+
);
|
|
8792
|
+
const expansionScore = compressionScore == null || compressionScore === 0 ? null : 1 / compressionScore;
|
|
8793
|
+
const bbWidthPctSeries = calculateRecentBbWidthPctSeries(closeSeries, 100);
|
|
8794
|
+
const rawAtrPctSeries = calculateRecentAtrPctSeries(candlesHistory, 100);
|
|
8795
|
+
const rawAtrPct = safeDivide(atr2, candle.close);
|
|
8796
|
+
const realizedVolatility = calculateRealizedVolatility(closeSeries);
|
|
8797
|
+
const realizedVolatilitySeries = calculateRecentRealizedVolatilitySeries(
|
|
8798
|
+
closeSeries,
|
|
8799
|
+
100
|
|
8800
|
+
);
|
|
8801
|
+
const rangeExpansionSeries = calculateRecentRangeExpansionSeries(
|
|
8802
|
+
candlesHistory,
|
|
8803
|
+
20
|
|
8804
|
+
);
|
|
8805
|
+
const rangeExpansion = rangeExpansionSeries[rangeExpansionSeries.length - 1] ?? null;
|
|
8806
|
+
const volatilityState = compressionScore == null ? "unknown" : compressionScore <= 0.9 ? "compressed" : compressionScore >= 1.1 ? "expanded" : "normal";
|
|
8807
|
+
const bodyStrength = highLowRange > 0 ? Math.abs(candle.close - candle.open) / highLowRange : null;
|
|
8808
|
+
const closeLocationInRange = highLowRange > 0 ? (candle.close - candle.low) / highLowRange : null;
|
|
8809
|
+
const recentFalseBreakoutDensity = highLevel == null || lowLevel == null || recent20.length < 2 ? null : recent20.reduce((count, item, index) => {
|
|
8810
|
+
if (index === 0) return count;
|
|
8811
|
+
const prevItem = recent20[index - 1];
|
|
8812
|
+
if (!prevItem) return count;
|
|
8813
|
+
if (prevItem.close > highLevel && item.close <= highLevel) {
|
|
8814
|
+
return count + 1;
|
|
8815
|
+
}
|
|
8816
|
+
if (prevItem.close < lowLevel && item.close >= lowLevel) {
|
|
8817
|
+
return count + 1;
|
|
8818
|
+
}
|
|
8819
|
+
return count;
|
|
8820
|
+
}, 0) / (recent20.length - 1);
|
|
8821
|
+
const adxContext = buildAdxContext(adxValue) ?? calculateAdxContext(candlesHistory);
|
|
8822
|
+
const rsiContext = buildRsiContext(rsiValue) ?? calculateRsiContext(closeSeries);
|
|
8823
|
+
const trendFollow = buildTrendFollowContext(
|
|
8824
|
+
candlesHistory.slice(-220),
|
|
8825
|
+
candle.close,
|
|
8826
|
+
atr2
|
|
8827
|
+
);
|
|
8828
|
+
const hl2Series = precomputedMaLayers === void 0 ? candlesHistory.map((item) => (item.high + item.low) / 2) : [];
|
|
8829
|
+
const maLayers = buildMaLayersContext(hl2Series, precomputedMaLayers);
|
|
8830
|
+
const contextMa = buildContextMaContext(
|
|
8831
|
+
closeSeries,
|
|
8832
|
+
candle.close,
|
|
8833
|
+
atr2,
|
|
8834
|
+
precomputedContextMa
|
|
8835
|
+
);
|
|
8836
|
+
const adaptiveChannel = buildAdaptiveChannelContext(
|
|
8837
|
+
candlesHistory,
|
|
8838
|
+
candle.close,
|
|
8839
|
+
atr2,
|
|
8840
|
+
precomputedAdaptiveChannel
|
|
8841
|
+
);
|
|
8842
|
+
return {
|
|
8790
8843
|
trend: {
|
|
8791
8844
|
bias: trendBias,
|
|
8792
8845
|
maStackScore,
|
|
@@ -8859,89 +8912,17 @@ var buildBaseContextSnapshot = ({
|
|
|
8859
8912
|
upCloseStreak: closeStreaks.up,
|
|
8860
8913
|
downCloseStreak: closeStreaks.down
|
|
8861
8914
|
},
|
|
8862
|
-
session,
|
|
8915
|
+
session: buildSessionContext(candle.timestamp),
|
|
8863
8916
|
memory: {
|
|
8864
8917
|
recentFalseBreakoutDensity
|
|
8865
8918
|
}
|
|
8866
|
-
}
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
|
|
8871
|
-
|
|
8872
|
-
|
|
8873
|
-
upper: nearestSupport?.upper ?? null,
|
|
8874
|
-
touches: nearestSupport?.touches ?? null,
|
|
8875
|
-
ageBars: nearestSupport?.ageBars ?? null,
|
|
8876
|
-
volumeShare: supportVolumeShare,
|
|
8877
|
-
distanceAtr: safeDivide(
|
|
8878
|
-
nearestSupport == null ? null : candle.close - nearestSupport.level,
|
|
8879
|
-
atr2
|
|
8880
|
-
)
|
|
8881
|
-
},
|
|
8882
|
-
resistance: {
|
|
8883
|
-
level: nearestResistance?.level ?? null,
|
|
8884
|
-
lower: nearestResistance?.lower ?? null,
|
|
8885
|
-
upper: nearestResistance?.upper ?? null,
|
|
8886
|
-
touches: nearestResistance?.touches ?? null,
|
|
8887
|
-
ageBars: nearestResistance?.ageBars ?? null,
|
|
8888
|
-
volumeShare: resistanceVolumeShare,
|
|
8889
|
-
distanceAtr: safeDivide(
|
|
8890
|
-
nearestResistance == null ? null : nearestResistance.level - candle.close,
|
|
8891
|
-
atr2
|
|
8892
|
-
)
|
|
8893
|
-
},
|
|
8894
|
-
active: {
|
|
8895
|
-
side: activeZoneType,
|
|
8896
|
-
priceInZone
|
|
8897
|
-
}
|
|
8898
|
-
},
|
|
8899
|
-
srZones,
|
|
8900
|
-
liquidity: {
|
|
8901
|
-
sweepState,
|
|
8902
|
-
side: liquiditySide,
|
|
8903
|
-
referenceZoneSide,
|
|
8904
|
-
sweepHigh20,
|
|
8905
|
-
sweepLow20,
|
|
8906
|
-
closeBackInsideRange,
|
|
8907
|
-
stopRunDirection,
|
|
8908
|
-
sweepWickPct
|
|
8909
|
-
},
|
|
8910
|
-
liquidityZones,
|
|
8911
|
-
liquidityTails,
|
|
8912
|
-
structureZones: structureZonesContext,
|
|
8913
|
-
pivots: pivotContext,
|
|
8914
|
-
acceptance: {
|
|
8915
|
-
closesAboveHighLevel3,
|
|
8916
|
-
closesBelowLowLevel3,
|
|
8917
|
-
failedAcceptanceBars,
|
|
8918
|
-
acceptanceScore,
|
|
8919
|
-
breakoutBodyAtr
|
|
8920
|
-
},
|
|
8921
|
-
localRange: {
|
|
8922
|
-
rangePosition20: calculateRangePosition(
|
|
8923
|
-
candle.close,
|
|
8924
|
-
recent20Low,
|
|
8925
|
-
recent20High
|
|
8926
|
-
),
|
|
8927
|
-
distanceToHighLevelAtr,
|
|
8928
|
-
distanceToLowLevelAtr,
|
|
8929
|
-
breakoutState,
|
|
8930
|
-
barsSinceBreakout: breakoutRuntimeState.barsSinceBreakout,
|
|
8931
|
-
breakoutRetestQuality
|
|
8932
|
-
},
|
|
8933
|
-
levels: {
|
|
8934
|
-
highTouchCount20,
|
|
8935
|
-
lowTouchCount20,
|
|
8936
|
-
dominantTouchCount20
|
|
8937
|
-
},
|
|
8938
|
-
candleQuality: {
|
|
8939
|
-
upperWickPct: upperWick,
|
|
8940
|
-
lowerWickPct: lowerWick,
|
|
8941
|
-
rejectionWickScore
|
|
8942
|
-
}
|
|
8943
|
-
},
|
|
8944
|
-
participation: {
|
|
8919
|
+
};
|
|
8920
|
+
};
|
|
8921
|
+
const buildParticipationSnapshot = () => {
|
|
8922
|
+
let cachedPriceVolumeProfile;
|
|
8923
|
+
let cachedVolumeStructure;
|
|
8924
|
+
let cachedDelta;
|
|
8925
|
+
return {
|
|
8945
8926
|
volume: {
|
|
8946
8927
|
volumeRel20,
|
|
8947
8928
|
turnoverRel20,
|
|
@@ -8954,30 +8935,89 @@ var buildBaseContextSnapshot = ({
|
|
|
8954
8935
|
),
|
|
8955
8936
|
effortVsResult
|
|
8956
8937
|
},
|
|
8957
|
-
priceVolumeProfile
|
|
8958
|
-
|
|
8959
|
-
|
|
8960
|
-
|
|
8961
|
-
|
|
8962
|
-
|
|
8963
|
-
maFast: benchmarkMaFast,
|
|
8964
|
-
maSlow: benchmarkMaSlow,
|
|
8965
|
-
bias: benchmarkTrendBias,
|
|
8966
|
-
relativeStrength1h,
|
|
8967
|
-
relativeStrength4h,
|
|
8968
|
-
relativeStrength1d,
|
|
8969
|
-
trendAlignment
|
|
8938
|
+
get priceVolumeProfile() {
|
|
8939
|
+
return cachedPriceVolumeProfile ??= buildPriceVolumeProfileContext(
|
|
8940
|
+
structureWindow,
|
|
8941
|
+
candle.close,
|
|
8942
|
+
atr2
|
|
8943
|
+
);
|
|
8970
8944
|
},
|
|
8971
|
-
|
|
8972
|
-
|
|
8973
|
-
|
|
8974
|
-
|
|
8975
|
-
|
|
8976
|
-
)
|
|
8945
|
+
get volumeStructure() {
|
|
8946
|
+
return cachedVolumeStructure ??= buildVolumeStructureContext(
|
|
8947
|
+
candlesHistory,
|
|
8948
|
+
candle.close,
|
|
8949
|
+
atr2
|
|
8950
|
+
);
|
|
8977
8951
|
},
|
|
8978
|
-
|
|
8979
|
-
|
|
8980
|
-
|
|
8952
|
+
get delta() {
|
|
8953
|
+
return cachedDelta ??= buildDeltaContext(
|
|
8954
|
+
structureWindow
|
|
8955
|
+
);
|
|
8956
|
+
}
|
|
8957
|
+
};
|
|
8958
|
+
};
|
|
8959
|
+
let cachedStructureSnapshot;
|
|
8960
|
+
let cachedRegimeSnapshot;
|
|
8961
|
+
let cachedParticipationSnapshot;
|
|
8962
|
+
let cachedRelativeSnapshot;
|
|
8963
|
+
const snapshot = {
|
|
8964
|
+
candle,
|
|
8965
|
+
prevCandle,
|
|
8966
|
+
raw: {
|
|
8967
|
+
trend: {
|
|
8968
|
+
maFast: baseResult.maFast,
|
|
8969
|
+
maMedium: baseResult.maMedium,
|
|
8970
|
+
maSlow: baseResult.maSlow
|
|
8971
|
+
},
|
|
8972
|
+
volatility: {
|
|
8973
|
+
atr: atr2,
|
|
8974
|
+
atrPct: toNullable(baseResult.atrPct),
|
|
8975
|
+
bbUpper: baseResult.bbUpper,
|
|
8976
|
+
bbMiddle: baseResult.bbMiddle,
|
|
8977
|
+
bbLower: baseResult.bbLower,
|
|
8978
|
+
bbWidthPct
|
|
8979
|
+
},
|
|
8980
|
+
momentum: {
|
|
8981
|
+
macd: toNullable(baseResult.macd),
|
|
8982
|
+
macdSignal: toNullable(baseResult.macdSignal),
|
|
8983
|
+
macdHistogram: toNullable(baseResult.macdHistogram)
|
|
8984
|
+
},
|
|
8985
|
+
volume: {
|
|
8986
|
+
volume: candle.volume,
|
|
8987
|
+
turnover: candle.turnover,
|
|
8988
|
+
obv: baseResult.obv,
|
|
8989
|
+
obvSma: baseResult.smaObv,
|
|
8990
|
+
volume1h: baseResult.volume1h,
|
|
8991
|
+
volume24h: baseResult.volume24h
|
|
8992
|
+
},
|
|
8993
|
+
price: {
|
|
8994
|
+
prevClose: baseResult.prevClose,
|
|
8995
|
+
price1hPct: baseResult.price1hPcnt,
|
|
8996
|
+
price24hPct: baseResult.price24hPcnt,
|
|
8997
|
+
highPrice1h: baseResult.highPrice1h,
|
|
8998
|
+
lowPrice1h: baseResult.lowPrice1h,
|
|
8999
|
+
highPrice24h: baseResult.highPrice24h,
|
|
9000
|
+
lowPrice24h: baseResult.lowPrice24h
|
|
9001
|
+
},
|
|
9002
|
+
levels: {
|
|
9003
|
+
highLevel: baseResult.highLevel,
|
|
9004
|
+
lowLevel: baseResult.lowLevel
|
|
9005
|
+
},
|
|
9006
|
+
crossAsset: {
|
|
9007
|
+
btcCorrelation: baseResult.correlation
|
|
9008
|
+
}
|
|
9009
|
+
},
|
|
9010
|
+
get regime() {
|
|
9011
|
+
return cachedRegimeSnapshot ??= buildRegimeSnapshot();
|
|
9012
|
+
},
|
|
9013
|
+
get structure() {
|
|
9014
|
+
return cachedStructureSnapshot ??= buildStructureSnapshot();
|
|
9015
|
+
},
|
|
9016
|
+
get participation() {
|
|
9017
|
+
return cachedParticipationSnapshot ??= buildParticipationSnapshot();
|
|
9018
|
+
},
|
|
9019
|
+
get relative() {
|
|
9020
|
+
return cachedRelativeSnapshot ??= buildRelativeSnapshot();
|
|
8981
9021
|
}
|
|
8982
9022
|
};
|
|
8983
9023
|
let cachedMtfSnapshot = null;
|
|
@@ -11185,6 +11225,22 @@ var createIndicators = (data, btcData = [], options = {}) => {
|
|
|
11185
11225
|
const last = value[value.length - 1];
|
|
11186
11226
|
return typeof last === "number" ? last : void 0;
|
|
11187
11227
|
},
|
|
11228
|
+
latestNumbers: (key, count) => {
|
|
11229
|
+
const normalizedCount = Number.isFinite(count) ? Math.max(0, Math.trunc(count)) : 0;
|
|
11230
|
+
if (normalizedCount === 0) return [];
|
|
11231
|
+
const buffer = indicatorHistory[key];
|
|
11232
|
+
if (buffer) {
|
|
11233
|
+
const resultSize = Math.min(normalizedCount, buffer.size);
|
|
11234
|
+
const result = new Array(resultSize);
|
|
11235
|
+
const firstOffset = buffer.size - resultSize;
|
|
11236
|
+
for (let index = 0; index < resultSize; index += 1) {
|
|
11237
|
+
result[index] = buffer.values[(buffer.start + firstOffset + index) % ML_BASE_CANDLES_WINDOW];
|
|
11238
|
+
}
|
|
11239
|
+
return result;
|
|
11240
|
+
}
|
|
11241
|
+
const value = getHistoryResult()[key];
|
|
11242
|
+
return Array.isArray(value) ? value.slice(-normalizedCount).filter((item) => typeof item === "number") : [];
|
|
11243
|
+
},
|
|
11188
11244
|
result: () => {
|
|
11189
11245
|
return cloneHistorySnapshot(
|
|
11190
11246
|
getHistoryResult()
|
|
@@ -12006,23 +12062,13 @@ var createTrendlineEngine = (initialCandles, options) => {
|
|
|
12006
12062
|
};
|
|
12007
12063
|
const next = (candle) => {
|
|
12008
12064
|
appendCandle(candle);
|
|
12009
|
-
|
|
12010
|
-
if (opts.capture && result.length === 0 && rawExtremaPoints.length) {
|
|
12011
|
-
rebuildCandidatesLikeBatch();
|
|
12012
|
-
result = buildResult();
|
|
12013
|
-
}
|
|
12014
|
-
return result;
|
|
12065
|
+
return buildResult();
|
|
12015
12066
|
};
|
|
12016
12067
|
const nextMany = (candles) => {
|
|
12017
12068
|
for (const candle of candles) {
|
|
12018
12069
|
appendCandle(candle);
|
|
12019
12070
|
}
|
|
12020
|
-
|
|
12021
|
-
if (opts.capture && result.length === 0 && rawExtremaPoints.length) {
|
|
12022
|
-
rebuildCandidatesLikeBatch();
|
|
12023
|
-
result = buildResult();
|
|
12024
|
-
}
|
|
12025
|
-
return result;
|
|
12071
|
+
return buildResult();
|
|
12026
12072
|
};
|
|
12027
12073
|
const getLines = () => buildResult();
|
|
12028
12074
|
const reset = () => {
|