@tradejs/core 2.0.15 → 2.0.16
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
package/dist/indicators.js
CHANGED
|
@@ -8550,19 +8550,9 @@ var buildBaseContextSnapshot = ({
|
|
|
8550
8550
|
const btcCloseSeries = fullBtcCloseSeries.slice(-BASE_CONTEXT_CANDLE_WINDOW);
|
|
8551
8551
|
const atr2 = toNullable(baseResult.atr);
|
|
8552
8552
|
const bbWidthPct = baseResult.bbUpper != null && baseResult.bbLower != null && baseResult.bbMiddle != null && baseResult.bbMiddle !== 0 ? (baseResult.bbUpper - baseResult.bbLower) / baseResult.bbMiddle * 100 : null;
|
|
8553
|
-
const atrPctSeries = materializeNumericHistory(
|
|
8554
|
-
indicatorHistory.atrPct ?? createNumericHistoryBuffer()
|
|
8555
|
-
);
|
|
8556
|
-
const macdHistogramSeries = materializeNumericHistory(
|
|
8557
|
-
indicatorHistory.macdHistogram ?? createNumericHistoryBuffer()
|
|
8558
|
-
);
|
|
8559
|
-
const spreadSeries = materializeNumericHistory(
|
|
8560
|
-
indicatorHistory.spread ?? createNumericHistoryBuffer()
|
|
8561
|
-
);
|
|
8562
8553
|
const recent20 = candlesHistory.slice(-20);
|
|
8563
8554
|
const prior20 = candlesHistory.slice(-21, -1);
|
|
8564
8555
|
const structureWindow = candlesHistory.slice(-STRUCTURE_LOOKBACK);
|
|
8565
|
-
const session = buildSessionContext(candle.timestamp);
|
|
8566
8556
|
const recent20High = recent20.length > 0 ? Math.max(...recent20.map((item) => item.high)) : null;
|
|
8567
8557
|
const recent20Low = recent20.length > 0 ? Math.min(...recent20.map((item) => item.low)) : null;
|
|
8568
8558
|
const avgVolume20 = recent20.length > 0 ? recent20.reduce((sum2, item) => sum2 + item.volume, 0) / recent20.length : null;
|
|
@@ -8591,38 +8581,7 @@ var buildBaseContextSnapshot = ({
|
|
|
8591
8581
|
);
|
|
8592
8582
|
const maStackScore = baseResult.maFast == null || baseResult.maMedium == null || baseResult.maSlow == null ? null : Math.sign(baseResult.maFast - baseResult.maMedium) + Math.sign(baseResult.maMedium - baseResult.maSlow);
|
|
8593
8583
|
const trendBias = maStackScore == null ? "neutral" : maStackScore > 0 ? "bull" : maStackScore < 0 ? "bear" : "neutral";
|
|
8594
|
-
const persistenceWindow = closeSeries.slice(-10);
|
|
8595
|
-
const directionalMoves = persistenceWindow.slice(1).map((value, index) => value - persistenceWindow[index]);
|
|
8596
|
-
const persistence = directionalMoves.length === 0 ? null : directionalMoves.filter(
|
|
8597
|
-
(delta) => trendBias === "bull" ? delta > 0 : trendBias === "bear" ? delta < 0 : delta === 0
|
|
8598
|
-
).length / directionalMoves.length;
|
|
8599
|
-
const atrPctZScore = calculateZScore(
|
|
8600
|
-
atrPctSeries,
|
|
8601
|
-
toNullable(baseResult.atrPct)
|
|
8602
|
-
);
|
|
8603
|
-
const atrSlope = calculateLineSlope(atrPctSeries, 5);
|
|
8604
|
-
const compressionScore = safeDivide(
|
|
8605
|
-
toNullable(baseResult.atrPct),
|
|
8606
|
-
getLastFiniteValue(atrPctSeries.slice(0, -1))
|
|
8607
|
-
);
|
|
8608
|
-
const expansionScore = compressionScore == null || compressionScore === 0 ? null : 1 / compressionScore;
|
|
8609
|
-
const bbWidthPctSeries = calculateRecentBbWidthPctSeries(closeSeries, 100);
|
|
8610
|
-
const rawAtrPctSeries = calculateRecentAtrPctSeries(candlesHistory, 100);
|
|
8611
|
-
const rawAtrPct = safeDivide(atr2, candle.close);
|
|
8612
|
-
const realizedVolatility = calculateRealizedVolatility(closeSeries);
|
|
8613
|
-
const realizedVolatilitySeries = calculateRecentRealizedVolatilitySeries(
|
|
8614
|
-
closeSeries,
|
|
8615
|
-
100
|
|
8616
|
-
);
|
|
8617
|
-
const rangeExpansionSeries = calculateRecentRangeExpansionSeries(
|
|
8618
|
-
candlesHistory,
|
|
8619
|
-
20
|
|
8620
|
-
);
|
|
8621
|
-
const rangeExpansion = rangeExpansionSeries[rangeExpansionSeries.length - 1] ?? null;
|
|
8622
|
-
const volatilityState = compressionScore == null ? "unknown" : compressionScore <= 0.9 ? "compressed" : compressionScore >= 1.1 ? "expanded" : "normal";
|
|
8623
8584
|
const highLowRange = candle.high - candle.low;
|
|
8624
|
-
const bodyStrength = highLowRange > 0 ? Math.abs(candle.close - candle.open) / highLowRange : null;
|
|
8625
|
-
const closeLocationInRange = highLowRange > 0 ? (candle.close - candle.low) / highLowRange : null;
|
|
8626
8585
|
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";
|
|
8627
8586
|
const touchTolerance = atr2 != null && Number.isFinite(atr2) && atr2 > 0 ? atr2 * 0.15 : null;
|
|
8628
8587
|
const highLevel = baseResult.highLevel;
|
|
@@ -8655,253 +8614,347 @@ var buildBaseContextSnapshot = ({
|
|
|
8655
8614
|
distanceScore * 0.45 + wickSupport * 0.25 + closeAcceptance * 0.3
|
|
8656
8615
|
);
|
|
8657
8616
|
})();
|
|
8658
|
-
const recentFalseBreakoutDensity = highLevel == null || lowLevel == null || recent20.length < 2 ? null : recent20.reduce((count, item, index) => {
|
|
8659
|
-
if (index === 0) {
|
|
8660
|
-
return count;
|
|
8661
|
-
}
|
|
8662
|
-
const prevItem = recent20[index - 1];
|
|
8663
|
-
if (!prevItem) {
|
|
8664
|
-
return count;
|
|
8665
|
-
}
|
|
8666
|
-
if (prevItem.close > highLevel && item.close <= highLevel) {
|
|
8667
|
-
return count + 1;
|
|
8668
|
-
}
|
|
8669
|
-
if (prevItem.close < lowLevel && item.close >= lowLevel) {
|
|
8670
|
-
return count + 1;
|
|
8671
|
-
}
|
|
8672
|
-
return count;
|
|
8673
|
-
}, 0) / (recent20.length - 1);
|
|
8674
8617
|
const rejectionWickScore = trendBias === "bull" ? lowerWick : trendBias === "bear" ? upperWick : Math.max(upperWick ?? 0, lowerWick ?? 0);
|
|
8675
|
-
const adxContext = buildAdxContext(adxValue) ?? calculateAdxContext(candlesHistory);
|
|
8676
|
-
const rsiContext = buildRsiContext(rsiValue) ?? calculateRsiContext(closeSeries);
|
|
8677
|
-
const benchmarkMaFast = averageLastN(btcCloseSeries, indicatorPeriods.maFast);
|
|
8678
|
-
const benchmarkMaSlow = averageLastN(btcCloseSeries, indicatorPeriods.maSlow);
|
|
8679
|
-
const coin1h = coinResampledCandles.h1;
|
|
8680
|
-
const btc1h = btcResampledCandles.h1;
|
|
8681
|
-
const btc4h = btcResampledCandles.h4;
|
|
8682
|
-
const btc1d = btcResampledCandles.d1;
|
|
8683
|
-
const eth1h = ethResampledCandles?.h1 ?? [];
|
|
8684
|
-
const eth4h = ethResampledCandles?.h4 ?? [];
|
|
8685
|
-
const eth1d = ethResampledCandles?.d1 ?? [];
|
|
8686
8618
|
const coin4h = coinResampledCandles.h4;
|
|
8687
8619
|
const coin1d = coinResampledCandles.d1;
|
|
8688
|
-
const
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
|
|
8695
|
-
|
|
8696
|
-
|
|
8697
|
-
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
|
|
8701
|
-
|
|
8702
|
-
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
8720
|
-
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
8728
|
-
|
|
8729
|
-
|
|
8730
|
-
|
|
8731
|
-
|
|
8732
|
-
|
|
8733
|
-
|
|
8734
|
-
|
|
8735
|
-
|
|
8736
|
-
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
|
|
8740
|
-
|
|
8741
|
-
|
|
8742
|
-
|
|
8743
|
-
|
|
8744
|
-
|
|
8745
|
-
)
|
|
8746
|
-
|
|
8747
|
-
|
|
8748
|
-
|
|
8749
|
-
|
|
8750
|
-
|
|
8751
|
-
|
|
8752
|
-
|
|
8753
|
-
|
|
8754
|
-
|
|
8755
|
-
|
|
8756
|
-
|
|
8757
|
-
|
|
8758
|
-
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
8766
|
-
|
|
8767
|
-
|
|
8768
|
-
|
|
8769
|
-
|
|
8770
|
-
|
|
8771
|
-
|
|
8772
|
-
|
|
8773
|
-
|
|
8774
|
-
|
|
8775
|
-
|
|
8776
|
-
|
|
8777
|
-
|
|
8778
|
-
totalStructureVolume
|
|
8779
|
-
);
|
|
8780
|
-
const supportVolumeShare = safeDivide(
|
|
8781
|
-
nearestSupport?.volume ?? null,
|
|
8782
|
-
totalStructureVolume
|
|
8783
|
-
);
|
|
8784
|
-
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";
|
|
8785
|
-
const liquiditySide = sweepState === "swept_high" || sweepState === "broken_high" ? "high" : sweepState === "swept_low" || sweepState === "broken_low" ? "low" : null;
|
|
8786
|
-
const referenceZoneSide = liquiditySide === "high" ? "resistance" : liquiditySide === "low" ? "support" : null;
|
|
8787
|
-
const prior20High = prior20.length > 0 ? Math.max(...prior20.map((item) => item.high)) : null;
|
|
8788
|
-
const prior20Low = prior20.length > 0 ? Math.min(...prior20.map((item) => item.low)) : null;
|
|
8789
|
-
const sweepHigh20 = prior20High == null ? null : candle.high > prior20High && candle.close < prior20High;
|
|
8790
|
-
const sweepLow20 = prior20Low == null ? null : candle.low < prior20Low && candle.close > prior20Low;
|
|
8791
|
-
const closeBackInsideRange = sweepHigh20 == null && sweepLow20 == null ? null : Boolean(sweepHigh20 || sweepLow20);
|
|
8792
|
-
const stopRunDirection = sweepHigh20 ? "up" : sweepLow20 ? "down" : null;
|
|
8793
|
-
const sweepWickPct = stopRunDirection === "up" ? upperWick : stopRunDirection === "down" ? lowerWick : null;
|
|
8794
|
-
const recent3 = candlesHistory.slice(-3);
|
|
8795
|
-
const recent5 = candlesHistory.slice(-5);
|
|
8796
|
-
const closesAboveHighLevel3 = highLevel == null ? null : recent3.filter((item) => item.close > highLevel).length;
|
|
8797
|
-
const closesBelowLowLevel3 = lowLevel == null ? null : recent3.filter((item) => item.close < lowLevel).length;
|
|
8798
|
-
const failedAcceptanceBars = highLevel == null || lowLevel == null ? null : recent5.filter(
|
|
8799
|
-
(item) => item.high > highLevel && item.close <= highLevel || item.low < lowLevel && item.close >= lowLevel
|
|
8800
|
-
).length;
|
|
8801
|
-
const acceptanceScore = closesAboveHighLevel3 == null || closesBelowLowLevel3 == null ? null : (closesAboveHighLevel3 - closesBelowLowLevel3) / Math.max(1, recent3.length);
|
|
8802
|
-
const breakoutBodyAtr = safeDivide(Math.abs(candle.close - candle.open), atr2);
|
|
8803
|
-
const priceVolumeProfile = buildPriceVolumeProfileContext(
|
|
8804
|
-
structureWindow,
|
|
8805
|
-
candle.close,
|
|
8806
|
-
atr2
|
|
8807
|
-
);
|
|
8808
|
-
const volumeStructure = buildVolumeStructureContext(
|
|
8809
|
-
candlesHistory,
|
|
8810
|
-
candle.close,
|
|
8811
|
-
atr2
|
|
8812
|
-
);
|
|
8813
|
-
const srZones = buildSrZonesContext(
|
|
8814
|
-
structureWindow,
|
|
8815
|
-
candle.close,
|
|
8816
|
-
prevCandle?.close ?? null,
|
|
8817
|
-
atr2
|
|
8818
|
-
);
|
|
8819
|
-
const liquidityZones = buildLiquidityZonesContext(
|
|
8820
|
-
candlesHistory.slice(-180),
|
|
8821
|
-
candle.close,
|
|
8822
|
-
prevCandle?.close ?? null,
|
|
8823
|
-
atr2
|
|
8824
|
-
);
|
|
8825
|
-
const liquidityTails = buildLiquidityTailsContext(
|
|
8826
|
-
candlesHistory.slice(-180),
|
|
8827
|
-
candle.close,
|
|
8828
|
-
atr2
|
|
8829
|
-
);
|
|
8830
|
-
const trendFollow = buildTrendFollowContext(
|
|
8831
|
-
candlesHistory.slice(-220),
|
|
8832
|
-
candle.close,
|
|
8833
|
-
atr2
|
|
8834
|
-
);
|
|
8835
|
-
const structureZonesContext = buildStructureZonesContext(
|
|
8836
|
-
swingContext,
|
|
8837
|
-
pivotContext,
|
|
8838
|
-
candle.close,
|
|
8839
|
-
atr2,
|
|
8840
|
-
structureWindow
|
|
8841
|
-
);
|
|
8842
|
-
const hl2Series = precomputedMaLayers === void 0 ? candlesHistory.map((item) => (item.high + item.low) / 2) : [];
|
|
8843
|
-
const maLayers = buildMaLayersContext(hl2Series, precomputedMaLayers);
|
|
8844
|
-
const contextMa = buildContextMaContext(
|
|
8845
|
-
closeSeries,
|
|
8846
|
-
candle.close,
|
|
8847
|
-
atr2,
|
|
8848
|
-
precomputedContextMa
|
|
8849
|
-
);
|
|
8850
|
-
const adaptiveChannel = buildAdaptiveChannelContext(
|
|
8851
|
-
candlesHistory,
|
|
8852
|
-
candle.close,
|
|
8853
|
-
atr2,
|
|
8854
|
-
precomputedAdaptiveChannel
|
|
8855
|
-
);
|
|
8856
|
-
const deltaContext = buildDeltaContext(structureWindow);
|
|
8857
|
-
const snapshot = {
|
|
8858
|
-
candle,
|
|
8859
|
-
prevCandle,
|
|
8860
|
-
raw: {
|
|
8861
|
-
trend: {
|
|
8862
|
-
maFast: baseResult.maFast,
|
|
8863
|
-
maMedium: baseResult.maMedium,
|
|
8864
|
-
maSlow: baseResult.maSlow
|
|
8620
|
+
const buildRelativeSnapshot = () => {
|
|
8621
|
+
const spreadSeries = materializeNumericHistory(
|
|
8622
|
+
indicatorHistory.spread ?? createNumericHistoryBuffer()
|
|
8623
|
+
);
|
|
8624
|
+
const benchmarkMaFast = averageLastN(
|
|
8625
|
+
btcCloseSeries,
|
|
8626
|
+
indicatorPeriods.maFast
|
|
8627
|
+
);
|
|
8628
|
+
const benchmarkMaSlow = averageLastN(
|
|
8629
|
+
btcCloseSeries,
|
|
8630
|
+
indicatorPeriods.maSlow
|
|
8631
|
+
);
|
|
8632
|
+
const coin1h = coinResampledCandles.h1;
|
|
8633
|
+
const btc1h = btcResampledCandles.h1;
|
|
8634
|
+
const btc4h = btcResampledCandles.h4;
|
|
8635
|
+
const btc1d = btcResampledCandles.d1;
|
|
8636
|
+
const eth1h = ethResampledCandles?.h1 ?? [];
|
|
8637
|
+
const eth4h = ethResampledCandles?.h4 ?? [];
|
|
8638
|
+
const eth1d = ethResampledCandles?.d1 ?? [];
|
|
8639
|
+
const targetVsBtc = buildTargetVsBtcContext({
|
|
8640
|
+
coin1h,
|
|
8641
|
+
btc1h,
|
|
8642
|
+
coin4h,
|
|
8643
|
+
btc4h,
|
|
8644
|
+
coin1d,
|
|
8645
|
+
btc1d,
|
|
8646
|
+
coinCandles: candlesHistory,
|
|
8647
|
+
btcCandles: btcCandlesHistory
|
|
8648
|
+
});
|
|
8649
|
+
const targetVsEth = ethCandlesHistory.length >= 2 ? buildTargetVsEthContext({
|
|
8650
|
+
coin1h,
|
|
8651
|
+
eth1h,
|
|
8652
|
+
coin4h,
|
|
8653
|
+
eth4h,
|
|
8654
|
+
coin1d,
|
|
8655
|
+
eth1d,
|
|
8656
|
+
coinCandles: candlesHistory,
|
|
8657
|
+
ethCandles: ethCandlesHistory
|
|
8658
|
+
}) : null;
|
|
8659
|
+
const btcPsychologicalLevels = buildPsychologicalLevelAssetContext(
|
|
8660
|
+
btcCandlesHistory,
|
|
8661
|
+
1e3
|
|
8662
|
+
);
|
|
8663
|
+
const ethPsychologicalLevels = buildPsychologicalLevelAssetContext(
|
|
8664
|
+
ethCandlesHistory,
|
|
8665
|
+
100
|
|
8666
|
+
);
|
|
8667
|
+
const referencePsychologicalLevels = btcPsychologicalLevels != null || ethPsychologicalLevels != null ? {
|
|
8668
|
+
...btcPsychologicalLevels != null ? { BTCUSDT: btcPsychologicalLevels } : {},
|
|
8669
|
+
...ethPsychologicalLevels != null ? { ETHUSDT: ethPsychologicalLevels } : {}
|
|
8670
|
+
} : null;
|
|
8671
|
+
const relativeStrength1h = getRelativeChange(
|
|
8672
|
+
baseResult.price1hPcnt,
|
|
8673
|
+
btc1h.length >= 2 ? percentChange(
|
|
8674
|
+
btc1h[btc1h.length - 1].close,
|
|
8675
|
+
btc1h[Math.max(0, btc1h.length - 2)].close
|
|
8676
|
+
) : null
|
|
8677
|
+
);
|
|
8678
|
+
const relativeStrength4h = getRelativeChange(
|
|
8679
|
+
coin4h.length >= 2 ? percentChange(
|
|
8680
|
+
coin4h[coin4h.length - 1].close,
|
|
8681
|
+
coin4h[coin4h.length - 2].close
|
|
8682
|
+
) : null,
|
|
8683
|
+
btc4h.length >= 2 ? percentChange(
|
|
8684
|
+
btc4h[btc4h.length - 1].close,
|
|
8685
|
+
btc4h[btc4h.length - 2].close
|
|
8686
|
+
) : null
|
|
8687
|
+
);
|
|
8688
|
+
const relativeStrength1d = getRelativeChange(
|
|
8689
|
+
coin1d.length >= 2 ? percentChange(
|
|
8690
|
+
coin1d[coin1d.length - 1].close,
|
|
8691
|
+
coin1d[coin1d.length - 2].close
|
|
8692
|
+
) : null,
|
|
8693
|
+
btc1d.length >= 2 ? percentChange(
|
|
8694
|
+
btc1d[btc1d.length - 1].close,
|
|
8695
|
+
btc1d[btc1d.length - 2].close
|
|
8696
|
+
) : null
|
|
8697
|
+
);
|
|
8698
|
+
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";
|
|
8699
|
+
const trendAlignment = trendBias === "neutral" || benchmarkBias === "neutral" ? "neutral" : trendBias === benchmarkBias ? trendBias === "bull" ? "aligned_bull" : "aligned_bear" : "against_benchmark";
|
|
8700
|
+
const benchmarkTrendBias = benchmarkMaFast == null || benchmarkMaSlow == null ? "neutral" : benchmarkMaFast > benchmarkMaSlow ? "bull" : benchmarkMaFast < benchmarkMaSlow ? "bear" : "neutral";
|
|
8701
|
+
return {
|
|
8702
|
+
benchmark: {
|
|
8703
|
+
maFast: benchmarkMaFast,
|
|
8704
|
+
maSlow: benchmarkMaSlow,
|
|
8705
|
+
bias: benchmarkTrendBias,
|
|
8706
|
+
relativeStrength1h,
|
|
8707
|
+
relativeStrength4h,
|
|
8708
|
+
relativeStrength1d,
|
|
8709
|
+
trendAlignment
|
|
8865
8710
|
},
|
|
8866
|
-
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
|
|
8871
|
-
|
|
8872
|
-
bbWidthPct
|
|
8711
|
+
execution: {
|
|
8712
|
+
venueSpread: baseResult.spread,
|
|
8713
|
+
venueSpreadZScore: calculateZScore(
|
|
8714
|
+
spreadSeries,
|
|
8715
|
+
toNullable(baseResult.spread)
|
|
8716
|
+
)
|
|
8873
8717
|
},
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
|
|
8718
|
+
targetVsBtc,
|
|
8719
|
+
...targetVsEth != null ? { targetVsEth } : {},
|
|
8720
|
+
...referencePsychologicalLevels != null ? { referencePsychologicalLevels } : {}
|
|
8721
|
+
};
|
|
8722
|
+
};
|
|
8723
|
+
const buildStructureSnapshot = () => {
|
|
8724
|
+
const structurePivots = detectConfirmedPivots(structureWindow, atr2);
|
|
8725
|
+
const structureZones = buildPriceZones(
|
|
8726
|
+
structureWindow,
|
|
8727
|
+
structurePivots,
|
|
8728
|
+
atr2
|
|
8729
|
+
);
|
|
8730
|
+
const swingContext = buildSwingContext(structurePivots);
|
|
8731
|
+
const pivotContext = buildPivotContext(
|
|
8732
|
+
structurePivots,
|
|
8733
|
+
structureWindow.length,
|
|
8734
|
+
atr2
|
|
8735
|
+
);
|
|
8736
|
+
const nearestSupport = getNearestZone(
|
|
8737
|
+
structureZones,
|
|
8738
|
+
"support",
|
|
8739
|
+
candle.close
|
|
8740
|
+
);
|
|
8741
|
+
const nearestResistance = getNearestZone(
|
|
8742
|
+
structureZones,
|
|
8743
|
+
"resistance",
|
|
8744
|
+
candle.close
|
|
8745
|
+
);
|
|
8746
|
+
const totalStructureVolume = structureWindow.reduce(
|
|
8747
|
+
(sum2, item) => sum2 + item.volume,
|
|
8748
|
+
0
|
|
8749
|
+
);
|
|
8750
|
+
const priceInSupportZone = nearestSupport == null ? null : candle.close >= nearestSupport.lower && candle.close <= nearestSupport.upper;
|
|
8751
|
+
const priceInResistanceZone = nearestResistance == null ? null : candle.close >= nearestResistance.lower && candle.close <= nearestResistance.upper;
|
|
8752
|
+
const activeZoneType = priceInSupportZone ? "support" : priceInResistanceZone ? "resistance" : null;
|
|
8753
|
+
const priceInZone = priceInSupportZone == null && priceInResistanceZone == null ? null : Boolean(priceInSupportZone || priceInResistanceZone);
|
|
8754
|
+
const resistanceVolumeShare = safeDivide(
|
|
8755
|
+
nearestResistance?.volume ?? null,
|
|
8756
|
+
totalStructureVolume
|
|
8757
|
+
);
|
|
8758
|
+
const supportVolumeShare = safeDivide(
|
|
8759
|
+
nearestSupport?.volume ?? null,
|
|
8760
|
+
totalStructureVolume
|
|
8761
|
+
);
|
|
8762
|
+
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";
|
|
8763
|
+
const liquiditySide = sweepState === "swept_high" || sweepState === "broken_high" ? "high" : sweepState === "swept_low" || sweepState === "broken_low" ? "low" : null;
|
|
8764
|
+
const referenceZoneSide = liquiditySide === "high" ? "resistance" : liquiditySide === "low" ? "support" : null;
|
|
8765
|
+
const prior20High = prior20.length > 0 ? Math.max(...prior20.map((item) => item.high)) : null;
|
|
8766
|
+
const prior20Low = prior20.length > 0 ? Math.min(...prior20.map((item) => item.low)) : null;
|
|
8767
|
+
const sweepHigh20 = prior20High == null ? null : candle.high > prior20High && candle.close < prior20High;
|
|
8768
|
+
const sweepLow20 = prior20Low == null ? null : candle.low < prior20Low && candle.close > prior20Low;
|
|
8769
|
+
const closeBackInsideRange = sweepHigh20 == null && sweepLow20 == null ? null : Boolean(sweepHigh20 || sweepLow20);
|
|
8770
|
+
const stopRunDirection = sweepHigh20 ? "up" : sweepLow20 ? "down" : null;
|
|
8771
|
+
const sweepWickPct = stopRunDirection === "up" ? upperWick : stopRunDirection === "down" ? lowerWick : null;
|
|
8772
|
+
const recent3 = candlesHistory.slice(-3);
|
|
8773
|
+
const recent5 = candlesHistory.slice(-5);
|
|
8774
|
+
const closesAboveHighLevel3 = highLevel == null ? null : recent3.filter((item) => item.close > highLevel).length;
|
|
8775
|
+
const closesBelowLowLevel3 = lowLevel == null ? null : recent3.filter((item) => item.close < lowLevel).length;
|
|
8776
|
+
const failedAcceptanceBars = highLevel == null || lowLevel == null ? null : recent5.filter(
|
|
8777
|
+
(item) => item.high > highLevel && item.close <= highLevel || item.low < lowLevel && item.close >= lowLevel
|
|
8778
|
+
).length;
|
|
8779
|
+
const acceptanceScore = closesAboveHighLevel3 == null || closesBelowLowLevel3 == null ? null : (closesAboveHighLevel3 - closesBelowLowLevel3) / Math.max(1, recent3.length);
|
|
8780
|
+
const breakoutBodyAtr = safeDivide(
|
|
8781
|
+
Math.abs(candle.close - candle.open),
|
|
8782
|
+
atr2
|
|
8783
|
+
);
|
|
8784
|
+
const srZones = buildSrZonesContext(
|
|
8785
|
+
structureWindow,
|
|
8786
|
+
candle.close,
|
|
8787
|
+
prevCandle?.close ?? null,
|
|
8788
|
+
atr2
|
|
8789
|
+
);
|
|
8790
|
+
const liquidityZones = buildLiquidityZonesContext(
|
|
8791
|
+
candlesHistory.slice(-180),
|
|
8792
|
+
candle.close,
|
|
8793
|
+
prevCandle?.close ?? null,
|
|
8794
|
+
atr2
|
|
8795
|
+
);
|
|
8796
|
+
const liquidityTails = buildLiquidityTailsContext(
|
|
8797
|
+
candlesHistory.slice(-180),
|
|
8798
|
+
candle.close,
|
|
8799
|
+
atr2
|
|
8800
|
+
);
|
|
8801
|
+
const structureZonesContext = buildStructureZonesContext(
|
|
8802
|
+
swingContext,
|
|
8803
|
+
pivotContext,
|
|
8804
|
+
candle.close,
|
|
8805
|
+
atr2,
|
|
8806
|
+
structureWindow
|
|
8807
|
+
);
|
|
8808
|
+
return {
|
|
8809
|
+
swing: swingContext,
|
|
8810
|
+
zones: {
|
|
8811
|
+
support: {
|
|
8812
|
+
level: nearestSupport?.level ?? null,
|
|
8813
|
+
lower: nearestSupport?.lower ?? null,
|
|
8814
|
+
upper: nearestSupport?.upper ?? null,
|
|
8815
|
+
touches: nearestSupport?.touches ?? null,
|
|
8816
|
+
ageBars: nearestSupport?.ageBars ?? null,
|
|
8817
|
+
volumeShare: supportVolumeShare,
|
|
8818
|
+
distanceAtr: safeDivide(
|
|
8819
|
+
nearestSupport == null ? null : candle.close - nearestSupport.level,
|
|
8820
|
+
atr2
|
|
8821
|
+
)
|
|
8822
|
+
},
|
|
8823
|
+
resistance: {
|
|
8824
|
+
level: nearestResistance?.level ?? null,
|
|
8825
|
+
lower: nearestResistance?.lower ?? null,
|
|
8826
|
+
upper: nearestResistance?.upper ?? null,
|
|
8827
|
+
touches: nearestResistance?.touches ?? null,
|
|
8828
|
+
ageBars: nearestResistance?.ageBars ?? null,
|
|
8829
|
+
volumeShare: resistanceVolumeShare,
|
|
8830
|
+
distanceAtr: safeDivide(
|
|
8831
|
+
nearestResistance == null ? null : nearestResistance.level - candle.close,
|
|
8832
|
+
atr2
|
|
8833
|
+
)
|
|
8834
|
+
},
|
|
8835
|
+
active: {
|
|
8836
|
+
side: activeZoneType,
|
|
8837
|
+
priceInZone
|
|
8838
|
+
}
|
|
8878
8839
|
},
|
|
8879
|
-
|
|
8880
|
-
|
|
8881
|
-
|
|
8882
|
-
|
|
8883
|
-
|
|
8884
|
-
|
|
8885
|
-
|
|
8840
|
+
srZones,
|
|
8841
|
+
liquidity: {
|
|
8842
|
+
sweepState,
|
|
8843
|
+
side: liquiditySide,
|
|
8844
|
+
referenceZoneSide,
|
|
8845
|
+
sweepHigh20,
|
|
8846
|
+
sweepLow20,
|
|
8847
|
+
closeBackInsideRange,
|
|
8848
|
+
stopRunDirection,
|
|
8849
|
+
sweepWickPct
|
|
8886
8850
|
},
|
|
8887
|
-
|
|
8888
|
-
|
|
8889
|
-
|
|
8890
|
-
|
|
8891
|
-
|
|
8892
|
-
|
|
8893
|
-
|
|
8894
|
-
|
|
8851
|
+
liquidityZones,
|
|
8852
|
+
liquidityTails,
|
|
8853
|
+
structureZones: structureZonesContext,
|
|
8854
|
+
pivots: pivotContext,
|
|
8855
|
+
acceptance: {
|
|
8856
|
+
closesAboveHighLevel3,
|
|
8857
|
+
closesBelowLowLevel3,
|
|
8858
|
+
failedAcceptanceBars,
|
|
8859
|
+
acceptanceScore,
|
|
8860
|
+
breakoutBodyAtr
|
|
8861
|
+
},
|
|
8862
|
+
localRange: {
|
|
8863
|
+
rangePosition20: calculateRangePosition(
|
|
8864
|
+
candle.close,
|
|
8865
|
+
recent20Low,
|
|
8866
|
+
recent20High
|
|
8867
|
+
),
|
|
8868
|
+
distanceToHighLevelAtr,
|
|
8869
|
+
distanceToLowLevelAtr,
|
|
8870
|
+
breakoutState,
|
|
8871
|
+
barsSinceBreakout: breakoutRuntimeState.barsSinceBreakout,
|
|
8872
|
+
breakoutRetestQuality
|
|
8895
8873
|
},
|
|
8896
8874
|
levels: {
|
|
8897
|
-
|
|
8898
|
-
|
|
8875
|
+
highTouchCount20,
|
|
8876
|
+
lowTouchCount20,
|
|
8877
|
+
dominantTouchCount20
|
|
8899
8878
|
},
|
|
8900
|
-
|
|
8901
|
-
|
|
8879
|
+
candleQuality: {
|
|
8880
|
+
upperWickPct: upperWick,
|
|
8881
|
+
lowerWickPct: lowerWick,
|
|
8882
|
+
rejectionWickScore
|
|
8902
8883
|
}
|
|
8903
|
-
}
|
|
8904
|
-
|
|
8884
|
+
};
|
|
8885
|
+
};
|
|
8886
|
+
const buildRegimeSnapshot = () => {
|
|
8887
|
+
const atrPctSeries = materializeNumericHistory(
|
|
8888
|
+
indicatorHistory.atrPct ?? createNumericHistoryBuffer()
|
|
8889
|
+
);
|
|
8890
|
+
const macdHistogramSeries = materializeNumericHistory(
|
|
8891
|
+
indicatorHistory.macdHistogram ?? createNumericHistoryBuffer()
|
|
8892
|
+
);
|
|
8893
|
+
const persistenceWindow = closeSeries.slice(-10);
|
|
8894
|
+
const directionalMoves = persistenceWindow.slice(1).map((value, index) => value - persistenceWindow[index]);
|
|
8895
|
+
const persistence = directionalMoves.length === 0 ? null : directionalMoves.filter(
|
|
8896
|
+
(delta) => trendBias === "bull" ? delta > 0 : trendBias === "bear" ? delta < 0 : delta === 0
|
|
8897
|
+
).length / directionalMoves.length;
|
|
8898
|
+
const atrPctZScore = calculateZScore(
|
|
8899
|
+
atrPctSeries,
|
|
8900
|
+
toNullable(baseResult.atrPct)
|
|
8901
|
+
);
|
|
8902
|
+
const atrSlope = calculateLineSlope(atrPctSeries, 5);
|
|
8903
|
+
const compressionScore = safeDivide(
|
|
8904
|
+
toNullable(baseResult.atrPct),
|
|
8905
|
+
getLastFiniteValue(atrPctSeries.slice(0, -1))
|
|
8906
|
+
);
|
|
8907
|
+
const expansionScore = compressionScore == null || compressionScore === 0 ? null : 1 / compressionScore;
|
|
8908
|
+
const bbWidthPctSeries = calculateRecentBbWidthPctSeries(closeSeries, 100);
|
|
8909
|
+
const rawAtrPctSeries = calculateRecentAtrPctSeries(candlesHistory, 100);
|
|
8910
|
+
const rawAtrPct = safeDivide(atr2, candle.close);
|
|
8911
|
+
const realizedVolatility = calculateRealizedVolatility(closeSeries);
|
|
8912
|
+
const realizedVolatilitySeries = calculateRecentRealizedVolatilitySeries(
|
|
8913
|
+
closeSeries,
|
|
8914
|
+
100
|
|
8915
|
+
);
|
|
8916
|
+
const rangeExpansionSeries = calculateRecentRangeExpansionSeries(
|
|
8917
|
+
candlesHistory,
|
|
8918
|
+
20
|
|
8919
|
+
);
|
|
8920
|
+
const rangeExpansion = rangeExpansionSeries[rangeExpansionSeries.length - 1] ?? null;
|
|
8921
|
+
const volatilityState = compressionScore == null ? "unknown" : compressionScore <= 0.9 ? "compressed" : compressionScore >= 1.1 ? "expanded" : "normal";
|
|
8922
|
+
const bodyStrength = highLowRange > 0 ? Math.abs(candle.close - candle.open) / highLowRange : null;
|
|
8923
|
+
const closeLocationInRange = highLowRange > 0 ? (candle.close - candle.low) / highLowRange : null;
|
|
8924
|
+
const recentFalseBreakoutDensity = highLevel == null || lowLevel == null || recent20.length < 2 ? null : recent20.reduce((count, item, index) => {
|
|
8925
|
+
if (index === 0) return count;
|
|
8926
|
+
const prevItem = recent20[index - 1];
|
|
8927
|
+
if (!prevItem) return count;
|
|
8928
|
+
if (prevItem.close > highLevel && item.close <= highLevel) {
|
|
8929
|
+
return count + 1;
|
|
8930
|
+
}
|
|
8931
|
+
if (prevItem.close < lowLevel && item.close >= lowLevel) {
|
|
8932
|
+
return count + 1;
|
|
8933
|
+
}
|
|
8934
|
+
return count;
|
|
8935
|
+
}, 0) / (recent20.length - 1);
|
|
8936
|
+
const adxContext = buildAdxContext(adxValue) ?? calculateAdxContext(candlesHistory);
|
|
8937
|
+
const rsiContext = buildRsiContext(rsiValue) ?? calculateRsiContext(closeSeries);
|
|
8938
|
+
const trendFollow = buildTrendFollowContext(
|
|
8939
|
+
candlesHistory.slice(-220),
|
|
8940
|
+
candle.close,
|
|
8941
|
+
atr2
|
|
8942
|
+
);
|
|
8943
|
+
const hl2Series = precomputedMaLayers === void 0 ? candlesHistory.map((item) => (item.high + item.low) / 2) : [];
|
|
8944
|
+
const maLayers = buildMaLayersContext(hl2Series, precomputedMaLayers);
|
|
8945
|
+
const contextMa = buildContextMaContext(
|
|
8946
|
+
closeSeries,
|
|
8947
|
+
candle.close,
|
|
8948
|
+
atr2,
|
|
8949
|
+
precomputedContextMa
|
|
8950
|
+
);
|
|
8951
|
+
const adaptiveChannel = buildAdaptiveChannelContext(
|
|
8952
|
+
candlesHistory,
|
|
8953
|
+
candle.close,
|
|
8954
|
+
atr2,
|
|
8955
|
+
precomputedAdaptiveChannel
|
|
8956
|
+
);
|
|
8957
|
+
return {
|
|
8905
8958
|
trend: {
|
|
8906
8959
|
bias: trendBias,
|
|
8907
8960
|
maStackScore,
|
|
@@ -8974,89 +9027,17 @@ var buildBaseContextSnapshot = ({
|
|
|
8974
9027
|
upCloseStreak: closeStreaks.up,
|
|
8975
9028
|
downCloseStreak: closeStreaks.down
|
|
8976
9029
|
},
|
|
8977
|
-
session,
|
|
9030
|
+
session: buildSessionContext(candle.timestamp),
|
|
8978
9031
|
memory: {
|
|
8979
9032
|
recentFalseBreakoutDensity
|
|
8980
9033
|
}
|
|
8981
|
-
}
|
|
8982
|
-
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
upper: nearestSupport?.upper ?? null,
|
|
8989
|
-
touches: nearestSupport?.touches ?? null,
|
|
8990
|
-
ageBars: nearestSupport?.ageBars ?? null,
|
|
8991
|
-
volumeShare: supportVolumeShare,
|
|
8992
|
-
distanceAtr: safeDivide(
|
|
8993
|
-
nearestSupport == null ? null : candle.close - nearestSupport.level,
|
|
8994
|
-
atr2
|
|
8995
|
-
)
|
|
8996
|
-
},
|
|
8997
|
-
resistance: {
|
|
8998
|
-
level: nearestResistance?.level ?? null,
|
|
8999
|
-
lower: nearestResistance?.lower ?? null,
|
|
9000
|
-
upper: nearestResistance?.upper ?? null,
|
|
9001
|
-
touches: nearestResistance?.touches ?? null,
|
|
9002
|
-
ageBars: nearestResistance?.ageBars ?? null,
|
|
9003
|
-
volumeShare: resistanceVolumeShare,
|
|
9004
|
-
distanceAtr: safeDivide(
|
|
9005
|
-
nearestResistance == null ? null : nearestResistance.level - candle.close,
|
|
9006
|
-
atr2
|
|
9007
|
-
)
|
|
9008
|
-
},
|
|
9009
|
-
active: {
|
|
9010
|
-
side: activeZoneType,
|
|
9011
|
-
priceInZone
|
|
9012
|
-
}
|
|
9013
|
-
},
|
|
9014
|
-
srZones,
|
|
9015
|
-
liquidity: {
|
|
9016
|
-
sweepState,
|
|
9017
|
-
side: liquiditySide,
|
|
9018
|
-
referenceZoneSide,
|
|
9019
|
-
sweepHigh20,
|
|
9020
|
-
sweepLow20,
|
|
9021
|
-
closeBackInsideRange,
|
|
9022
|
-
stopRunDirection,
|
|
9023
|
-
sweepWickPct
|
|
9024
|
-
},
|
|
9025
|
-
liquidityZones,
|
|
9026
|
-
liquidityTails,
|
|
9027
|
-
structureZones: structureZonesContext,
|
|
9028
|
-
pivots: pivotContext,
|
|
9029
|
-
acceptance: {
|
|
9030
|
-
closesAboveHighLevel3,
|
|
9031
|
-
closesBelowLowLevel3,
|
|
9032
|
-
failedAcceptanceBars,
|
|
9033
|
-
acceptanceScore,
|
|
9034
|
-
breakoutBodyAtr
|
|
9035
|
-
},
|
|
9036
|
-
localRange: {
|
|
9037
|
-
rangePosition20: calculateRangePosition(
|
|
9038
|
-
candle.close,
|
|
9039
|
-
recent20Low,
|
|
9040
|
-
recent20High
|
|
9041
|
-
),
|
|
9042
|
-
distanceToHighLevelAtr,
|
|
9043
|
-
distanceToLowLevelAtr,
|
|
9044
|
-
breakoutState,
|
|
9045
|
-
barsSinceBreakout: breakoutRuntimeState.barsSinceBreakout,
|
|
9046
|
-
breakoutRetestQuality
|
|
9047
|
-
},
|
|
9048
|
-
levels: {
|
|
9049
|
-
highTouchCount20,
|
|
9050
|
-
lowTouchCount20,
|
|
9051
|
-
dominantTouchCount20
|
|
9052
|
-
},
|
|
9053
|
-
candleQuality: {
|
|
9054
|
-
upperWickPct: upperWick,
|
|
9055
|
-
lowerWickPct: lowerWick,
|
|
9056
|
-
rejectionWickScore
|
|
9057
|
-
}
|
|
9058
|
-
},
|
|
9059
|
-
participation: {
|
|
9034
|
+
};
|
|
9035
|
+
};
|
|
9036
|
+
const buildParticipationSnapshot = () => {
|
|
9037
|
+
let cachedPriceVolumeProfile;
|
|
9038
|
+
let cachedVolumeStructure;
|
|
9039
|
+
let cachedDelta;
|
|
9040
|
+
return {
|
|
9060
9041
|
volume: {
|
|
9061
9042
|
volumeRel20,
|
|
9062
9043
|
turnoverRel20,
|
|
@@ -9069,30 +9050,89 @@ var buildBaseContextSnapshot = ({
|
|
|
9069
9050
|
),
|
|
9070
9051
|
effortVsResult
|
|
9071
9052
|
},
|
|
9072
|
-
priceVolumeProfile
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
|
|
9078
|
-
maFast: benchmarkMaFast,
|
|
9079
|
-
maSlow: benchmarkMaSlow,
|
|
9080
|
-
bias: benchmarkTrendBias,
|
|
9081
|
-
relativeStrength1h,
|
|
9082
|
-
relativeStrength4h,
|
|
9083
|
-
relativeStrength1d,
|
|
9084
|
-
trendAlignment
|
|
9053
|
+
get priceVolumeProfile() {
|
|
9054
|
+
return cachedPriceVolumeProfile ??= buildPriceVolumeProfileContext(
|
|
9055
|
+
structureWindow,
|
|
9056
|
+
candle.close,
|
|
9057
|
+
atr2
|
|
9058
|
+
);
|
|
9085
9059
|
},
|
|
9086
|
-
|
|
9087
|
-
|
|
9088
|
-
|
|
9089
|
-
|
|
9090
|
-
|
|
9091
|
-
)
|
|
9060
|
+
get volumeStructure() {
|
|
9061
|
+
return cachedVolumeStructure ??= buildVolumeStructureContext(
|
|
9062
|
+
candlesHistory,
|
|
9063
|
+
candle.close,
|
|
9064
|
+
atr2
|
|
9065
|
+
);
|
|
9092
9066
|
},
|
|
9093
|
-
|
|
9094
|
-
|
|
9095
|
-
|
|
9067
|
+
get delta() {
|
|
9068
|
+
return cachedDelta ??= buildDeltaContext(
|
|
9069
|
+
structureWindow
|
|
9070
|
+
);
|
|
9071
|
+
}
|
|
9072
|
+
};
|
|
9073
|
+
};
|
|
9074
|
+
let cachedStructureSnapshot;
|
|
9075
|
+
let cachedRegimeSnapshot;
|
|
9076
|
+
let cachedParticipationSnapshot;
|
|
9077
|
+
let cachedRelativeSnapshot;
|
|
9078
|
+
const snapshot = {
|
|
9079
|
+
candle,
|
|
9080
|
+
prevCandle,
|
|
9081
|
+
raw: {
|
|
9082
|
+
trend: {
|
|
9083
|
+
maFast: baseResult.maFast,
|
|
9084
|
+
maMedium: baseResult.maMedium,
|
|
9085
|
+
maSlow: baseResult.maSlow
|
|
9086
|
+
},
|
|
9087
|
+
volatility: {
|
|
9088
|
+
atr: atr2,
|
|
9089
|
+
atrPct: toNullable(baseResult.atrPct),
|
|
9090
|
+
bbUpper: baseResult.bbUpper,
|
|
9091
|
+
bbMiddle: baseResult.bbMiddle,
|
|
9092
|
+
bbLower: baseResult.bbLower,
|
|
9093
|
+
bbWidthPct
|
|
9094
|
+
},
|
|
9095
|
+
momentum: {
|
|
9096
|
+
macd: toNullable(baseResult.macd),
|
|
9097
|
+
macdSignal: toNullable(baseResult.macdSignal),
|
|
9098
|
+
macdHistogram: toNullable(baseResult.macdHistogram)
|
|
9099
|
+
},
|
|
9100
|
+
volume: {
|
|
9101
|
+
volume: candle.volume,
|
|
9102
|
+
turnover: candle.turnover,
|
|
9103
|
+
obv: baseResult.obv,
|
|
9104
|
+
obvSma: baseResult.smaObv,
|
|
9105
|
+
volume1h: baseResult.volume1h,
|
|
9106
|
+
volume24h: baseResult.volume24h
|
|
9107
|
+
},
|
|
9108
|
+
price: {
|
|
9109
|
+
prevClose: baseResult.prevClose,
|
|
9110
|
+
price1hPct: baseResult.price1hPcnt,
|
|
9111
|
+
price24hPct: baseResult.price24hPcnt,
|
|
9112
|
+
highPrice1h: baseResult.highPrice1h,
|
|
9113
|
+
lowPrice1h: baseResult.lowPrice1h,
|
|
9114
|
+
highPrice24h: baseResult.highPrice24h,
|
|
9115
|
+
lowPrice24h: baseResult.lowPrice24h
|
|
9116
|
+
},
|
|
9117
|
+
levels: {
|
|
9118
|
+
highLevel: baseResult.highLevel,
|
|
9119
|
+
lowLevel: baseResult.lowLevel
|
|
9120
|
+
},
|
|
9121
|
+
crossAsset: {
|
|
9122
|
+
btcCorrelation: baseResult.correlation
|
|
9123
|
+
}
|
|
9124
|
+
},
|
|
9125
|
+
get regime() {
|
|
9126
|
+
return cachedRegimeSnapshot ??= buildRegimeSnapshot();
|
|
9127
|
+
},
|
|
9128
|
+
get structure() {
|
|
9129
|
+
return cachedStructureSnapshot ??= buildStructureSnapshot();
|
|
9130
|
+
},
|
|
9131
|
+
get participation() {
|
|
9132
|
+
return cachedParticipationSnapshot ??= buildParticipationSnapshot();
|
|
9133
|
+
},
|
|
9134
|
+
get relative() {
|
|
9135
|
+
return cachedRelativeSnapshot ??= buildRelativeSnapshot();
|
|
9096
9136
|
}
|
|
9097
9137
|
};
|
|
9098
9138
|
let cachedMtfSnapshot = null;
|
|
@@ -11300,6 +11340,22 @@ var createIndicators = (data, btcData = [], options = {}) => {
|
|
|
11300
11340
|
const last = value[value.length - 1];
|
|
11301
11341
|
return typeof last === "number" ? last : void 0;
|
|
11302
11342
|
},
|
|
11343
|
+
latestNumbers: (key, count) => {
|
|
11344
|
+
const normalizedCount = Number.isFinite(count) ? Math.max(0, Math.trunc(count)) : 0;
|
|
11345
|
+
if (normalizedCount === 0) return [];
|
|
11346
|
+
const buffer = indicatorHistory[key];
|
|
11347
|
+
if (buffer) {
|
|
11348
|
+
const resultSize = Math.min(normalizedCount, buffer.size);
|
|
11349
|
+
const result = new Array(resultSize);
|
|
11350
|
+
const firstOffset = buffer.size - resultSize;
|
|
11351
|
+
for (let index = 0; index < resultSize; index += 1) {
|
|
11352
|
+
result[index] = buffer.values[(buffer.start + firstOffset + index) % ML_BASE_CANDLES_WINDOW];
|
|
11353
|
+
}
|
|
11354
|
+
return result;
|
|
11355
|
+
}
|
|
11356
|
+
const value = getHistoryResult()[key];
|
|
11357
|
+
return Array.isArray(value) ? value.slice(-normalizedCount).filter((item) => typeof item === "number") : [];
|
|
11358
|
+
},
|
|
11303
11359
|
result: () => {
|
|
11304
11360
|
return cloneHistorySnapshot(
|
|
11305
11361
|
getHistoryResult()
|
|
@@ -12127,23 +12183,13 @@ var createTrendlineEngine = (initialCandles, options) => {
|
|
|
12127
12183
|
};
|
|
12128
12184
|
const next = (candle) => {
|
|
12129
12185
|
appendCandle(candle);
|
|
12130
|
-
|
|
12131
|
-
if (opts.capture && result.length === 0 && rawExtremaPoints.length) {
|
|
12132
|
-
rebuildCandidatesLikeBatch();
|
|
12133
|
-
result = buildResult();
|
|
12134
|
-
}
|
|
12135
|
-
return result;
|
|
12186
|
+
return buildResult();
|
|
12136
12187
|
};
|
|
12137
12188
|
const nextMany = (candles) => {
|
|
12138
12189
|
for (const candle of candles) {
|
|
12139
12190
|
appendCandle(candle);
|
|
12140
12191
|
}
|
|
12141
|
-
|
|
12142
|
-
if (opts.capture && result.length === 0 && rawExtremaPoints.length) {
|
|
12143
|
-
rebuildCandidatesLikeBatch();
|
|
12144
|
-
result = buildResult();
|
|
12145
|
-
}
|
|
12146
|
-
return result;
|
|
12192
|
+
return buildResult();
|
|
12147
12193
|
};
|
|
12148
12194
|
const getLines = () => buildResult();
|
|
12149
12195
|
const reset = () => {
|