@tradejs/strategies 2.0.1 → 2.0.2

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.
Files changed (3) hide show
  1. package/dist/index.js +347 -54
  2. package/dist/index.mjs +347 -54
  3. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -16516,7 +16516,7 @@ AdaptiveMomentumRibbon addon:
16516
16516
  - \`quality=4\` additionally allows two narrower continuation pockets: oscillatorStrength >= 1.2 with coin bias conflict, structuralRewardRiskRatio >= 2.2 and volumeRel20 <= 1.2, or Europe-session oscillatorStrength >= 1.5 with effortVsResult <= 120.
16517
16517
  - If signal candle range is available, \`signalRangeAtrRatio\` must be >= 1.05 for live approval; weaker signal candles stay in watch mode.
16518
16518
  - The local deterministic gate approves LONG by default. SHORT stays in watch mode except for separately calibrated market-breadth shock pockets.
16519
- - SHORT breadth-shock approvals use two calibrated pockets: BTC-favored breadth shock, or a neutral shared-context breadth exhaustion pocket with marketBreadth.advancers <= 0 and effortVsResult <= 800.
16519
+ - SHORT watch-mode approvals use three calibrated pockets: BTC-favored breadth shock, neutral shared-context breadth exhaustion with marketBreadth.advancers <= 0 and effortVsResult <= 800, or low-CMC benchmark OI contraction with BTC net flow <= 0.
16520
16520
  - A reference-derivatives rotation pocket can approve q4 when XRP 15m OI 4h change >= 1.6 and TRX 15m OI 4h change <= -0.2. It may override weak signal range and the default SHORT watch mode, but never hard signal invalidation.
16521
16521
  - Non-derivatives approvals are demoted when stopDistanceAtr > 4.5 and breakoutBodyAtr > 2.25, because that combination behaves like a chase entry.
16522
16522
  - All live approvals require a calibrated market-regime floor: tpDistanceAtr >= 2.9, trendAdx >= 15, and benchmarkRelativeStrength1d <= 4 when available.
@@ -16528,11 +16528,14 @@ AdaptiveMomentumRibbon addon:
16528
16528
  `;
16529
16529
  var ADAPTIVE_MOMENTUM_RIBBON_PAYLOAD_PROMPT = `
16530
16530
  - \`payload.additionalIndicators.adaptiveMomentumRibbonContext\` contains a compact signal summary:
16531
- signalOsc / oscillatorStrength / signalRangeAtrRatio / stopDistanceAtr / tpDistanceAtr / breakoutBodyAtr / trendAdx / benchmarkRelativeStrength1d / chaseRiskBlocked / approvalRegimeAllowed / approvalRegimeBlockReasons / channelState / channelExtensionPct / invalidationDistancePct / structuralRewardRiskRatio / coinBiasAligned / btcBiasAligned / targetVsBtcAlpha1h / targetVsBtcAlpha4h / spreadBps / cmcAltLiquidityRegime / cmcFearGreedValueChange7d / cmcBtcDominanceChange24hPct / baseDecisionApproveBias / marketBreadthAdvancers / marketBreadthAdvanceDeclineRatio / marketBreadthReturn / shortBreadthShockPocket / shortBreadthNeutralPocket / referenceDerivativesRotationPocket / referenceXrpOiChangePct4h15m / referenceTrxOiChangePct4h15m / q4TargetAlpha1Allowed / q4ContinuationAllowed / q4ContinuationBlockReasons / q4ContinuationRecoveryAllowed / derivativesDirectionAligned / derivativesRiskFlags / derivativesFundingZScore / deterministicQuality / approvalAllowedNow / approvalBlockReasons / riskAnnotations.
16531
+ signalOsc / oscillatorStrength / signalRangeAtrRatio / stopDistanceAtr / tpDistanceAtr / breakoutBodyAtr / trendAdx / benchmarkRelativeStrength1d / chaseRiskBlocked / approvalRegimeAllowed / approvalRegimeBlockReasons / channelState / channelExtensionPct / invalidationDistancePct / structuralRewardRiskRatio / coinBiasAligned / btcBiasAligned / targetVsBtcAlpha1h / targetVsBtcAlpha4h / spreadBps / cmcAltLiquidityRegime / cmcTotalMarketCapUsd / cmcFearGreedValueChange7d / cmcBtcDominanceChange24hPct / benchmarkOiChangePct24h1h / btcReferenceTradeFlowNetBaseDelta / baseDecisionApproveBias / marketBreadthAdvancers / marketBreadthAdvanceDeclineRatio / marketBreadthReturn / shortBreadthShockPocket / shortBreadthNeutralPocket / shortCmcBenchmarkContractionPocket / referenceDerivativesRotationPocket / referenceXrpOiChangePct4h15m / referenceTrxOiChangePct4h15m / q4TargetAlpha1Allowed / q4ContinuationAllowed / q4ContinuationBlockReasons / q4ContinuationRecoveryAllowed / derivativesDirectionAligned / derivativesRiskFlags / derivativesFundingZScore / deterministicQuality / approvalAllowedNow / approvalBlockReasons / riskAnnotations.
16532
16532
  - Use this context as the primary strategy-specific interpretation instead of re-deriving it only from generic series.
16533
16533
  `;
16534
16534
  var SHORT_BREADTH_SHOCK_MARKET_BREADTH_RETURN_MAX = -0.01;
16535
16535
  var SHORT_BREADTH_NEUTRAL_EFFORT_VS_RESULT_MAX = 800;
16536
+ var SHORT_CMC_TOTAL_MARKET_CAP_USD_MAX = 229e10;
16537
+ var SHORT_BENCHMARK_OI_CHANGE_PCT_24H_1H_MAX = -4;
16538
+ var SHORT_BTC_REFERENCE_TRADE_FLOW_NET_BASE_DELTA_MAX = 0;
16536
16539
  var Q4_TARGET_VS_BTC_ALPHA_1H_MAX = 2.4;
16537
16540
  var REFERENCE_XRP_OI_CHANGE_PCT_4H_15M_MIN = 1.6;
16538
16541
  var REFERENCE_TRX_OI_CHANGE_PCT_4H_15M_MAX = -0.2;
@@ -16745,7 +16748,7 @@ var getDeterministicAdaptiveMomentumRibbonQuality = (context) => {
16745
16748
  return 3;
16746
16749
  }
16747
16750
  if (context.signalDirection === "SHORT") {
16748
- return context.shortBreadthShockPocket || context.shortBreadthNeutralPocket || context.referenceDerivativesRotationPocket ? 4 : 3;
16751
+ return context.shortBreadthShockPocket || context.shortBreadthNeutralPocket || context.shortCmcBenchmarkContractionPocket || context.referenceDerivativesRotationPocket ? 4 : 3;
16749
16752
  }
16750
16753
  if (context.signalDirection === "LONG" && context.cmcAltLiquidityRegime === "btc_favored") {
16751
16754
  return 3;
@@ -16756,12 +16759,12 @@ var getDeterministicAdaptiveMomentumRibbonQuality = (context) => {
16756
16759
  if (causalMomentumLowEffortPocket) {
16757
16760
  return 5;
16758
16761
  }
16762
+ if (context.signalDirection === "LONG" && !context.q4TargetAlpha1Allowed) {
16763
+ return 3;
16764
+ }
16759
16765
  if (context.referenceDerivativesRotationPocket) {
16760
16766
  return 4;
16761
16767
  }
16762
- if (!context.q4TargetAlpha1Allowed) {
16763
- return 3;
16764
- }
16765
16768
  if (context.q4ContinuationRecoveryAllowed) {
16766
16769
  return 4;
16767
16770
  }
@@ -16871,6 +16874,8 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16871
16874
  const gateFeaturesRelative = getRecord(gateFeatures?.relative);
16872
16875
  const gateFeaturesDecisionHints = getRecord(gateFeatures?.decisionHints);
16873
16876
  const baseDerivativesContext = getRecord(baseContext?.derivatives);
16877
+ const baseDerivativesIntervals = getRecord(baseDerivativesContext?.intervals);
16878
+ const baseDerivatives1h = getRecord(baseDerivativesIntervals?.["1h"]);
16874
16879
  const referenceDerivativeContexts = getRecord(
16875
16880
  baseDerivativesContext?.referenceContexts
16876
16881
  );
@@ -16884,6 +16889,11 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16884
16889
  const targetVsBtc = getRecord(relative?.targetVsBtc);
16885
16890
  const cmcGlobal = getRecord(relative?.cmcGlobal);
16886
16891
  const cmcFearGreed = getRecord(relative?.cmcFearGreed);
16892
+ const referenceTradeFlow = getRecord(relative?.referenceTradeFlow);
16893
+ const referenceTradeFlowBySymbol = getRecord(
16894
+ referenceTradeFlow?.tradeFlowBySymbol
16895
+ );
16896
+ const btcReferenceTradeFlow = getRecord(referenceTradeFlowBySymbol?.BTCUSDT);
16887
16897
  const baseMarketBreadth = getRecord(relative?.marketBreadth);
16888
16898
  const structureAcceptance = getRecord(structure?.acceptance);
16889
16899
  const marketContext = getRecord(additional?.marketContext);
@@ -16934,12 +16944,21 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16934
16944
  );
16935
16945
  const referenceDerivativesRotationPocket = referenceXrpOiChangePct4h15m != null && referenceXrpOiChangePct4h15m >= REFERENCE_XRP_OI_CHANGE_PCT_4H_15M_MIN && referenceTrxOiChangePct4h15m != null && referenceTrxOiChangePct4h15m <= REFERENCE_TRX_OI_CHANGE_PCT_4H_15M_MAX;
16936
16946
  const cmcAltLiquidityRegime = typeof cmcGlobal?.altLiquidityRegime === "string" && cmcGlobal.altLiquidityRegime.trim().length > 0 ? cmcGlobal.altLiquidityRegime : null;
16947
+ const cmcTotalMarketCapUsd = toFiniteNumberOrNull(
16948
+ cmcGlobal?.totalMarketCapUsd
16949
+ );
16937
16950
  const cmcFearGreedValueChange7d = toFiniteNumberOrNull(
16938
16951
  cmcFearGreed?.valueChange7d
16939
16952
  );
16940
16953
  const cmcBtcDominanceChange24hPct = toFiniteNumberOrNull(
16941
16954
  cmcGlobal?.btcDominanceChange24hPct
16942
16955
  );
16956
+ const benchmarkOiChangePct24h1h = toFiniteNumberOrNull(
16957
+ baseDerivatives1h?.oiChangePct24h
16958
+ );
16959
+ const btcReferenceTradeFlowNetBaseDelta = toFiniteNumberOrNull(
16960
+ btcReferenceTradeFlow?.netBaseDelta
16961
+ );
16943
16962
  const baseDecisionApproveBias = gateFeaturesDecisionHints?.approveBias === "support" || gateFeaturesDecisionHints?.approveBias === "neutral" || gateFeaturesDecisionHints?.approveBias === "reject" ? gateFeaturesDecisionHints.approveBias : null;
16944
16963
  const marketBreadthAdvanceDeclineRatio = toFiniteNumberOrNull(
16945
16964
  marketBreadth?.advanceDeclineRatio
@@ -16948,6 +16967,7 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16948
16967
  const marketBreadthReturn = toFiniteNumberOrNull(gateFeaturesRelative?.marketBreadthReturn) ?? toFiniteNumberOrNull(marketBreadth?.equalWeightedReturn);
16949
16968
  const shortBreadthShockPocket = signalDirection === "SHORT" && cmcAltLiquidityRegime === "btc_favored" && marketBreadthAdvanceDeclineRatio != null && marketBreadthAdvanceDeclineRatio <= 0 && marketBreadthReturn != null && marketBreadthReturn <= SHORT_BREADTH_SHOCK_MARKET_BREADTH_RETURN_MAX;
16950
16969
  const shortBreadthNeutralPocket = signalDirection === "SHORT" && baseDecisionApproveBias === "neutral" && marketBreadthAdvancers != null && marketBreadthAdvancers <= 0 && marketBreadthReturn != null && marketBreadthReturn <= 0 && isInRange(effortVsResult, 0, SHORT_BREADTH_NEUTRAL_EFFORT_VS_RESULT_MAX);
16970
+ const shortCmcBenchmarkContractionPocket = signalDirection === "SHORT" && cmcTotalMarketCapUsd != null && cmcTotalMarketCapUsd <= SHORT_CMC_TOTAL_MARKET_CAP_USD_MAX && benchmarkOiChangePct24h1h != null && benchmarkOiChangePct24h1h <= SHORT_BENCHMARK_OI_CHANGE_PCT_24H_1H_MAX && btcReferenceTradeFlowNetBaseDelta != null && btcReferenceTradeFlowNetBaseDelta <= SHORT_BTC_REFERENCE_TRADE_FLOW_NET_BASE_DELTA_MAX;
16951
16971
  const q4TargetAlpha1Allowed = targetVsBtcAlpha1h == null || targetVsBtcAlpha1h <= Q4_TARGET_VS_BTC_ALPHA_1H_MAX;
16952
16972
  const q4ContinuationBlockReasons = getQ4ContinuationBlockReasons({
16953
16973
  targetVsBtcAlpha4h,
@@ -17019,7 +17039,7 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
17019
17039
  if (signalDirection === "LONG" && derivativesPressure === "crowded_long" || signalDirection === "SHORT" && derivativesPressure === "crowded_short") {
17020
17040
  riskAnnotations.push("derivatives_pressure_conflict");
17021
17041
  }
17022
- if (signalDirection === "SHORT" && !(shortBreadthShockPocket || shortBreadthNeutralPocket || referenceDerivativesRotationPocket)) {
17042
+ if (signalDirection === "SHORT" && !(shortBreadthShockPocket || shortBreadthNeutralPocket || shortCmcBenchmarkContractionPocket || referenceDerivativesRotationPocket)) {
17023
17043
  approvalBlockReasons.push("short_disabled");
17024
17044
  }
17025
17045
  if (signalDirection === "LONG" && cmcAltLiquidityRegime === "btc_favored") {
@@ -17081,14 +17101,18 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
17081
17101
  spreadBias,
17082
17102
  spreadSeverity,
17083
17103
  cmcAltLiquidityRegime,
17104
+ cmcTotalMarketCapUsd,
17084
17105
  cmcFearGreedValueChange7d,
17085
17106
  cmcBtcDominanceChange24hPct,
17107
+ benchmarkOiChangePct24h1h,
17108
+ btcReferenceTradeFlowNetBaseDelta,
17086
17109
  baseDecisionApproveBias,
17087
17110
  marketBreadthAdvancers,
17088
17111
  marketBreadthAdvanceDeclineRatio,
17089
17112
  marketBreadthReturn,
17090
17113
  shortBreadthShockPocket,
17091
17114
  shortBreadthNeutralPocket,
17115
+ shortCmcBenchmarkContractionPocket,
17092
17116
  referenceDerivativesRotationPocket,
17093
17117
  referenceXrpOiChangePct4h15m,
17094
17118
  referenceTrxOiChangePct4h15m,
@@ -17159,14 +17183,18 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
17159
17183
  spreadBias,
17160
17184
  spreadSeverity,
17161
17185
  cmcAltLiquidityRegime,
17186
+ cmcTotalMarketCapUsd,
17162
17187
  cmcFearGreedValueChange7d,
17163
17188
  cmcBtcDominanceChange24hPct,
17189
+ benchmarkOiChangePct24h1h,
17190
+ btcReferenceTradeFlowNetBaseDelta,
17164
17191
  baseDecisionApproveBias,
17165
17192
  marketBreadthAdvancers,
17166
17193
  marketBreadthAdvanceDeclineRatio,
17167
17194
  marketBreadthReturn,
17168
17195
  shortBreadthShockPocket,
17169
17196
  shortBreadthNeutralPocket,
17197
+ shortCmcBenchmarkContractionPocket,
17170
17198
  referenceDerivativesRotationPocket,
17171
17199
  referenceXrpOiChangePct4h15m,
17172
17200
  referenceTrxOiChangePct4h15m,
@@ -17305,14 +17333,18 @@ Additional AdaptiveMomentumRibbon context:
17305
17333
  - spreadBias=${context.spreadBias ?? "n/a"}
17306
17334
  - spreadSeverity=${context.spreadSeverity ?? "n/a"}
17307
17335
  - cmcAltLiquidityRegime=${context.cmcAltLiquidityRegime ?? "n/a"}
17336
+ - cmcTotalMarketCapUsd=${context.cmcTotalMarketCapUsd?.toFixed?.(0) ?? "n/a"}
17308
17337
  - cmcFearGreedValueChange7d=${context.cmcFearGreedValueChange7d?.toFixed?.(3) ?? "n/a"}
17309
17338
  - cmcBtcDominanceChange24hPct=${context.cmcBtcDominanceChange24hPct?.toFixed?.(3) ?? "n/a"}
17339
+ - benchmarkOiChangePct24h1h=${context.benchmarkOiChangePct24h1h?.toFixed?.(3) ?? "n/a"}
17340
+ - btcReferenceTradeFlowNetBaseDelta=${context.btcReferenceTradeFlowNetBaseDelta?.toFixed?.(3) ?? "n/a"}
17310
17341
  - baseDecisionApproveBias=${context.baseDecisionApproveBias ?? "n/a"}
17311
17342
  - marketBreadthAdvancers=${context.marketBreadthAdvancers?.toFixed?.(0) ?? "n/a"}
17312
17343
  - marketBreadthAdvanceDeclineRatio=${context.marketBreadthAdvanceDeclineRatio?.toFixed?.(3) ?? "n/a"}
17313
17344
  - marketBreadthReturn=${context.marketBreadthReturn?.toFixed?.(5) ?? "n/a"}
17314
17345
  - shortBreadthShockPocket=${context.shortBreadthShockPocket}
17315
17346
  - shortBreadthNeutralPocket=${context.shortBreadthNeutralPocket}
17347
+ - shortCmcBenchmarkContractionPocket=${context.shortCmcBenchmarkContractionPocket}
17316
17348
  - referenceDerivativesRotationPocket=${context.referenceDerivativesRotationPocket}
17317
17349
  - referenceXrpOiChangePct4h15m=${context.referenceXrpOiChangePct4h15m?.toFixed?.(3) ?? "n/a"}
17318
17350
  - referenceTrxOiChangePct4h15m=${context.referenceTrxOiChangePct4h15m?.toFixed?.(3) ?? "n/a"}
@@ -17380,6 +17412,9 @@ var MAX_REFERENCE_SHORT_RECOVERY_ETH_LIQ_IMBALANCE_1H = -0.99;
17380
17412
  var MAX_XRP_SHORT_RECOVERY_BTC_VS_ALT_RETURN_24H = -0.03;
17381
17413
  var MAX_XRP_SHORT_RECOVERY_FUNDING_Z_SCORE_1H = -1.8;
17382
17414
  var MIN_XRP_OI_REJECT_BIAS_BLOCK_15M = 25e7;
17415
+ var MAX_XRP_OI_RECOVERY_BTC_DOMINANCE_PCT = 58.45;
17416
+ var MIN_XRP_OI_RECOVERY_MARKET_BREADTH_SYMBOLS = 27;
17417
+ var MIN_XRP_OI_RECOVERY_BNB_FUNDING_CHANGE_1H = 0;
17383
17418
  var MAX_APPROVAL_RSI = 75;
17384
17419
  var MIN_APPROVAL_BB_WIDTH_RANK_100 = 50;
17385
17420
  var buildAdaptiveTrendChannelGuardrailContext = ({
@@ -17388,6 +17423,7 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17388
17423
  }) => {
17389
17424
  const targetDerivatives1h = baseContext?.derivatives?.intervals?.["1h"];
17390
17425
  const ethDerivatives1h = baseContext?.derivatives?.referenceContexts?.["ETHUSDT"]?.intervals?.["1h"];
17426
+ const bnbDerivativesSummary = baseContext?.derivatives?.referenceContexts?.["BNBUSDT"]?.summary;
17391
17427
  const xrpDerivatives15m = baseContext?.derivatives?.referenceContexts?.["XRPUSDT"]?.intervals?.["15m"];
17392
17428
  const xrpDerivatives1h = baseContext?.derivatives?.referenceContexts?.["XRPUSDT"]?.intervals?.["1h"];
17393
17429
  const targetDerivatives1hStale = targetDerivatives1h?.stale === true;
@@ -17405,10 +17441,17 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17405
17441
  baseContext?.regime?.volatility?.percentiles?.bbWidthRank100
17406
17442
  );
17407
17443
  const trendFollowState = baseContext?.regime?.trend?.trendFollow?.state ?? null;
17444
+ const volatilityState = baseContext?.regime?.volatility?.state ?? null;
17408
17445
  const h4VolatilityState = baseContext?.mtf?.summary?.h4VolatilityState ?? null;
17409
17446
  const benchmarkTrendAlignment = baseContext?.relative?.benchmark?.trendAlignment ?? null;
17410
17447
  const cmcExchangeLiquidityAligned = typeof baseContext?.gateFeatures?.relative?.cmcExchangeLiquidityAligned === "boolean" ? baseContext.gateFeatures.relative.cmcExchangeLiquidityAligned : null;
17411
17448
  const cmcExchangeLiquidityStale = typeof baseContext?.gateFeatures?.relative?.cmcExchangeLiquidityStale === "boolean" ? baseContext.gateFeatures.relative.cmcExchangeLiquidityStale : null;
17449
+ const cmcBtcDominancePct = asFiniteNumber(
17450
+ baseContext?.relative?.cmcGlobal?.btcDominancePct
17451
+ );
17452
+ const marketBreadthSymbolsCount = asFiniteNumber(
17453
+ baseContext?.relative?.marketBreadth?.symbolsCount
17454
+ );
17412
17455
  const baseApproveBias = baseContext?.gateFeatures?.decisionHints?.approveBias ?? null;
17413
17456
  const targetLiqImbalance1h = asFiniteNumber(
17414
17457
  targetDerivatives1h?.liqImbalance
@@ -17419,6 +17462,9 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17419
17462
  const targetLiqTotal1h = asFiniteNumber(targetDerivatives1h?.liqTotal);
17420
17463
  const ethLiqImbalance1h = asFiniteNumber(ethDerivatives1h?.liqImbalance);
17421
17464
  const ethFundingRate1h = asFiniteNumber(ethDerivatives1h?.fundingRate);
17465
+ const bnbFundingChange1h = asFiniteNumber(
17466
+ bnbDerivativesSummary?.fundingChange1h
17467
+ );
17422
17468
  const xrpOpenInterest15m = asFiniteNumber(xrpDerivatives15m?.openInterest);
17423
17469
  const xrpPriceOiDivergenceType = baseContext?.derivatives?.referenceContexts?.["XRPUSDT"]?.summary?.priceOiDivergenceType ?? null;
17424
17470
  const xrpFundingZScore1h = asFiniteNumber(xrpDerivatives1h?.fundingZScore);
@@ -17456,10 +17502,11 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17456
17502
  const xrpBtcShortRecoverySetup = direction === "SHORT" && xrpDerivatives1hStale !== true && xrpPriceOiDivergenceType === "price_down_oi_up" && btcVsAltReturn24h != null && btcVsAltReturn24h <= MAX_XRP_SHORT_RECOVERY_BTC_VS_ALT_RETURN_24H && xrpFundingZScore1h != null && xrpFundingZScore1h <= MAX_XRP_SHORT_RECOVERY_FUNDING_Z_SCORE_1H;
17457
17503
  const xrpEthShortRecoverySetup = direction === "SHORT" && xrpDerivatives1hStale !== true && ethDerivatives1hStale !== true && xrpPriceOiDivergenceType === "price_down_oi_up" && xrpFundingZScore1h != null && xrpFundingZScore1h <= MAX_XRP_SHORT_RECOVERY_FUNDING_Z_SCORE_1H && ethLiqImbalance1h != null && ethLiqImbalance1h <= MAX_REFERENCE_SHORT_RECOVERY_ETH_LIQ_IMBALANCE_1H;
17458
17504
  const xrpShortRecoverySetup = xrpBtcShortRecoverySetup || xrpEthShortRecoverySetup;
17459
- if (xrpOpenInterest15m != null && xrpOpenInterest15m >= MIN_XRP_OI_REJECT_BIAS_BLOCK_15M && baseApproveBias === "reject" && !xrpShortRecoverySetup) {
17505
+ const xrpOiReferenceRecoverySetup = xrpOpenInterest15m != null && xrpOpenInterest15m >= MIN_XRP_OI_REJECT_BIAS_BLOCK_15M && baseApproveBias === "reject" && volatilityState === "expanded" && cmcBtcDominancePct != null && cmcBtcDominancePct <= MAX_XRP_OI_RECOVERY_BTC_DOMINANCE_PCT && marketBreadthSymbolsCount != null && marketBreadthSymbolsCount >= MIN_XRP_OI_RECOVERY_MARKET_BREADTH_SYMBOLS && bnbFundingChange1h != null && bnbFundingChange1h >= MIN_XRP_OI_RECOVERY_BNB_FUNDING_CHANGE_1H;
17506
+ if (xrpOpenInterest15m != null && xrpOpenInterest15m >= MIN_XRP_OI_REJECT_BIAS_BLOCK_15M && baseApproveBias === "reject" && !xrpShortRecoverySetup && !xrpOiReferenceRecoverySetup) {
17460
17507
  hardBlockReasons.push("xrp_oi_reject_bias");
17461
17508
  }
17462
- const approvalSetup = longApprovalSetup || xrpShortRecoverySetup;
17509
+ const approvalSetup = longApprovalSetup || xrpShortRecoverySetup || xrpOiReferenceRecoverySetup;
17463
17510
  const highConfidenceSetup = longApprovalSetup && breakoutDistancePct >= MIN_HIGH_CONFIDENCE_BREAKOUT_DISTANCE_PCT && channelWidthPct >= MIN_HIGH_CONFIDENCE_CHANNEL_WIDTH_PCT;
17464
17511
  let deterministicQuality = 3;
17465
17512
  if (hardBlockReasons.length > 0) {
@@ -17517,15 +17564,19 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17517
17564
  rsi,
17518
17565
  bbWidthRank100,
17519
17566
  trendFollowState,
17567
+ volatilityState,
17520
17568
  h4VolatilityState,
17521
17569
  benchmarkTrendAlignment,
17522
17570
  cmcExchangeLiquidityAligned,
17523
17571
  cmcExchangeLiquidityStale,
17572
+ cmcBtcDominancePct,
17573
+ marketBreadthSymbolsCount,
17524
17574
  targetLiqImbalance1h,
17525
17575
  targetLiqSpikeRatio1h,
17526
17576
  targetLiqTotal1h,
17527
17577
  ethLiqImbalance1h,
17528
17578
  ethFundingRate1h,
17579
+ bnbFundingChange1h,
17529
17580
  xrpOpenInterest15m,
17530
17581
  xrpPriceOiDivergenceType,
17531
17582
  xrpFundingZScore1h,
@@ -17601,13 +17652,17 @@ Additional AdaptiveTrendChannel context:
17601
17652
  - rsi=${String(context.rsi ?? "n/a")}
17602
17653
  - bbWidthRank100=${String(context.bbWidthRank100 ?? "n/a")}
17603
17654
  - trendFollowState=${context.trendFollowState ?? "n/a"}
17655
+ - volatilityState=${context.volatilityState ?? "n/a"}
17604
17656
  - h4VolatilityState=${context.h4VolatilityState ?? "n/a"}
17605
17657
  - benchmarkTrendAlignment=${context.benchmarkTrendAlignment ?? "n/a"}
17658
+ - cmcBtcDominancePct=${String(context.cmcBtcDominancePct ?? "n/a")}
17659
+ - marketBreadthSymbolsCount=${String(context.marketBreadthSymbolsCount ?? "n/a")}
17606
17660
  - targetLiqImbalance1h=${String(context.targetLiqImbalance1h ?? "n/a")}
17607
17661
  - targetLiqSpikeRatio1h=${String(context.targetLiqSpikeRatio1h ?? "n/a")}
17608
17662
  - targetLiqTotal1h=${String(context.targetLiqTotal1h ?? "n/a")}
17609
17663
  - ethLiqImbalance1h=${String(context.ethLiqImbalance1h ?? "n/a")}
17610
17664
  - ethFundingRate1h=${String(context.ethFundingRate1h ?? "n/a")}
17665
+ - bnbFundingChange1h=${String(context.bnbFundingChange1h ?? "n/a")}
17611
17666
  - xrpOpenInterest15m=${String(context.xrpOpenInterest15m ?? "n/a")}
17612
17667
  - xrpPriceOiDivergenceType=${context.xrpPriceOiDivergenceType ?? "n/a"}
17613
17668
  - xrpFundingZScore1h=${String(context.xrpFundingZScore1h ?? "n/a")}
@@ -17625,7 +17680,7 @@ Interpretation rules for AdaptiveTrendChannel:
17625
17680
  - The centerline is the adaptive rail; floor/roof are volatility-scaled invalidation bands.
17626
17681
  - Prefer flips with reasonable distance from the centerline and confirmation from shared market context.
17627
17682
  - Thin participation, missing shared-context confirmation, or missing liquidation-shock recovery evidence should downgrade the setup.
17628
- - A high-XRP-OI reject bias should remain blocked unless a narrow XRP reference SHORT recovery setup is present.
17683
+ - A high-XRP-OI reject bias should remain blocked unless a narrow XRP reference SHORT recovery setup or expanded CMC/BNB/breadth recovery setup is present.
17629
17684
  - Treat deterministicQuality and approvalAllowedNow as the local normalized gate result.
17630
17685
  `.trim();
17631
17686
  },
@@ -17842,6 +17897,7 @@ var buildEntryStopTargetFigures = ({
17842
17897
  var MFR_CALIBRATED_LONG_TARGET_VS_BTC_RATIO_RETURN_24H_MAX = -3.3;
17843
17898
  var MFR_CALIBRATED_LONG_ETH_VS_BTC_VOLUME_RATIO_MIN = 0.54;
17844
17899
  var MFR_CALIBRATED_LONG_H1_RANGE_POSITION_MAX = 0.08;
17900
+ var MFR_AI_LONG_STOP_DISTANCE_ATR_MIN = 24;
17845
17901
  var getMarketFlushReversalLongReboundPocketFeatures = (baseContext) => ({
17846
17902
  targetVsBtcRatioReturn24h: toFiniteNumberOrNull2(
17847
17903
  baseContext?.relative?.targetVsBtc?.ratioReturn24h
@@ -17859,6 +17915,21 @@ var isMarketFlushReversalCalibratedLongReboundPocket = ({
17859
17915
  ethVsBtcVolumeRatio,
17860
17916
  h1RangePosition
17861
17917
  }) => direction === "LONG" && targetVsBtcRatioReturn24h != null && targetVsBtcRatioReturn24h <= MFR_CALIBRATED_LONG_TARGET_VS_BTC_RATIO_RETURN_24H_MAX && (ethVsBtcVolumeRatio != null && ethVsBtcVolumeRatio >= MFR_CALIBRATED_LONG_ETH_VS_BTC_VOLUME_RATIO_MIN || h1RangePosition != null && h1RangePosition <= MFR_CALIBRATED_LONG_H1_RANGE_POSITION_MAX);
17918
+ var getMarketFlushReversalAiLongPocketFeatures = (baseContext) => ({
17919
+ stopDistanceAtr: toFiniteNumberOrNull2(
17920
+ baseContext?.gateFeatures?.setup?.stopDistanceAtr
17921
+ ),
17922
+ cmcIndexRegime: baseContext?.relative?.cmcIndexes?.indexRegime ?? null,
17923
+ cmcIndexStale: typeof baseContext?.relative?.cmcIndexes?.stale === "boolean" ? baseContext.relative.cmcIndexes.stale : null,
17924
+ rsiState: baseContext?.regime?.momentum?.rsiState ?? null
17925
+ });
17926
+ var isMarketFlushReversalValidatedAiLongPocket = ({
17927
+ direction,
17928
+ stopDistanceAtr,
17929
+ cmcIndexRegime,
17930
+ cmcIndexStale,
17931
+ rsiState
17932
+ }) => direction === "LONG" && stopDistanceAtr != null && stopDistanceAtr >= MFR_AI_LONG_STOP_DISTANCE_ATR_MIN && cmcIndexRegime === "risk_off" && cmcIndexStale === false && rsiState === "oversold";
17862
17933
 
17863
17934
  // src/MarketFlushReversal/guardrails.ts
17864
17935
  var toFiniteNumberOrNull3 = (value) => {
@@ -17948,6 +18019,12 @@ var buildMarketFlushReversalGuardrailContext = ({
17948
18019
  direction
17949
18020
  });
17950
18021
  const { targetVsBtcRatioReturn24h, ethVsBtcVolumeRatio, h1RangePosition } = longReboundPocketFeatures;
18022
+ const aiLongPocketFeatures = getMarketFlushReversalAiLongPocketFeatures(baseContext);
18023
+ const validatedAiLongPocket = isMarketFlushReversalValidatedAiLongPocket({
18024
+ ...aiLongPocketFeatures,
18025
+ direction
18026
+ });
18027
+ const { stopDistanceAtr, cmcIndexRegime, cmcIndexStale, rsiState } = aiLongPocketFeatures;
17951
18028
  const approvalBlockReasons = [];
17952
18029
  const riskAnnotations = [];
17953
18030
  if (direction == null) approvalBlockReasons.push("missing_direction");
@@ -17958,22 +18035,22 @@ var buildMarketFlushReversalGuardrailContext = ({
17958
18035
  approvalBlockReasons.push("local_participation_not_confirmed");
17959
18036
  }
17960
18037
  if (!marketContextAvailable) {
17961
- approvalBlockReasons.push("missing_broad_market_derivatives");
18038
+ riskAnnotations.push("missing_broad_market_derivatives");
17962
18039
  }
17963
18040
  if (marketRiskFlags.includes("stale_derivatives")) {
17964
- approvalBlockReasons.push("stale_broad_market_derivatives");
18041
+ riskAnnotations.push("stale_broad_market_derivatives");
17965
18042
  }
17966
18043
  if (marketContextAvailable && broadMarketFlushDirection == null) {
17967
- approvalBlockReasons.push("no_broad_market_flush");
18044
+ riskAnnotations.push("no_broad_market_flush");
17968
18045
  }
17969
18046
  if (direction != null && broadMarketFlushDirection != null && broadMarketFlushDirection !== direction) {
17970
- approvalBlockReasons.push("broad_market_flush_direction_mismatch");
18047
+ riskAnnotations.push("broad_market_flush_direction_mismatch");
17971
18048
  }
17972
18049
  if (direction === "SHORT") {
17973
18050
  approvalBlockReasons.push("short_flush_rebound_pocket_not_validated");
17974
18051
  }
17975
- if (direction === "LONG" && !calibratedLongRebound) {
17976
- approvalBlockReasons.push("calibrated_long_rebound_missing");
18052
+ if (direction === "LONG" && !validatedAiLongPocket) {
18053
+ approvalBlockReasons.push("validated_long_ai_pocket_missing");
17977
18054
  }
17978
18055
  if (signalContext.marketFlushConfirmed !== true) {
17979
18056
  riskAnnotations.push("market_flush_not_available_at_core_time");
@@ -17997,7 +18074,12 @@ var buildMarketFlushReversalGuardrailContext = ({
17997
18074
  targetVsBtcRatioReturn24h,
17998
18075
  ethVsBtcVolumeRatio,
17999
18076
  h1RangePosition,
18000
- calibratedLongRebound
18077
+ calibratedLongRebound,
18078
+ stopDistanceAtr,
18079
+ cmcIndexRegime,
18080
+ cmcIndexStale,
18081
+ rsiState,
18082
+ validatedAiLongPocket
18001
18083
  };
18002
18084
  return {
18003
18085
  ...signalContext,
@@ -18096,6 +18178,11 @@ Additional Market Flush Reversal context:
18096
18178
  - ethVsBtcVolumeRatio=${String(context.marketFlushReversalGateFeatures.ethVsBtcVolumeRatio ?? "n/a")}
18097
18179
  - h1RangePosition=${String(context.marketFlushReversalGateFeatures.h1RangePosition ?? "n/a")}
18098
18180
  - calibratedLongRebound=${String(context.marketFlushReversalGateFeatures.calibratedLongRebound)}
18181
+ - stopDistanceAtr=${String(context.marketFlushReversalGateFeatures.stopDistanceAtr ?? "n/a")}
18182
+ - cmcIndexRegime=${context.marketFlushReversalGateFeatures.cmcIndexRegime ?? "n/a"}
18183
+ - cmcIndexStale=${String(context.marketFlushReversalGateFeatures.cmcIndexStale ?? "n/a")}
18184
+ - rsiState=${context.marketFlushReversalGateFeatures.rsiState ?? "n/a"}
18185
+ - validatedAiLongPocket=${String(context.marketFlushReversalGateFeatures.validatedAiLongPocket)}
18099
18186
  - approvalAllowedNow=${String(context.approvalAllowedNow)}
18100
18187
  - deterministicQuality=${String(context.deterministicQuality)}
18101
18188
  - approvalBlockReasons=${context.approvalBlockReasons.join(",") || "none"}
@@ -18208,6 +18295,7 @@ var buildDoubleTapGateFeatures = ({
18208
18295
  defaultApprovalAllowed,
18209
18296
  q4AltDispersionOk,
18210
18297
  q4DerivativesCmcRiskOk,
18298
+ q4DerivativesDirectionSessionOk,
18211
18299
  strictMomentumApproved,
18212
18300
  strictMomentumRoc1dOk
18213
18301
  }) => {
@@ -18230,6 +18318,7 @@ var buildDoubleTapGateFeatures = ({
18230
18318
  q4AltDispersionOk,
18231
18319
  q4DerivativesPocket,
18232
18320
  q4DerivativesCmcRiskOk,
18321
+ q4DerivativesDirectionSessionOk,
18233
18322
  strictMomentumApproved,
18234
18323
  strictMomentumRoc1dOk
18235
18324
  };
@@ -18408,7 +18497,8 @@ var buildDoubleTapAiContext = (payload) => {
18408
18497
  const q4CmcApproval = legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && baseIndicatorCandidate && cmcBtcDominanceChange24hPct != null && cmcBtcDominanceChange24hPct > Q4_CMC_BTC_DOMINANCE_CHANGE_MIN && cmcBtcDominanceChange24hPct <= Q4_CMC_BTC_DOMINANCE_CHANGE_MAX && altDispersion24h != null && altDispersion24h < Q4_ALT_DISPERSION_24H_MAX;
18409
18498
  const q4DerivativesBadCmcPocket = btcVsAltReturn24h != null && cmc20ToCmc100RatioChange24hPct != null && btcVsAltReturn24h <= Q4_DERIVATIVES_BAD_BTC_VS_ALT_RETURN_24H_MAX && cmc20ToCmc100RatioChange24hPct <= Q4_DERIVATIVES_BAD_CMC20_TO_CMC100_CHANGE_24H_MAX;
18410
18499
  const q4DerivativesPocket = baseContextAvailable && btcVsAltReturn24h != null && ethCrowdingPersistenceBars != null && solFundingZScore15m != null && btcVsAltReturn24h <= Q4_DERIVATIVES_BTC_VS_ALT_RETURN_24H_MAX && ethCrowdingPersistenceBars >= Q4_DERIVATIVES_ETH_CROWDING_PERSISTENCE_MIN && solFundingZScore15m <= Q4_DERIVATIVES_SOL_FUNDING_Z_SCORE_15M_MAX;
18411
- const q4DerivativesApproval = q4DerivativesPocket && !q4DerivativesBadCmcPocket;
18500
+ const q4DerivativesDirectionSessionOk = q4DerivativesPocket ? signalDirection === "LONG" ? primarySession === "europe" : signalDirection === "SHORT" ? true : false : null;
18501
+ const q4DerivativesApproval = q4DerivativesPocket && q4DerivativesDirectionSessionOk === true && !q4DerivativesBadCmcPocket;
18412
18502
  const softBlockReasons = [
18413
18503
  ...legacyShapeCandidate && sessionWindowPhase !== "active" ? ["inactive_session_window"] : [],
18414
18504
  ...legacyShapeCandidate && (executionScore == null || executionScore < MIN_EXECUTION_SCORE_FOR_AI_GATE) ? ["low_or_missing_execution_score"] : [],
@@ -18421,7 +18511,9 @@ var buildDoubleTapAiContext = (payload) => {
18421
18511
  ...legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && cmcBtcDominanceChange24hPct != null && (cmcBtcDominanceChange24hPct <= Q4_CMC_BTC_DOMINANCE_CHANGE_MIN || cmcBtcDominanceChange24hPct > Q4_CMC_BTC_DOMINANCE_CHANGE_MAX) ? ["cmc_btc_dominance_change_outside_band"] : [],
18422
18512
  ...legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && cmcBtcDominanceChange24hPct != null && cmcBtcDominanceChange24hPct > Q4_CMC_BTC_DOMINANCE_CHANGE_MIN && cmcBtcDominanceChange24hPct <= Q4_CMC_BTC_DOMINANCE_CHANGE_MAX && altDispersion24h == null ? ["missing_alt_dispersion_24h_for_q4"] : [],
18423
18513
  ...legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && altDispersion24h != null && altDispersion24h >= Q4_ALT_DISPERSION_24H_MAX ? ["alt_dispersion_24h_too_high_for_q4"] : [],
18424
- ...q4CmcApproval ? ["legacy_q4_structural_observation_only"] : []
18514
+ ...q4CmcApproval ? ["legacy_q4_structural_observation_only"] : [],
18515
+ ...q4DerivativesPocket && signalDirection === "LONG" && q4DerivativesDirectionSessionOk === false ? ["long_q4_derivatives_outside_europe_session"] : [],
18516
+ ...q4DerivativesPocket && signalDirection == null ? ["missing_signal_direction_for_q4_derivatives"] : []
18425
18517
  ];
18426
18518
  const highPrecisionApprovalBlocked = legacyHighPrecisionShapeCandidate && !highPrecisionCmcApproval && !q4DerivativesApproval;
18427
18519
  const q4DerivativesApprovalBlocked = q4DerivativesPocket && !q4DerivativesApproval && !highPrecisionCmcApproval;
@@ -18457,6 +18549,7 @@ var buildDoubleTapAiContext = (payload) => {
18457
18549
  defaultApprovalAllowed,
18458
18550
  q4AltDispersionOk: altDispersion24h == null ? null : altDispersion24h < Q4_ALT_DISPERSION_24H_MAX,
18459
18551
  q4DerivativesCmcRiskOk: btcVsAltReturn24h == null || cmc20ToCmc100RatioChange24hPct == null ? null : !q4DerivativesBadCmcPocket,
18552
+ q4DerivativesDirectionSessionOk,
18460
18553
  strictMomentumApproved: strictMomentumApprovalAllowedNow,
18461
18554
  strictMomentumRoc1dOk
18462
18555
  });
@@ -18490,6 +18583,7 @@ var buildDoubleTapAiContext = (payload) => {
18490
18583
  ethCrowdingPersistenceBars,
18491
18584
  solFundingZScore15m,
18492
18585
  altDispersion24h,
18586
+ q4DerivativesDirectionSessionOk,
18493
18587
  doubleTapGateFeatures,
18494
18588
  structuralHardBlockReasons,
18495
18589
  softBlockReasons,
@@ -18594,6 +18688,7 @@ Additional DoubleTap context:
18594
18688
  - doubleTapGateQ4AltDispersionOk=${String(context.doubleTapGateFeatures.q4AltDispersionOk ?? "n/a")}
18595
18689
  - doubleTapGateQ4DerivativesPocket=${String(context.doubleTapGateFeatures.q4DerivativesPocket)}
18596
18690
  - doubleTapGateQ4DerivativesCmcRiskOk=${String(context.doubleTapGateFeatures.q4DerivativesCmcRiskOk ?? "n/a")}
18691
+ - doubleTapGateQ4DerivativesDirectionSessionOk=${String(context.doubleTapGateFeatures.q4DerivativesDirectionSessionOk ?? "n/a")}
18597
18692
  - doubleTapGateStrictMomentumApproved=${String(context.doubleTapGateFeatures.strictMomentumApproved)}
18598
18693
  - doubleTapGateStrictMomentumRoc1dOk=${String(context.doubleTapGateFeatures.strictMomentumRoc1dOk ?? "n/a")}
18599
18694
  - deterministicQuality=${String(context.deterministicQuality)}
@@ -18611,7 +18706,7 @@ Interpretation rules for DoubleTap:
18611
18706
  - Treat deterministicQuality and approvalAllowedNow as the normalized local gate result.
18612
18707
  - Local q5 approval needs the high-precision pocket plus active session window, execution score >= 35, lowTouchCount20 >= 1, aligned volume structure, no benchmark conflict, and CMC alt volume change <= 0.5.
18613
18708
  - The legacy structural q4 CMC pocket is retained only as observation context and should not be treated as local approval.
18614
- - Local q4 approval comes from the derivatives reference pocket: BTC underperforms alts by at least 0.9%, ETH crowding persistence >= 140, SOL 15m funding z-score <= 0.2, unless BTC underperforms alts by at least 1.4% while CMC20/CMC100 ratio change <= -0.0007.
18709
+ - Local q4 approval comes from the derivatives reference pocket: BTC underperforms alts by at least 0.9%, ETH crowding persistence >= 140, SOL 15m funding z-score <= 0.2, unless BTC underperforms alts by at least 1.4% while CMC20/CMC100 ratio change <= -0.0007; LONG q4 derivatives approval additionally requires the Europe session, while SHORT q4 derivatives approval has no session-side restriction.
18615
18710
  - Main local approval additionally needs strict momentum confirmation with ROC1D >= -5.25 for q5 approval; the derivatives reference q4 pocket is already momentum/positioning filtered and does not require that ROC gate.
18616
18711
  - A good long has two comparable lows and a clean close above the neckline.
18617
18712
  - A good short has two comparable highs and a clean close below the neckline.
@@ -18695,6 +18790,8 @@ var MAX_APPROVAL_PRICE_DISTANCE_TO_MA_SLOW_ATR = 1.2;
18695
18790
  var MIN_APPROVAL_ACTIVE_LIQUIDITY_ZONES = 1;
18696
18791
  var MAX_DERIVATIVES_RISK_OFF_ALT_BASKET_RETURN_24H = -0.035;
18697
18792
  var MAX_DERIVATIVES_RISK_OFF_TRX_OI_CHANGE_PCT_4H = -1.8;
18793
+ var MIN_BENCHMARK_FLOW_BUY_PRESSURE_PCT = 0.61;
18794
+ var MIN_BENCHMARK_OI_ACCELERATION = 0.55;
18698
18795
  var Q4_APPROVAL_ATR_RANK_BUCKETS = /* @__PURE__ */ new Set(["high", "extreme"]);
18699
18796
  var buildLiquidityTailsGateFeatures = ({
18700
18797
  signalContext,
@@ -18799,10 +18896,17 @@ var buildLiquidityTailsGuardrailContext = ({
18799
18896
  const flushSupport = direction === "LONG" ? derivativesRiskFlags.includes("short_liquidation_spike") || derivativesPressure === "short_flush" : direction === "SHORT" ? derivativesRiskFlags.includes("long_liquidation_spike") || derivativesPressure === "long_flush" : false;
18800
18897
  const directionalCrowding = direction === "LONG" ? derivativesRiskFlags.includes("crowded_long") : direction === "SHORT" ? derivativesRiskFlags.includes("crowded_short") : false;
18801
18898
  const derivativesRiskOffLongRecoveryPocket = direction === "LONG" && cmcFearGreedValue != null && cmcFearGreedValue <= MAX_APPROVAL_CMC_FEAR_GREED_VALUE && altBasketReturn24h != null && altBasketReturn24h <= MAX_DERIVATIVES_RISK_OFF_ALT_BASKET_RETURN_24H && referenceTrx1hStale === false && referenceTrx1hOiChangePct4h != null && referenceTrx1hOiChangePct4h <= MAX_DERIVATIVES_RISK_OFF_TRX_OI_CHANGE_PCT_4H;
18802
- if (derivativesDirectionAligned === true && !flushSupport && !derivativesRiskOffLongRecoveryPocket) {
18899
+ const referenceTradeFlowBuyPressurePct = asFiniteNumber2(
18900
+ baseContext?.gateFeatures?.participation?.referenceTradeFlowBuyPressurePct
18901
+ );
18902
+ const benchmarkOiAcceleration = asFiniteNumber2(
18903
+ derivativesSummary?.oiAcceleration
18904
+ );
18905
+ const benchmarkFlowOiExpansionRecoveryPocket = (direction === "LONG" || direction === "SHORT") && q4AtrRankEligible && referenceTradeFlowBuyPressurePct != null && referenceTradeFlowBuyPressurePct >= MIN_BENCHMARK_FLOW_BUY_PRESSURE_PCT && benchmarkOiAcceleration != null && benchmarkOiAcceleration >= MIN_BENCHMARK_OI_ACCELERATION;
18906
+ if (derivativesDirectionAligned === true && !flushSupport && !derivativesRiskOffLongRecoveryPocket && !benchmarkFlowOiExpansionRecoveryPocket) {
18803
18907
  hardBlockReasons.push("derivatives_reversal_aligned");
18804
18908
  }
18805
- if (derivativesDirectionAligned === false && !flushSupport && !derivativesRiskOffLongRecoveryPocket) {
18909
+ if (derivativesDirectionAligned === false && !flushSupport && !derivativesRiskOffLongRecoveryPocket && !benchmarkFlowOiExpansionRecoveryPocket) {
18806
18910
  hardBlockReasons.push("derivatives_reversal_conflict");
18807
18911
  }
18808
18912
  if (volumeRel20 != null && volumeRel20 < 0.75) {
@@ -18892,6 +18996,9 @@ var buildLiquidityTailsGuardrailContext = ({
18892
18996
  softBlockReasons.push(...approvalContextReasons);
18893
18997
  }
18894
18998
  }
18999
+ if (deterministicQuality < 4 && hardBlockReasons.length === 0 && benchmarkFlowOiExpansionRecoveryPocket) {
19000
+ deterministicQuality = 4;
19001
+ }
18895
19002
  return {
18896
19003
  ...signalContext,
18897
19004
  baseContextAvailable: Boolean(baseContext),
@@ -18922,6 +19029,7 @@ var buildLiquidityTailsGuardrailContext = ({
18922
19029
  derivativesRiskFlags,
18923
19030
  cadenceUpgradePocket,
18924
19031
  derivativesRiskOffLongRecoveryPocket,
19032
+ benchmarkFlowOiExpansionRecoveryPocket,
18925
19033
  liquidityTailsGateFeatures,
18926
19034
  hardBlockReasons,
18927
19035
  softBlockReasons,
@@ -19092,6 +19200,9 @@ var isDirectionalPriceAboveLevel = ({
19092
19200
  price,
19093
19201
  level
19094
19202
  }) => direction === "LONG" ? price != null && level != null && price > level : direction === "SHORT" ? price != null && level != null && price < level : null;
19203
+ var TRANSITION_LOW_TOUCH_COUNT_MAX = 2;
19204
+ var ETH_REFERENCE_WEAK_NON_STRESS_OI_CHANGE_PCT_24H_MAX = -2.5;
19205
+ var LONG_DIRECT_INDICATOR_SUPPORT_MIN = 2;
19095
19206
  var buildLiquidityZonesGuardrailContext = ({
19096
19207
  signalContext,
19097
19208
  baseContext
@@ -19252,12 +19363,15 @@ var buildLiquidityZonesGuardrailContext = ({
19252
19363
  const isContinuationBreakoutRetest = direction === "LONG" ? breakoutState === "above_high_level" || entryLocation === "breakout" : direction === "SHORT" ? breakoutState === "below_low_level" || entryLocation === "breakdown" : false;
19253
19364
  const hasBaseRetestConfirmation = filterMetric >= 3 && hitCount >= 2 && reactionCloseDistancePct >= 0.08 && retestPenetrationPct <= 90;
19254
19365
  const ethReferenceOiWeakPocket = ethReferenceOiChangePct4h != null && ethReferenceOiChangePct4h <= -0.8;
19255
- const transitionStructureExpansionPocket = hasBaseRetestConfirmation && structureZoneState === "transition" && structureScore != null && structureScore >= 17 && adaptiveChannelFlipDown === false && !directionalCrowding && !ethReferenceOiWeakPocket;
19256
19366
  const ethReferenceStressPocket = hasBaseRetestConfirmation && lowTouchCount20 != null && lowTouchCount20 <= 3 && ethReferenceOiChangePct24h != null && ethReferenceOiChangePct24h <= -5.8 && ethReferenceFundingZScore != null && ethReferenceFundingZScore <= -1.05;
19367
+ const transitionStructureExpansionPocket = hasBaseRetestConfirmation && lowTouchCount20 != null && lowTouchCount20 <= TRANSITION_LOW_TOUCH_COUNT_MAX && structureZoneState === "transition" && structureScore != null && structureScore >= 17 && adaptiveChannelFlipDown === false && !directionalCrowding && !ethReferenceOiWeakPocket;
19257
19368
  const solReferenceStressPocket = hasBaseRetestConfirmation && lowTouchCount20 != null && lowTouchCount20 <= 3 && solReferenceOiChangePct24h != null && solReferenceOiChangePct24h <= -4.2 && solReferenceFundingZScore != null && solReferenceFundingZScore <= -1.2;
19258
19369
  const calibratedExpansionPocket = transitionStructureExpansionPocket || ethReferenceStressPocket || solReferenceStressPocket;
19370
+ const ethReferenceWeakNonStressPocket = ethReferenceOiChangePct24h != null && ethReferenceOiChangePct24h <= ETH_REFERENCE_WEAK_NON_STRESS_OI_CHANGE_PCT_24H_MAX && !ethReferenceStressPocket;
19371
+ const longDirectIndicatorSupportConfirmed = direction === "LONG" ? directIndicatorSupportCount != null && directIndicatorSupportCount >= LONG_DIRECT_INDICATOR_SUPPORT_MIN : null;
19259
19372
  const longRequiresCalibratedExpansion = direction === "LONG" && !calibratedExpansionPocket;
19260
- const approvalDisqualifiedByCalibration = !calibratedExpansionPocket && (longRequiresCalibratedExpansion || isContinuationBreakoutRetest || hasOverextendedVolumeConfirmation || hasIsolatedIndicatorSupport);
19373
+ const longDirectIndicatorSupportMissing = longDirectIndicatorSupportConfirmed === false;
19374
+ const approvalDisqualifiedByCalibration = !calibratedExpansionPocket && (longRequiresCalibratedExpansion || isContinuationBreakoutRetest || hasOverextendedVolumeConfirmation || hasIsolatedIndicatorSupport) || ethReferenceWeakNonStressPocket || longDirectIndicatorSupportMissing;
19261
19375
  if (longRequiresCalibratedExpansion) {
19262
19376
  softBlockReasons.push("long_liquidity_retest_requires_recalibration");
19263
19377
  }
@@ -19270,6 +19384,12 @@ var buildLiquidityZonesGuardrailContext = ({
19270
19384
  if (hasIsolatedIndicatorSupport) {
19271
19385
  softBlockReasons.push("isolated_indicator_support");
19272
19386
  }
19387
+ if (ethReferenceWeakNonStressPocket) {
19388
+ softBlockReasons.push("eth_reference_oi_weak_without_stress");
19389
+ }
19390
+ if (longDirectIndicatorSupportMissing) {
19391
+ softBlockReasons.push("long_direct_indicator_support_missing");
19392
+ }
19273
19393
  const hasLongBreakoutConfirmation = direction === "LONG" && (breakoutState === "below_low_level" || breakoutState === "above_high_level") && reactionCloseDistancePct >= 1 && volumeRel20 != null && volumeRel20 >= 2 && venueSpreadZScore != null && venueSpreadZScore >= 0;
19274
19394
  const hasShortContinuationConfirmation = direction === "SHORT" && hasVolumeConfirmation;
19275
19395
  let deterministicQuality = 3;
@@ -19336,6 +19456,8 @@ var buildLiquidityZonesGuardrailContext = ({
19336
19456
  transitionStructureExpansionPocket,
19337
19457
  ethReferenceStressPocket,
19338
19458
  solReferenceStressPocket,
19459
+ ethReferenceWeakNonStressPocket,
19460
+ longDirectIndicatorSupportConfirmed,
19339
19461
  hardBlockReasons,
19340
19462
  softBlockReasons,
19341
19463
  deterministicQuality,
@@ -19429,6 +19551,7 @@ Additional Liquidity Zones context:
19429
19551
  - obvLevelAligned=${String(context.obvLevelAligned ?? "n/a")}
19430
19552
  - obvSlopeAligned=${String(context.obvSlopeAligned ?? "n/a")}
19431
19553
  - directIndicatorSupportCount=${String(context.directIndicatorSupportCount ?? "n/a")}
19554
+ - longDirectIndicatorSupportConfirmed=${String(context.longDirectIndicatorSupportConfirmed ?? "n/a")}
19432
19555
  - venueSpreadZScore=${String(context.venueSpreadZScore ?? "n/a")}
19433
19556
  - benchmarkTrendAlignment=${context.benchmarkTrendAlignment ?? "n/a"}
19434
19557
  - btcCorrelation=${String(context.btcCorrelation ?? "n/a")}
@@ -19447,6 +19570,7 @@ Additional Liquidity Zones context:
19447
19570
  - transitionStructureExpansionPocket=${String(context.transitionStructureExpansionPocket)}
19448
19571
  - ethReferenceStressPocket=${String(context.ethReferenceStressPocket)}
19449
19572
  - solReferenceStressPocket=${String(context.solReferenceStressPocket)}
19573
+ - ethReferenceWeakNonStressPocket=${String(context.ethReferenceWeakNonStressPocket)}
19450
19574
  - deterministicQuality=${context.deterministicQuality}
19451
19575
  - approvalAllowedNow=${String(context.approvalAllowedNow)}
19452
19576
  - hardBlockReasons=${JSON.stringify(context.hardBlockReasons)}
@@ -19462,6 +19586,8 @@ Interpretation rules for Liquidity Zones:
19462
19586
  - Top-level derivatives context is BTC benchmark evidence; target-symbol derivatives require targetContext/targetDerived.
19463
19587
  - Do not treat derivatives points, rows, or loaded-history size as approval evidence.
19464
19588
  - A calibrated transition-structure pocket, ETH reference stress pocket, or SOL reference stress pocket can approve a structurally valid retest.
19589
+ - LONG approvals need at least two direct MA/MACD/OBV alignments after calibration.
19590
+ - Moderate ETH reference OI weakness blocks approval unless the deeper ETH reference stress pocket is active.
19465
19591
  - Treat deterministicQuality and approvalAllowedNow as the local normalized gate result.
19466
19592
  `.trim();
19467
19593
  },
@@ -19927,6 +20053,16 @@ var getNestedString2 = (value, path) => {
19927
20053
  }
19928
20054
  return typeof current === "string" ? current : null;
19929
20055
  };
20056
+ var getNestedBoolean2 = (value, path) => {
20057
+ let current = value;
20058
+ for (const segment of path) {
20059
+ if (!isRecord2(current)) {
20060
+ return null;
20061
+ }
20062
+ current = current[segment];
20063
+ }
20064
+ return typeof current === "boolean" ? current : null;
20065
+ };
19930
20066
  var isShortBtcOnlyRecoveryLane = (context, baseContext) => {
19931
20067
  const riskFlags = getNestedRecord2(baseContext, [
19932
20068
  "derivatives",
@@ -19951,23 +20087,59 @@ var isShortBtcOnlyRecoveryLane = (context, baseContext) => {
19951
20087
  const biasConflictState = getReverseTrendlineBiasConflictState(context);
19952
20088
  return context.signalDirection === "SHORT" && context.entryTiming === "ready_rejection" && biasConflictState === "btc_only" && context.deterministicRejectionScore != null && context.deterministicRejectionScore >= 6 && context.distance != null && context.distance >= 61 && !hasMissingDerivatives && (derivativesPressure === "long_flush" || derivativesPressure === "short_flush" || derivativesPressure === "crowded_long") && volumeRel20 != null && volumeRel20 >= 1.5 && rangePosition20 != null && rangePosition20 >= 0.2 && rangePosition20 <= 0.7;
19953
20089
  };
20090
+ var hasMissingDerivativesRisk = (baseContext) => {
20091
+ const riskFlags = getNestedRecord2(baseContext, [
20092
+ "derivatives",
20093
+ "summary"
20094
+ ])?.riskFlags;
20095
+ return Array.isArray(riskFlags) && riskFlags.includes("missing_derivatives");
20096
+ };
20097
+ var isExtremeVolatilityRecoveryLane = (context, baseContext) => {
20098
+ if (context.hardBlockReasons.length > 0) {
20099
+ return false;
20100
+ }
20101
+ const primaryIssue = getNestedString2(baseContext, [
20102
+ "gateFeatures",
20103
+ "decisionHints",
20104
+ "primaryIssue"
20105
+ ]);
20106
+ const approveBias = getNestedString2(baseContext, [
20107
+ "gateFeatures",
20108
+ "decisionHints",
20109
+ "approveBias"
20110
+ ]);
20111
+ const upCloseStreak = getNestedNumber2(baseContext, [
20112
+ "regime",
20113
+ "momentum",
20114
+ "upCloseStreak"
20115
+ ]);
20116
+ const adaptiveChannelFlipUp = getNestedBoolean2(baseContext, [
20117
+ "regime",
20118
+ "trend",
20119
+ "adaptiveChannel",
20120
+ "flipUp"
20121
+ ]);
20122
+ const atrPctRank100 = getNestedNumber2(baseContext, [
20123
+ "regime",
20124
+ "volatility",
20125
+ "percentiles",
20126
+ "atrPctRank100"
20127
+ ]);
20128
+ return primaryIssue === "extreme_volatility" && approveBias === "reject" && upCloseStreak != null && upCloseStreak <= 2 && adaptiveChannelFlipUp === false && atrPctRank100 != null && atrPctRank100 <= 99 && !hasMissingDerivativesRisk(baseContext);
20129
+ };
19954
20130
  var getBaseContextQualityPromotion = (context, signal) => {
19955
20131
  const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
19956
20132
  if (!baseContext) {
19957
20133
  return null;
19958
20134
  }
19959
- return isShortBtcOnlyRecoveryLane(context, baseContext) ? 4 : null;
20135
+ return isShortBtcOnlyRecoveryLane(context, baseContext) || isExtremeVolatilityRecoveryLane(context, baseContext) ? 4 : null;
19960
20136
  };
19961
20137
  var getBaseContextApprovalBlockReasons = (context, signal) => {
19962
20138
  const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
19963
20139
  if (!baseContext) {
19964
20140
  return [];
19965
20141
  }
19966
- const riskFlags = getNestedRecord2(baseContext, [
19967
- "derivatives",
19968
- "summary"
19969
- ])?.riskFlags;
19970
- const hasMissingDerivatives = Array.isArray(riskFlags) && riskFlags.includes("missing_derivatives");
20142
+ const hasMissingDerivatives = hasMissingDerivativesRisk(baseContext);
19971
20143
  const volumeRel20 = getNestedNumber2(baseContext, [
19972
20144
  "participation",
19973
20145
  "volume",
@@ -20003,6 +20175,10 @@ var getBaseContextApprovalBlockReasons = (context, signal) => {
20003
20175
  context,
20004
20176
  baseContext
20005
20177
  );
20178
+ const extremeVolatilityRecoveryLane = isExtremeVolatilityRecoveryLane(
20179
+ context,
20180
+ baseContext
20181
+ );
20006
20182
  const reasons = [];
20007
20183
  if (hasMissingDerivatives) {
20008
20184
  reasons.push("missing_derivatives");
@@ -20022,7 +20198,7 @@ var getBaseContextApprovalBlockReasons = (context, signal) => {
20022
20198
  if (context.signalDirection === "SHORT" && biasConflictState === "btc_only" && context.distance != null && context.distance <= 60) {
20023
20199
  reasons.push("short_btc_conflict_too_shallow");
20024
20200
  }
20025
- if (context.signalDirection === "SHORT" && atrPctZScore != null && atrPctZScore >= 2 && !shortBtcOnlyRecoveryLane) {
20201
+ if (context.signalDirection === "SHORT" && atrPctZScore != null && atrPctZScore >= 2 && !shortBtcOnlyRecoveryLane && !extremeVolatilityRecoveryLane) {
20026
20202
  reasons.push("short_extreme_volatility");
20027
20203
  }
20028
20204
  if (context.signalDirection === "SHORT" && rangePosition20 != null && rangePosition20 < 0.2) {
@@ -20043,7 +20219,9 @@ var buildReverseTrendLineGateFeatures = ({
20043
20219
  context,
20044
20220
  signal,
20045
20221
  approvalBlockReasons,
20046
- deterministicRejectionScore
20222
+ deterministicRejectionScore,
20223
+ approvalLane,
20224
+ extremeVolatilityRecoveryPocket
20047
20225
  }) => {
20048
20226
  const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
20049
20227
  const volumeRel20 = getNestedNumber2(baseContext, [
@@ -20077,6 +20255,8 @@ var buildReverseTrendLineGateFeatures = ({
20077
20255
  volatilityState,
20078
20256
  rangePositionState,
20079
20257
  highQualityBouncePocket: context.deterministicQuality >= 4 && approvalBlockReasons.length === 0 && (bounceAcceptance === "rejection" || bounceAcceptance === "follow_through"),
20258
+ extremeVolatilityRecoveryPocket,
20259
+ approvalLane,
20080
20260
  deterministicRejectionScore
20081
20261
  };
20082
20262
  };
@@ -20201,7 +20381,14 @@ var buildReverseTrendlineAiContext = (signal) => {
20201
20381
  },
20202
20382
  signal
20203
20383
  );
20204
- const reverseTrendLineGateFeatures = buildReverseTrendLineGateFeatures({
20384
+ const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
20385
+ const extremeVolatilityRecoveryPocket = baseContext != null ? isExtremeVolatilityRecoveryLane(
20386
+ {
20387
+ hardBlockReasons
20388
+ },
20389
+ baseContext
20390
+ ) : false;
20391
+ const baseReverseTrendLineGateFeatures = buildReverseTrendLineGateFeatures({
20205
20392
  context: {
20206
20393
  ...structural,
20207
20394
  ...timing,
@@ -20210,17 +20397,28 @@ var buildReverseTrendlineAiContext = (signal) => {
20210
20397
  },
20211
20398
  signal,
20212
20399
  approvalBlockReasons,
20213
- deterministicRejectionScore
20400
+ deterministicRejectionScore,
20401
+ approvalLane: "watch",
20402
+ extremeVolatilityRecoveryPocket
20214
20403
  });
20404
+ const highScoreBouncePocket = baseReverseTrendLineGateFeatures.highQualityBouncePocket && deterministicRejectionScore != null && deterministicRejectionScore >= 7;
20405
+ const approvalLane = highScoreBouncePocket ? "high_score_bounce" : extremeVolatilityRecoveryPocket ? "extreme_volatility_recovery" : "watch";
20406
+ const approvalAllowedNow = approvalLane !== "watch";
20407
+ const finalApprovalBlockReasons = !approvalAllowedNow && promotedDeterministicQuality >= 4 && approvalBlockReasons.length === 0 ? [...approvalBlockReasons, "rejection_score_below_gate"] : approvalBlockReasons;
20408
+ const finalDeterministicQuality = approvalAllowedNow ? Math.max(promotedDeterministicQuality, 4) : promotedDeterministicQuality;
20409
+ const reverseTrendLineGateFeatures = {
20410
+ ...baseReverseTrendLineGateFeatures,
20411
+ approvalLane
20412
+ };
20215
20413
  return {
20216
20414
  ...structural,
20217
20415
  ...timing,
20218
20416
  reverseTrendLineGateFeatures,
20219
- deterministicQuality: promotedDeterministicQuality,
20417
+ deterministicQuality: finalDeterministicQuality,
20220
20418
  deterministicRejectionScore,
20221
- approvalAllowedNow: promotedDeterministicQuality >= 4 && approvalBlockReasons.length === 0,
20419
+ approvalAllowedNow,
20222
20420
  hardBlockReasons,
20223
- approvalBlockReasons
20421
+ approvalBlockReasons: finalApprovalBlockReasons
20224
20422
  };
20225
20423
  };
20226
20424
  var withReverseTrendLineGateFeatures = ({
@@ -20265,6 +20463,8 @@ var getHardBlockReasonText2 = (reason) => {
20265
20463
  return "LONG bounce distance sits in a weak mid-distance pocket";
20266
20464
  case "short_follow_through_overrated":
20267
20465
  return "SHORT follow-through bounce is not reliable enough for quality 5";
20466
+ case "rejection_score_below_gate":
20467
+ return "deterministic rejection score is below the current strict gate";
20268
20468
  default:
20269
20469
  return reason;
20270
20470
  }
@@ -20349,6 +20549,8 @@ Additional ReverseTrendLine context:
20349
20549
  - reverseTrendLineGateVolatilityState=${context.reverseTrendLineGateFeatures.volatilityState}
20350
20550
  - reverseTrendLineGateRangePositionState=${context.reverseTrendLineGateFeatures.rangePositionState}
20351
20551
  - reverseTrendLineGateHighQualityBouncePocket=${String(context.reverseTrendLineGateFeatures.highQualityBouncePocket)}
20552
+ - reverseTrendLineGateExtremeVolatilityRecoveryPocket=${String(context.reverseTrendLineGateFeatures.extremeVolatilityRecoveryPocket)}
20553
+ - reverseTrendLineGateApprovalLane=${context.reverseTrendLineGateFeatures.approvalLane}
20352
20554
  - approvalAllowedNow=${context.approvalAllowedNow}
20353
20555
  - hardBlockReasons=${context.hardBlockReasons.join(", ") || "none"}
20354
20556
  - approvalBlockReasons=${context.approvalBlockReasons.join(", ") || "none"}
@@ -20766,6 +20968,7 @@ var buildTrendFollowGateFeatures = ({
20766
20968
  const referenceDerivativesLossBlock = direction === "SHORT" && referenceXrp15mOpenInterest != null && referenceXrp15mOpenInterest >= TREND_FOLLOW_REF_LOSS_XRP_OI_MIN && referenceEthCrowdingPersistenceBars != null && referenceEthCrowdingPersistenceBars >= TREND_FOLLOW_REF_LOSS_ETH_CROWDING_MIN && referenceSol15mFundingZScore != null && referenceSol15mFundingZScore <= TREND_FOLLOW_REF_LOSS_SOL_FUNDING_Z_MAX;
20767
20969
  const referenceDerivativesCadencePocket = !referenceDerivativesLossBlock && (legacyCadencePocket || referenceDerivativesOiCompressionPocket || referenceDerivativesXrpFundingPocket || referenceDerivativesSolFlushPocket);
20768
20970
  const referenceDerivativesOpeningPocket = direction === "SHORT" && minutesFromSessionOpen != null && minutesFromSessionOpen <= TREND_FOLLOW_OPENING_SESSION_MAX_MINUTES_FROM_OPEN && referenceXrp15mOpenInterest != null && referenceXrp15mOpenInterest <= TREND_FOLLOW_OPENING_REF_XRP_OI_MAX && referenceXrp1hOiChangePct1h != null && referenceXrp1hOiChangePct1h >= TREND_FOLLOW_OPENING_REF_XRP_OI_CHANGE_1H_MIN && referenceBnb15mOpenInterest != null && referenceBnb15mOpenInterest >= TREND_FOLLOW_OPENING_REF_BNB_OI_MIN;
20971
+ const referenceDerivativesCleanCadencePocket = referenceDerivativesCadencePocket && !derivativesShortFlushOiPocket;
20769
20972
  const normalVolatilityCadencePocket = marketVolatilityState === TREND_FOLLOW_ALLOWED_VOLATILITY_STATE;
20770
20973
  return {
20771
20974
  setupStopDistanceAtr,
@@ -20808,9 +21011,10 @@ var buildTrendFollowGateFeatures = ({
20808
21011
  referenceDerivativesSolFlushPocket,
20809
21012
  referenceDerivativesLossBlock,
20810
21013
  referenceDerivativesCadencePocket,
21014
+ referenceDerivativesCleanCadencePocket,
20811
21015
  referenceDerivativesOpeningPocket,
20812
21016
  normalVolatilityCadencePocket,
20813
- highQualityCadencePocket: normalVolatilityCadencePocket && (referenceDerivativesCadencePocket || referenceDerivativesOpeningPocket)
21017
+ highQualityCadencePocket: normalVolatilityCadencePocket && referenceDerivativesCleanCadencePocket
20814
21018
  };
20815
21019
  };
20816
21020
  var buildTrendFollowGuardrailContext = ({
@@ -21070,6 +21274,7 @@ Additional TrendFollow context:
21070
21274
  - trendFollowGateReferenceDerivativesSolFlushPocket=${String(context.trendFollowGateFeatures.referenceDerivativesSolFlushPocket)}
21071
21275
  - trendFollowGateReferenceDerivativesLossBlock=${String(context.trendFollowGateFeatures.referenceDerivativesLossBlock)}
21072
21276
  - trendFollowGateReferenceDerivativesCadencePocket=${String(context.trendFollowGateFeatures.referenceDerivativesCadencePocket)}
21277
+ - trendFollowGateReferenceDerivativesCleanCadencePocket=${String(context.trendFollowGateFeatures.referenceDerivativesCleanCadencePocket)}
21073
21278
  - trendFollowGateReferenceDerivativesOpeningPocket=${String(context.trendFollowGateFeatures.referenceDerivativesOpeningPocket)}
21074
21279
  - trendFollowGateNormalVolatilityCadencePocket=${String(context.trendFollowGateFeatures.normalVolatilityCadencePocket)}
21075
21280
  - trendFollowGateHighQualityCadencePocket=${String(context.trendFollowGateFeatures.highQualityCadencePocket)}
@@ -21089,7 +21294,7 @@ Interpretation rules for TrendFollow:
21089
21294
  - The ATR trailing stop is the structural invalidation line and also updates while a position is open.
21090
21295
  - Prefer breakouts aligned with shared market context and backed by participation.
21091
21296
  - Late, thin, crowded, inside-range, adverse-delta, weak-momentum, or weak-volume-structure breakouts should be downgraded even if the pivot cross is valid.
21092
- - Live approval is reserved for calibrated SHORT derivatives pockets in normal volatility: the legacy BTC benchmark long-liquidation flush, guarded extra-reference XRP/SOL/BNB/TRX continuation pockets, or the narrow opening-session XRP/BNB reference pocket; other structurally valid breakouts remain watch mode.
21297
+ - Live approval is reserved for calibrated SHORT extra-reference derivatives pockets in normal volatility when the BTC benchmark short-flush/OI pocket is not active; legacy BTC benchmark flush and opening-session recovery remain watch mode.
21093
21298
  - Treat deterministicQuality and approvalAllowedNow as the local normalized gate result.
21094
21299
  `.trim();
21095
21300
  },
@@ -21126,6 +21331,8 @@ var LONG_BROAD_MARKET_SHORT_FLUSH_PCT_ABOVE_MA20_MIN = 0.95;
21126
21331
  var LONG_BROAD_MARKET_SHORT_FLUSH_BTC_VS_ALT_RETURN_24H_MIN = 0;
21127
21332
  var SHORT_ASIA_LONG_FLUSH_LOW_CMC_FEAR_GREED_MAX = 18;
21128
21333
  var SHORT_ASIA_LONG_FLUSH_ADVANCERS_MAX = 2;
21334
+ var BNB_REFERENCE_OI_CHANGE_PCT_4H_RISK_MIN = 0;
21335
+ var DERIVATIVES_DATA_UNAVAILABLE_STRESS_CMC_FEAR_GREED_MAX = 25;
21129
21336
  var toMtfAlignmentForTrendShift = ({
21130
21337
  direction,
21131
21338
  mtfAlignment
@@ -21393,9 +21600,14 @@ var buildTrendShiftGuardrailContext = ({
21393
21600
  gateRelative?.cmcFearGreedValueChange24h ?? baseCmcFearGreed?.valueChange24h
21394
21601
  );
21395
21602
  const cmcFearGreedStale = gateRelative?.cmcFearGreedStale === true || baseCmcFearGreed?.stale === true;
21603
+ const derivativesDataUnavailable = derivativesRiskFlags.includes("missing_derivatives") || derivativesRiskFlags.includes("stale_derivatives");
21604
+ const derivativesDataUnavailableStressRisk = derivativesDataUnavailable && cmcFearGreedStale !== true && cmcFearGreedValue != null && cmcFearGreedValue <= DERIVATIVES_DATA_UNAVAILABLE_STRESS_CMC_FEAR_GREED_MAX;
21396
21605
  const derivatives1hLiqShort = asFiniteNumber6(
21397
21606
  baseContext?.derivatives?.intervals?.["1h"]?.liqShort
21398
21607
  );
21608
+ const bnbReferenceOiChangePct4h = asFiniteNumber6(
21609
+ baseContext?.derivatives?.referenceContexts?.BNBUSDT?.intervals?.["1h"]?.oiChangePct4h
21610
+ );
21399
21611
  const btcAltRegime = typeof gateRelative?.btcAltRegime === "string" ? gateRelative.btcAltRegime : null;
21400
21612
  const btcAltRegimeStale = gateRelative?.btcAltRegimeStale === true;
21401
21613
  const cmcExchangeLiquidityVolumeChange24hPct = asFiniteNumber6(
@@ -21420,8 +21632,8 @@ var buildTrendShiftGuardrailContext = ({
21420
21632
  const q4LongBreakoutCandidate = signalContext.signalDirection === "LONG" && breakoutState === "above_high_level" && volumeRel20 != null && volumeRel20 >= 1.2 && atrPctZScore != null && atrPctZScore >= 0 && relativeStrength1h != null && relativeStrength1h > -1 && derivativesPressure === "short_flush";
21421
21633
  const q4ShortBreakoutCandidate = signalContext.signalDirection === "SHORT" && breakoutState === "below_low_level" && volumeRel20 != null && volumeRel20 >= 1.2 && atrPctZScore != null && atrPctZScore >= 0 && relativeStrength1h != null && relativeStrength1h < 1 && derivativesPressure === "long_flush";
21422
21634
  const q4ShortAsiaFlushCandidate = signalContext.signalDirection === "SHORT" && derivativesPressure === "neutral" && derivativesFlushSupport && sessionPrimary === "asia" && !sessionIsOverlap && distanceAtrRatio < 0.7 && slopeAbs >= 0.08 && closeVsAvgPctAbs >= 0.12;
21423
- const selectiveNeutralQ4Candidate = hasDerivativesSummary && derivativesPressure === "neutral" && !sessionIsOverlap && (signalContext.signalDirection === "LONG" && sessionPrimary === "europe" && (breakoutState === "above_high_level" || breakoutState === "failed_high_breakout") || signalContext.signalDirection === "SHORT" && (sessionPrimary === "off_hours" || sessionPrimary === "asia") && breakoutState === "below_low_level");
21424
- const shortNeutralBearChannelBreakdownCandidate = signalContext.signalDirection === "SHORT" && breakoutState === "below_low_level" && derivativesPressure === "neutral" && atrPctZScore != null && atrPctZScore >= 0 && atrPctZScore < 1 && adaptiveChannelDirection === "bear";
21635
+ const selectiveNeutralQ4Candidate = hasDerivativesSummary && derivativesPressure === "neutral" && !derivativesDataUnavailableStressRisk && !sessionIsOverlap && (signalContext.signalDirection === "LONG" && sessionPrimary === "europe" && (breakoutState === "above_high_level" || breakoutState === "failed_high_breakout") || signalContext.signalDirection === "SHORT" && (sessionPrimary === "off_hours" || sessionPrimary === "asia") && breakoutState === "below_low_level");
21636
+ const shortNeutralBearChannelBreakdownCandidate = signalContext.signalDirection === "SHORT" && breakoutState === "below_low_level" && derivativesPressure === "neutral" && !derivativesDataUnavailableStressRisk && atrPctZScore != null && atrPctZScore >= 0 && atrPctZScore < 1 && adaptiveChannelDirection === "bear";
21425
21637
  let deterministicQuality = 3;
21426
21638
  if (hardBlockReasons.length > 0) {
21427
21639
  deterministicQuality = signalContext.confirmedFlip ? 2 : 1;
@@ -21489,6 +21701,10 @@ var buildTrendShiftGuardrailContext = ({
21489
21701
  hardBlockReasons.push("us_short_oi_not_expanding");
21490
21702
  }
21491
21703
  }
21704
+ if (deterministicQuality >= 5 && derivativesDataUnavailableStressRisk) {
21705
+ deterministicQuality = 4;
21706
+ hardBlockReasons.push("derivatives_data_unavailable_stress");
21707
+ }
21492
21708
  if (deterministicQuality >= 5 && hasDerivativesSummary && !selectiveNeutralQ4Candidate && !shortNeutralBearChannelBreakdownCandidate && derivativesPressure === "neutral" && !derivativesFlushSupport) {
21493
21709
  deterministicQuality = 4;
21494
21710
  hardBlockReasons.push("neutral_derivatives_pressure");
@@ -21511,6 +21727,7 @@ var buildTrendShiftGuardrailContext = ({
21511
21727
  const shortAsiaLongFlushLowCmcBreadthRisk = signalContext.signalDirection === "SHORT" && sessionPrimary === "asia" && derivativesPressure === "long_flush" && cmcFearGreedStale !== true && marketBreadthStale !== true && cmcFearGreedValue != null && cmcFearGreedValue <= SHORT_ASIA_LONG_FLUSH_LOW_CMC_FEAR_GREED_MAX && marketBreadthAdvancers != null && marketBreadthAdvancers <= SHORT_ASIA_LONG_FLUSH_ADVANCERS_MAX;
21512
21728
  const lowRewardToVolatilityRisk = rewardToVolatility != null && rewardToVolatility < 0.25;
21513
21729
  const defensiveRewardToVolatilityRisk = rewardToVolatility != null && rewardToVolatility >= 0.25 && rewardToVolatility < 8;
21730
+ const bnbReferenceOiExpansionRisk = bnbReferenceOiChangePct4h != null && bnbReferenceOiChangePct4h >= BNB_REFERENCE_OI_CHANGE_PCT_4H_RISK_MIN;
21514
21731
  const longBtcAltRegimeRisk = signalContext.signalDirection === "LONG" && btcAltRegimeStale !== true && (btcAltRegime === "btc_lead" || btcAltRegime === "risk_off");
21515
21732
  const longBroadMarketShortFlushRisk = signalContext.signalDirection === "LONG" && derivativesPressure === "short_flush" && marketBreadthAdvancers != null && marketBreadthAdvancers >= LONG_BROAD_MARKET_SHORT_FLUSH_ADVANCERS_MIN && marketBreadthPctAboveMa20 != null && marketBreadthPctAboveMa20 >= LONG_BROAD_MARKET_SHORT_FLUSH_PCT_ABOVE_MA20_MIN && btcVsAltReturn24h != null && btcVsAltReturn24h >= LONG_BROAD_MARKET_SHORT_FLUSH_BTC_VS_ALT_RETURN_24H_MIN;
21516
21733
  const cmcExchangeLiquidityVolumeChangeRisk = cmcExchangeLiquidityStale !== true && cmcExchangeLiquidityVolumeChange24hPct != null && (cmcExchangeLiquidityVolumeChange24hPct > -0.1 && cmcExchangeLiquidityVolumeChange24hPct < 0 || cmcExchangeLiquidityVolumeChange24hPct >= 0.1 && cmcExchangeLiquidityVolumeChange24hPct < 0.3);
@@ -21562,6 +21779,10 @@ var buildTrendShiftGuardrailContext = ({
21562
21779
  deterministicQuality = 4;
21563
21780
  hardBlockReasons.push("reward_to_volatility_below_defensive_threshold");
21564
21781
  }
21782
+ if (deterministicQuality >= 5 && bnbReferenceOiExpansionRisk) {
21783
+ deterministicQuality = 4;
21784
+ hardBlockReasons.push("bnb_reference_1h_oi4h_expansion_risk");
21785
+ }
21565
21786
  if (deterministicQuality >= 4 && longBtcAltRegimeRisk) {
21566
21787
  deterministicQuality = 4;
21567
21788
  hardBlockReasons.push("long_btc_alt_regime_risk");
@@ -21588,7 +21809,7 @@ var buildTrendShiftGuardrailContext = ({
21588
21809
  const q4UsClosingOiConfirmationRecoveryCandidate = deterministicQuality === 4 && signalContext.confirmedFlip === true && signalContext.flipDistanceOk === true && sessionPrimary === "us" && sessionWindowPhase === "closing" && hardBlockReasons.length > 0 && hardBlockReasons.every(
21589
21810
  (reason) => q4UsClosingOiConfirmationRecoveryAllowedReasons.includes(reason)
21590
21811
  );
21591
- const q4ShortBreadthShockLiquidationRecoveryCandidate = deterministicQuality === 4 && signalContext.signalDirection === "SHORT" && signalContext.confirmedFlip === true && signalContext.flipDistanceOk === true && marketBreadthReturn != null && marketBreadthReturn <= SHORT_BREADTH_SHOCK_MARKET_BREADTH_RETURN_MAX2 && derivatives1hLiqShort != null && derivatives1hLiqShort <= SHORT_BREADTH_SHOCK_1H_LIQ_SHORT_MAX;
21812
+ const q4ShortBreadthShockLiquidationRecoveryCandidate = deterministicQuality === 4 && signalContext.signalDirection === "SHORT" && signalContext.confirmedFlip === true && signalContext.flipDistanceOk === true && hardBlockReasons.length === 0 && !derivativesDataUnavailableStressRisk && marketBreadthReturn != null && marketBreadthReturn <= SHORT_BREADTH_SHOCK_MARKET_BREADTH_RETURN_MAX2 && derivatives1hLiqShort != null && derivatives1hLiqShort <= SHORT_BREADTH_SHOCK_1H_LIQ_SHORT_MAX;
21592
21813
  const q4LongAltLeadershipRecoveryAllowedReasons = [
21593
21814
  "flat_or_mixed_oi",
21594
21815
  "neutral_derivatives_pressure",
@@ -21636,8 +21857,10 @@ var buildTrendShiftGuardrailContext = ({
21636
21857
  shortBullSwingStructureRisk,
21637
21858
  shortLowBollingerWidthRisk,
21638
21859
  shortAsiaLongFlushLowCmcBreadthRisk,
21860
+ derivativesDataUnavailableStressRisk,
21639
21861
  lowRewardToVolatilityRisk,
21640
21862
  defensiveRewardToVolatilityRisk,
21863
+ bnbReferenceOiExpansionRisk,
21641
21864
  longBtcAltRegimeRisk,
21642
21865
  longBroadMarketShortFlushRisk,
21643
21866
  cmcExchangeLiquidityVolumeChangeRisk,
@@ -21662,6 +21885,7 @@ var buildTrendShiftGuardrailContext = ({
21662
21885
  cmcFearGreedValue,
21663
21886
  cmcFearGreedValueChange24h,
21664
21887
  derivatives1hLiqShort,
21888
+ bnbReferenceOiChangePct4h,
21665
21889
  btcAltRegime,
21666
21890
  cmcExchangeLiquidityVolumeChange24hPct,
21667
21891
  trendShiftGateFeatures,
@@ -21729,10 +21953,14 @@ var getTrendShiftGuardrailReasonText = (reason) => {
21729
21953
  return "the SHORT flip is in a narrow Bollinger-width compression pocket that has been less reliable, so keep it in watch mode";
21730
21954
  case "short_asia_long_flush_low_cmc_breadth":
21731
21955
  return "the SHORT flip is selling an Asia-session long flush while CMC fear/greed and market breadth are already in capitulation, so keep it in watch mode";
21956
+ case "derivatives_data_unavailable_stress":
21957
+ return "benchmark derivatives data is missing or stale during CMC stress, so keep the flip in watch mode instead of treating neutral derivatives as confirmation";
21732
21958
  case "low_reward_to_volatility":
21733
21959
  return "the expected reward is too small relative to current volatility after costs, so keep the flip in watch mode";
21734
21960
  case "reward_to_volatility_below_defensive_threshold":
21735
21961
  return "the expected reward is not large enough relative to current volatility for the defensive TrendShift gate after costs";
21962
+ case "bnb_reference_1h_oi4h_expansion_risk":
21963
+ return "BNB reference 1h open interest is expanding over 4h, a historically fragile cross-market state for TrendShift approvals";
21736
21964
  case "long_btc_alt_regime_risk":
21737
21965
  return "the LONG flip is fighting a BTC-led or risk-off alt regime, so keep it in watch mode";
21738
21966
  case "long_broad_market_short_flush_risk":
@@ -21885,8 +22113,11 @@ Additional TrendShift context:
21885
22113
  - defensiveRewardToVolatilityRisk=${String(context.defensiveRewardToVolatilityRisk)}
21886
22114
  - shortBullSwingStructureRisk=${String(context.shortBullSwingStructureRisk)}
21887
22115
  - shortAsiaLongFlushLowCmcBreadthRisk=${String(context.shortAsiaLongFlushLowCmcBreadthRisk)}
22116
+ - derivativesDataUnavailableStressRisk=${String(context.derivativesDataUnavailableStressRisk)}
21888
22117
  - longBtcAltRegimeRisk=${String(context.longBtcAltRegimeRisk)}
21889
22118
  - longBroadMarketShortFlushRisk=${String(context.longBroadMarketShortFlushRisk)}
22119
+ - bnbReferenceOiChangePct4h=${String(context.bnbReferenceOiChangePct4h ?? "n/a")}
22120
+ - bnbReferenceOiExpansionRisk=${String(context.bnbReferenceOiExpansionRisk)}
21890
22121
  - cmcExchangeLiquidityVolumeChangeRisk=${String(context.cmcExchangeLiquidityVolumeChangeRisk)}
21891
22122
  - q4TrendShiftGateFeaturesRecoveryCandidate=${String(context.q4TrendShiftGateFeaturesRecoveryCandidate)}
21892
22123
  - q4UsClosingOiConfirmationRecoveryCandidate=${String(context.q4UsClosingOiConfirmationRecoveryCandidate)}
@@ -21924,12 +22155,14 @@ Interpretation rules for TrendShift:
21924
22155
  - For SHORT, a bullish swing structure is a watch-only warning even when the immediate flip geometry looks q5-strong.
21925
22156
  - For SHORT, a narrow Bollinger-width compression pocket is watch-only even if another q4 recovery condition is present.
21926
22157
  - For SHORT, Asia-session long-flush setups are watch-only when CMC fear/greed and market breadth are already in capitulation.
22158
+ - If benchmark derivatives data is missing or stale while CMC fear/greed is in stress mode, keep the flip in watch mode; neutral/unknown derivatives are not confirmation in that state.
21927
22159
  - The defensive live gate requires rewardToVolatility >= 8 when that field is available.
22160
+ - If BNB reference 1h open interest is expanding over the last 4h, keep TrendShift flips in watch mode; this is a defensive cross-market risk cut, not target-symbol evidence.
21928
22161
  - For LONG, BTC-led or risk-off BTC/alt regime is watch-only even when flip geometry is q5-strong.
21929
22162
  - For LONG, broad-market squeeze clusters are watch-only when breadth is already extreme, BTC is leading alts, and benchmark derivatives show a short flush.
21930
22163
  - If CMC major-exchange liquidity 24h change is in the historically choppy bands (-0.1, 0) or [0.1, 0.3), keep the flip in watch mode.
21931
22164
  - A narrow q4 recovery is allowed during the US closing window only when the sole blocker is missing OI expansion on an otherwise liquidation-supported US-session flush.
21932
- - A narrow SHORT q4 recovery may pass during a market breadth shock only when marketBreadthReturn <= -0.0112952 and 1h liqShort <= 0.208; this does not override the low-Bollinger-width defensive cut.
22165
+ - A narrow SHORT q4 recovery may pass during a market breadth shock only when marketBreadthReturn <= -0.0112952 and 1h liqShort <= 0.208; this does not override existing hard blockers or the low-Bollinger-width defensive cut.
21933
22166
  - A narrow LONG q4 recovery may pass only when alt leadership is clear (btcVsAltReturn24h <= -0.00503054 and btcVsAltReturn1h <= -0.00581403), fear/greed is not falling hard, and the only blockers are the tested OI/benchmark-derivatives or defensive reward-to-volatility blockers.
21934
22167
  - If hardBlockReasons is not empty, explain exactly what is still missing for confirmation.
21935
22168
  `.trim();
@@ -22245,6 +22478,9 @@ var TRENDLINE_PAYLOAD_PROMPT = `
22245
22478
  - It also includes 'atrPct / breakVsAtrRatio / coinMaSpreadPct / btcMaSpreadPct / aggressivePreBreakPressure / strongNearBreakPressure / weakCleanBreak / compressedCleanBreak / weakBtcLedBreak / weakLongFarBreak'.
22246
22479
  - If 'payload.additionalIndicators.baseContext.derivatives' exists, it contains Coinalyze-derived open interest, funding, and liquidation fields for the signal moment; do not treat 'stale' or 'missing_derivatives' as confirmation or conflict.
22247
22480
  `;
22481
+ var MARKET_CONTEXT_PRIMARY_ISSUE = "market_context_against";
22482
+ var MARKET_CONTEXT_TOTAL_MARKET_CAP_USD_MIN = 233e10;
22483
+ var MARKET_CONTEXT_TREND_PERSISTENCE_MAX = 0.77;
22248
22484
  var getRecord2 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
22249
22485
  var getNestedRecord3 = (source, path) => {
22250
22486
  let current = source;
@@ -22320,6 +22556,22 @@ var buildTrendlineContext = (signal) => {
22320
22556
  const volumeStructurePocIndex = toFiniteNumberOrNull5(
22321
22557
  participationVolumeStructure?.pocIndex
22322
22558
  );
22559
+ const gateDecisionHints = getNestedRecord3(baseContext, [
22560
+ "gateFeatures",
22561
+ "decisionHints"
22562
+ ]);
22563
+ const gatePrimaryIssue = typeof gateDecisionHints?.primaryIssue === "string" ? gateDecisionHints.primaryIssue : null;
22564
+ const cmcGlobalContext = getNestedRecord3(baseContext, [
22565
+ "relative",
22566
+ "cmcGlobal"
22567
+ ]);
22568
+ const cmcTotalMarketCapUsd = toFiniteNumberOrNull5(
22569
+ cmcGlobalContext?.totalMarketCapUsd
22570
+ );
22571
+ const trendRegimeContext = getNestedRecord3(baseContext, ["regime", "trend"]);
22572
+ const trendPersistence = toFiniteNumberOrNull5(
22573
+ trendRegimeContext?.persistence
22574
+ );
22323
22575
  const benchmarkTrendAlignment = typeof benchmarkContext?.trendAlignment === "string" ? benchmarkContext.trendAlignment : null;
22324
22576
  const executionContext = getNestedRecord3(baseContext, [
22325
22577
  "relative",
@@ -22371,7 +22623,7 @@ var buildTrendlineContext = (signal) => {
22371
22623
  if (structural.signalDirection === "SHORT" && (entryTiming === "ready_follow_through" || entryTiming === "ready_retest") && (sessionPrimary === "off_hours" || sessionIsOverlap) && !hardBlockReasons.includes("short_session_risk")) {
22372
22624
  hardBlockReasons.push("short_session_risk");
22373
22625
  }
22374
- const deterministicQuality = getDeterministicTrendlineQuality({
22626
+ const baseDeterministicQuality = getDeterministicTrendlineQuality({
22375
22627
  signalDirection: structural.signalDirection,
22376
22628
  clearBreak: structural.clearBreak,
22377
22629
  nearLineNoise: structural.nearLineNoise,
@@ -22386,16 +22638,18 @@ var buildTrendlineContext = (signal) => {
22386
22638
  entryTiming,
22387
22639
  coinMaSpreadPct
22388
22640
  });
22641
+ const marketContextApprovalPocket = gatePrimaryIssue === MARKET_CONTEXT_PRIMARY_ISSUE && cmcTotalMarketCapUsd != null && cmcTotalMarketCapUsd >= MARKET_CONTEXT_TOTAL_MARKET_CAP_USD_MIN && trendPersistence != null && trendPersistence <= MARKET_CONTEXT_TREND_PERSISTENCE_MAX;
22642
+ const deterministicQuality = marketContextApprovalPocket ? 4 : baseDeterministicQuality;
22389
22643
  const maxAllowedQuality = deterministicQuality;
22390
22644
  const longUsLowVolumeCrowdedShortSqueeze = structural.signalDirection === "LONG" && sessionPrimary === "us" && volumeRel20 != null && volumeRel20 < 0.8 && derivativesRiskFlags.includes("crowded_short") && benchmarkTrendAlignment !== "against_benchmark";
22391
22645
  const longHistoricalApprovalPocket = venueSpreadZScore != null && venueSpreadZScore <= -1 || longUsLowVolumeCrowdedShortSqueeze || sessionPrimary !== "europe" && !derivativesRiskFlags.includes("missing_derivatives") && !(structural.breakVsAtrRatio != null && structural.breakVsAtrRatio >= 0.8 && structural.breakVsAtrRatio < 1.2) && volumeRel20 != null && volumeRel20 >= 0.8 && benchmarkTrendAlignment !== "against_benchmark";
22392
- const longHighQualitySessionApproval = deterministicQuality >= 5 && sessionPrimary !== "asia";
22646
+ const longHighQualitySessionApproval = baseDeterministicQuality >= 5 && sessionPrimary !== "asia";
22393
22647
  const longStrongDerivativesAlignedApproval = volumeRel20 != null && volumeRel20 >= 1.5 && derivativesDirectionAligned === true;
22394
- const longModerateRetestLiquidSessionApproval = structural.signalDirection === "LONG" && deterministicQuality === 4 && entryTiming === "ready_retest" && (sessionPrimary === "us" || sessionPrimary === "europe") && volumeRel20 != null && volumeRel20 >= 0.8 && volumeRel20 < 1.5 && benchmarkTrendAlignment !== "against_benchmark" && derivativesDirectionAligned == null && derivativesRiskFlags.length > 0 && !oiNotConfirming;
22648
+ const longModerateRetestLiquidSessionApproval = structural.signalDirection === "LONG" && baseDeterministicQuality === 4 && entryTiming === "ready_retest" && (sessionPrimary === "us" || sessionPrimary === "europe") && volumeRel20 != null && volumeRel20 >= 0.8 && volumeRel20 < 1.5 && benchmarkTrendAlignment !== "against_benchmark" && derivativesDirectionAligned == null && derivativesRiskFlags.length > 0 && !oiNotConfirming;
22395
22649
  const longBaseContextApprovalPocket = structural.signalDirection !== "LONG" || longModerateRetestLiquidSessionApproval || longHistoricalApprovalPocket && (longHighQualitySessionApproval || longStrongDerivativesAlignedApproval);
22396
22650
  const shortThinNeutralBenchmarkRisk = structural.signalDirection === "SHORT" && volumeRel20 != null && volumeRel20 < 0.8 && benchmarkTrendAlignment === "neutral";
22397
- const q4ReferenceOiPocApproval = deterministicQuality === 4 && volumeStructurePocIndex != null && volumeStructurePocIndex >= 5 && ethReferenceOiAcceleration != null && ethReferenceOiAcceleration <= -0.5906;
22398
- const approvalAllowedNow = deterministicQuality >= 4 && longBaseContextApprovalPocket && !shortThinNeutralBenchmarkRisk && (deterministicQuality >= 5 || q4ReferenceOiPocApproval);
22651
+ const q4ReferenceOiPocApproval = baseDeterministicQuality === 4 && volumeStructurePocIndex != null && volumeStructurePocIndex >= 5 && ethReferenceOiAcceleration != null && ethReferenceOiAcceleration <= -0.5906;
22652
+ const approvalAllowedNow = marketContextApprovalPocket;
22399
22653
  const trendLineGateFeatures = buildTrendLineGateFeatures({
22400
22654
  structural,
22401
22655
  entryTiming,
@@ -22431,6 +22685,11 @@ var buildTrendlineContext = (signal) => {
22431
22685
  derivativesRiskFlags,
22432
22686
  ethReferenceOiAcceleration,
22433
22687
  oiNotConfirming,
22688
+ gatePrimaryIssue,
22689
+ cmcTotalMarketCapUsd,
22690
+ trendPersistence,
22691
+ marketContextApprovalPocket,
22692
+ baseDeterministicQuality,
22434
22693
  longUsLowVolumeCrowdedShortSqueeze,
22435
22694
  longHighQualitySessionApproval,
22436
22695
  longStrongDerivativesAlignedApproval,
@@ -22680,6 +22939,11 @@ Additional TrendLine context:
22680
22939
  - trendline.volumeStructurePocIndex=${formatPromptNumber(trendlineContext.volumeStructurePocIndex, 0)}
22681
22940
  - trendline.ethReferenceOiAcceleration=${formatPromptNumber(trendlineContext.ethReferenceOiAcceleration, 3)}
22682
22941
  - trendline.q4ReferenceOiPocApproval=${String(trendlineContext.q4ReferenceOiPocApproval)}
22942
+ - trendline.gatePrimaryIssue=${trendlineContext.gatePrimaryIssue ?? "n/a"}
22943
+ - trendline.cmcTotalMarketCapUsd=${formatPromptNumber(trendlineContext.cmcTotalMarketCapUsd, 0)}
22944
+ - trendline.trendPersistence=${formatPromptNumber(trendlineContext.trendPersistence, 3)}
22945
+ - trendline.marketContextApprovalPocket=${String(trendlineContext.marketContextApprovalPocket)}
22946
+ - trendline.baseDeterministicQuality=${String(trendlineContext.baseDeterministicQuality)}
22683
22947
  - trendline.weakCleanBreak=${String(trendlineContext.weakCleanBreak)}
22684
22948
  - trendline.compressedCleanBreak=${String(trendlineContext.compressedCleanBreak)}
22685
22949
  - trendline.weakBtcLedBreak=${String(trendlineContext.weakBtcLedBreak)}
@@ -22958,10 +23222,13 @@ VolumeDivergence addon:
22958
23222
  `;
22959
23223
  var VOLUME_DIVERGENCE_PAYLOAD_PROMPT = `
22960
23224
  - \`payload.additionalIndicators.volumeDivergenceContext\` contains a compact divergence-strength summary:
22961
- divergenceKind / confirmationPrice / confirmationReady / structureAdvanced / reboundFromPivotPct / confirmationDistancePct / priceDisplacementPct / divergenceAmplitudeAtrRatio / reclaimPct / confirmationCandleQuality / volumeDivergenceStrength / deltaAligned / coinBiasAligned / btcBiasAligned / derivativesDirectionAligned / derivativesRiskFlags / derivativesLiqSpikeRatio / venueSpreadZScore / volumeRel20 / rangePosition20 / deterministicQuality / approvalAllowedNow / structuralHardBlockReasons / maxAllowedQuality.
23225
+ divergenceKind / confirmationPrice / confirmationReady / structureAdvanced / reboundFromPivotPct / confirmationDistancePct / priceDisplacementPct / divergenceAmplitudeAtrRatio / reclaimPct / confirmationCandleQuality / volumeDivergenceStrength / deltaAligned / coinBiasAligned / btcBiasAligned / derivativesDirectionAligned / derivativesRiskFlags / derivativesLiqSpikeRatio / venueSpreadZScore / volumeRel20 / rangePosition20 / btcOiChangePct1h15m / solOpenInterest15m / xrpFundingZScore15m / derivativesRegimePocket / deterministicQuality / approvalAllowedNow / structuralHardBlockReasons / maxAllowedQuality.
22962
23226
  - Use this context as the explicit strategy-specific summary instead of trying to derive the same conclusion again only from generic candles.
22963
23227
  - If \`payload.additionalIndicators.baseContext.derivatives\` exists, it is a Coinalyze-derived summary of derivatives state at signal time; \`stale\` or \`missing_derivatives\` means that Coinalyze context must not be used.
22964
23228
  `;
23229
+ var BTC_OI_CHANGE_PCT_1H_15M_MAX = -0.32;
23230
+ var SOL_OPEN_INTEREST_15M_MIN = 101e5;
23231
+ var XRP_FUNDING_Z_SCORE_15M_MAX = -1.2;
22965
23232
  var toFiniteNumberOrNull6 = (value) => {
22966
23233
  if (typeof value === "number" && Number.isFinite(value)) {
22967
23234
  return value;
@@ -23328,6 +23595,23 @@ var getVolumeDivergenceContext = (signal) => {
23328
23595
  const derivativesRiskFlags = getStringArray3(derivativesSummary?.riskFlags);
23329
23596
  const derivativesFundingZScore = toFiniteNumberOrNull6(derivatives15m?.fundingZScore) ?? toFiniteNumberOrNull6(derivatives1h?.fundingZScore);
23330
23597
  const derivativesLiqSpikeRatio = toFiniteNumberOrNull6(derivatives15m?.liqSpikeRatio) ?? toFiniteNumberOrNull6(derivatives1h?.liqSpikeRatio);
23598
+ const btcOiChangePct1h15m = toFiniteNumberOrNull6(
23599
+ derivatives15m?.oiChangePct1h
23600
+ );
23601
+ const solOpenInterest15m = getNestedNumber3(derivativesContext, [
23602
+ "referenceContexts",
23603
+ "SOLUSDT",
23604
+ "intervals",
23605
+ "15m",
23606
+ "openInterest"
23607
+ ]);
23608
+ const xrpFundingZScore15m = getNestedNumber3(derivativesContext, [
23609
+ "referenceContexts",
23610
+ "XRPUSDT",
23611
+ "intervals",
23612
+ "15m",
23613
+ "fundingZScore"
23614
+ ]);
23331
23615
  const marketContext = getRecord3(additional?.marketContext);
23332
23616
  const venueSpreadZScore = getNestedNumber3(marketContext, [
23333
23617
  "execution",
@@ -23427,9 +23711,9 @@ var getVolumeDivergenceContext = (signal) => {
23427
23711
  entryThresholds,
23428
23712
  aiThresholds
23429
23713
  }) : hardBlockReasons.length > 0 ? 2 : 3;
23430
- const longApprovalPocket = signalDirection !== "LONG" || isAtLeast2(confirmationDistancePct, 2) && isAtLeast2(volumeRel20, 1) && isAtLeast2(venueSpreadZScore, 1.5365);
23431
- const shortApprovalPocket = signalDirection !== "SHORT" || isAtMost(venueSpreadZScore, 0) && rangePosition20 != null && rangePosition20 < 0.2;
23432
- const approvalAllowedNow = hardBlockReasons.length === 0 && deterministicQuality >= 4 && confirmationReady && longApprovalPocket && shortApprovalPocket;
23714
+ const derivativesRegimePocket = isAtMost(btcOiChangePct1h15m, BTC_OI_CHANGE_PCT_1H_15M_MAX) && isAtLeast2(solOpenInterest15m, SOL_OPEN_INTEREST_15M_MIN) && isAtMost(xrpFundingZScore15m, XRP_FUNDING_Z_SCORE_15M_MAX);
23715
+ const maxAllowedQuality = derivativesRegimePocket ? Math.max(deterministicQuality, 4) : deterministicQuality;
23716
+ const approvalAllowedNow = hardBlockReasons.length === 0 && confirmationReady && derivativesRegimePocket && maxAllowedQuality >= 4;
23433
23717
  return {
23434
23718
  signalDirection,
23435
23719
  divergenceKind,
@@ -23462,12 +23746,16 @@ var getVolumeDivergenceContext = (signal) => {
23462
23746
  venueSpreadZScore,
23463
23747
  volumeRel20,
23464
23748
  rangePosition20,
23749
+ btcOiChangePct1h15m,
23750
+ solOpenInterest15m,
23751
+ xrpFundingZScore15m,
23752
+ derivativesRegimePocket,
23465
23753
  sessionPhase,
23466
23754
  hardBlockReasons,
23467
23755
  structuralHardBlockReasons: [...hardBlockReasons],
23468
23756
  deterministicQuality,
23469
23757
  approvalAllowedNow,
23470
- maxAllowedQuality: deterministicQuality
23758
+ maxAllowedQuality
23471
23759
  };
23472
23760
  };
23473
23761
  var getVolumeDivergenceContextFromPayload = (payload, signal) => {
@@ -23518,6 +23806,7 @@ var postProcessAnalysis2 = ({
23518
23806
  );
23519
23807
  const needRetest = finalDirection == null;
23520
23808
  const retestPrice = needRetest ? context.confirmationPrice : null;
23809
+ const approvedQuality = finalDirection != null && context.maxAllowedQuality >= 4 ? Math.max(finalQuality, 4) : finalQuality;
23521
23810
  if (finalDirection == null) {
23522
23811
  return {
23523
23812
  ...analysis,
@@ -23535,7 +23824,7 @@ var postProcessAnalysis2 = ({
23535
23824
  return {
23536
23825
  ...analysis,
23537
23826
  direction: finalDirection,
23538
- quality: finalQuality,
23827
+ quality: approvedQuality,
23539
23828
  needRetest,
23540
23829
  retestPrice,
23541
23830
  takeProfitPrice: signal.prices?.takeProfitPrice ?? null,
@@ -23581,6 +23870,10 @@ Additional VolumeDivergence context:
23581
23870
  - venueSpreadZScore=${context.venueSpreadZScore?.toFixed?.(3) ?? "n/a"}
23582
23871
  - volumeRel20=${context.volumeRel20?.toFixed?.(3) ?? "n/a"}
23583
23872
  - rangePosition20=${context.rangePosition20?.toFixed?.(3) ?? "n/a"}
23873
+ - btcOiChangePct1h15m=${context.btcOiChangePct1h15m?.toFixed?.(3) ?? "n/a"}
23874
+ - solOpenInterest15m=${context.solOpenInterest15m?.toFixed?.(0) ?? "n/a"}
23875
+ - xrpFundingZScore15m=${context.xrpFundingZScore15m?.toFixed?.(3) ?? "n/a"}
23876
+ - derivativesRegimePocket=${context.derivativesRegimePocket}
23584
23877
  - barsSincePivot=${context.barsSincePivot ?? "n/a"}
23585
23878
  - barsBetweenPivotConfirmations=${context.barsBetweenPivotConfirmations ?? "n/a"}
23586
23879
  - entryTiming=${context.entryTiming ?? "n/a"}