@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.mjs CHANGED
@@ -16481,7 +16481,7 @@ AdaptiveMomentumRibbon addon:
16481
16481
  - \`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.
16482
16482
  - If signal candle range is available, \`signalRangeAtrRatio\` must be >= 1.05 for live approval; weaker signal candles stay in watch mode.
16483
16483
  - The local deterministic gate approves LONG by default. SHORT stays in watch mode except for separately calibrated market-breadth shock pockets.
16484
- - 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.
16484
+ - 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.
16485
16485
  - 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.
16486
16486
  - Non-derivatives approvals are demoted when stopDistanceAtr > 4.5 and breakoutBodyAtr > 2.25, because that combination behaves like a chase entry.
16487
16487
  - All live approvals require a calibrated market-regime floor: tpDistanceAtr >= 2.9, trendAdx >= 15, and benchmarkRelativeStrength1d <= 4 when available.
@@ -16493,11 +16493,14 @@ AdaptiveMomentumRibbon addon:
16493
16493
  `;
16494
16494
  var ADAPTIVE_MOMENTUM_RIBBON_PAYLOAD_PROMPT = `
16495
16495
  - \`payload.additionalIndicators.adaptiveMomentumRibbonContext\` contains a compact signal summary:
16496
- 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.
16496
+ 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.
16497
16497
  - Use this context as the primary strategy-specific interpretation instead of re-deriving it only from generic series.
16498
16498
  `;
16499
16499
  var SHORT_BREADTH_SHOCK_MARKET_BREADTH_RETURN_MAX = -0.01;
16500
16500
  var SHORT_BREADTH_NEUTRAL_EFFORT_VS_RESULT_MAX = 800;
16501
+ var SHORT_CMC_TOTAL_MARKET_CAP_USD_MAX = 229e10;
16502
+ var SHORT_BENCHMARK_OI_CHANGE_PCT_24H_1H_MAX = -4;
16503
+ var SHORT_BTC_REFERENCE_TRADE_FLOW_NET_BASE_DELTA_MAX = 0;
16501
16504
  var Q4_TARGET_VS_BTC_ALPHA_1H_MAX = 2.4;
16502
16505
  var REFERENCE_XRP_OI_CHANGE_PCT_4H_15M_MIN = 1.6;
16503
16506
  var REFERENCE_TRX_OI_CHANGE_PCT_4H_15M_MAX = -0.2;
@@ -16710,7 +16713,7 @@ var getDeterministicAdaptiveMomentumRibbonQuality = (context) => {
16710
16713
  return 3;
16711
16714
  }
16712
16715
  if (context.signalDirection === "SHORT") {
16713
- return context.shortBreadthShockPocket || context.shortBreadthNeutralPocket || context.referenceDerivativesRotationPocket ? 4 : 3;
16716
+ return context.shortBreadthShockPocket || context.shortBreadthNeutralPocket || context.shortCmcBenchmarkContractionPocket || context.referenceDerivativesRotationPocket ? 4 : 3;
16714
16717
  }
16715
16718
  if (context.signalDirection === "LONG" && context.cmcAltLiquidityRegime === "btc_favored") {
16716
16719
  return 3;
@@ -16721,12 +16724,12 @@ var getDeterministicAdaptiveMomentumRibbonQuality = (context) => {
16721
16724
  if (causalMomentumLowEffortPocket) {
16722
16725
  return 5;
16723
16726
  }
16727
+ if (context.signalDirection === "LONG" && !context.q4TargetAlpha1Allowed) {
16728
+ return 3;
16729
+ }
16724
16730
  if (context.referenceDerivativesRotationPocket) {
16725
16731
  return 4;
16726
16732
  }
16727
- if (!context.q4TargetAlpha1Allowed) {
16728
- return 3;
16729
- }
16730
16733
  if (context.q4ContinuationRecoveryAllowed) {
16731
16734
  return 4;
16732
16735
  }
@@ -16836,6 +16839,8 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16836
16839
  const gateFeaturesRelative = getRecord(gateFeatures?.relative);
16837
16840
  const gateFeaturesDecisionHints = getRecord(gateFeatures?.decisionHints);
16838
16841
  const baseDerivativesContext = getRecord(baseContext?.derivatives);
16842
+ const baseDerivativesIntervals = getRecord(baseDerivativesContext?.intervals);
16843
+ const baseDerivatives1h = getRecord(baseDerivativesIntervals?.["1h"]);
16839
16844
  const referenceDerivativeContexts = getRecord(
16840
16845
  baseDerivativesContext?.referenceContexts
16841
16846
  );
@@ -16849,6 +16854,11 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16849
16854
  const targetVsBtc = getRecord(relative?.targetVsBtc);
16850
16855
  const cmcGlobal = getRecord(relative?.cmcGlobal);
16851
16856
  const cmcFearGreed = getRecord(relative?.cmcFearGreed);
16857
+ const referenceTradeFlow = getRecord(relative?.referenceTradeFlow);
16858
+ const referenceTradeFlowBySymbol = getRecord(
16859
+ referenceTradeFlow?.tradeFlowBySymbol
16860
+ );
16861
+ const btcReferenceTradeFlow = getRecord(referenceTradeFlowBySymbol?.BTCUSDT);
16852
16862
  const baseMarketBreadth = getRecord(relative?.marketBreadth);
16853
16863
  const structureAcceptance = getRecord(structure?.acceptance);
16854
16864
  const marketContext = getRecord(additional?.marketContext);
@@ -16899,12 +16909,21 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16899
16909
  );
16900
16910
  const referenceDerivativesRotationPocket = referenceXrpOiChangePct4h15m != null && referenceXrpOiChangePct4h15m >= REFERENCE_XRP_OI_CHANGE_PCT_4H_15M_MIN && referenceTrxOiChangePct4h15m != null && referenceTrxOiChangePct4h15m <= REFERENCE_TRX_OI_CHANGE_PCT_4H_15M_MAX;
16901
16911
  const cmcAltLiquidityRegime = typeof cmcGlobal?.altLiquidityRegime === "string" && cmcGlobal.altLiquidityRegime.trim().length > 0 ? cmcGlobal.altLiquidityRegime : null;
16912
+ const cmcTotalMarketCapUsd = toFiniteNumberOrNull(
16913
+ cmcGlobal?.totalMarketCapUsd
16914
+ );
16902
16915
  const cmcFearGreedValueChange7d = toFiniteNumberOrNull(
16903
16916
  cmcFearGreed?.valueChange7d
16904
16917
  );
16905
16918
  const cmcBtcDominanceChange24hPct = toFiniteNumberOrNull(
16906
16919
  cmcGlobal?.btcDominanceChange24hPct
16907
16920
  );
16921
+ const benchmarkOiChangePct24h1h = toFiniteNumberOrNull(
16922
+ baseDerivatives1h?.oiChangePct24h
16923
+ );
16924
+ const btcReferenceTradeFlowNetBaseDelta = toFiniteNumberOrNull(
16925
+ btcReferenceTradeFlow?.netBaseDelta
16926
+ );
16908
16927
  const baseDecisionApproveBias = gateFeaturesDecisionHints?.approveBias === "support" || gateFeaturesDecisionHints?.approveBias === "neutral" || gateFeaturesDecisionHints?.approveBias === "reject" ? gateFeaturesDecisionHints.approveBias : null;
16909
16928
  const marketBreadthAdvanceDeclineRatio = toFiniteNumberOrNull(
16910
16929
  marketBreadth?.advanceDeclineRatio
@@ -16913,6 +16932,7 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16913
16932
  const marketBreadthReturn = toFiniteNumberOrNull(gateFeaturesRelative?.marketBreadthReturn) ?? toFiniteNumberOrNull(marketBreadth?.equalWeightedReturn);
16914
16933
  const shortBreadthShockPocket = signalDirection === "SHORT" && cmcAltLiquidityRegime === "btc_favored" && marketBreadthAdvanceDeclineRatio != null && marketBreadthAdvanceDeclineRatio <= 0 && marketBreadthReturn != null && marketBreadthReturn <= SHORT_BREADTH_SHOCK_MARKET_BREADTH_RETURN_MAX;
16915
16934
  const shortBreadthNeutralPocket = signalDirection === "SHORT" && baseDecisionApproveBias === "neutral" && marketBreadthAdvancers != null && marketBreadthAdvancers <= 0 && marketBreadthReturn != null && marketBreadthReturn <= 0 && isInRange(effortVsResult, 0, SHORT_BREADTH_NEUTRAL_EFFORT_VS_RESULT_MAX);
16935
+ 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;
16916
16936
  const q4TargetAlpha1Allowed = targetVsBtcAlpha1h == null || targetVsBtcAlpha1h <= Q4_TARGET_VS_BTC_ALPHA_1H_MAX;
16917
16937
  const q4ContinuationBlockReasons = getQ4ContinuationBlockReasons({
16918
16938
  targetVsBtcAlpha4h,
@@ -16984,7 +17004,7 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16984
17004
  if (signalDirection === "LONG" && derivativesPressure === "crowded_long" || signalDirection === "SHORT" && derivativesPressure === "crowded_short") {
16985
17005
  riskAnnotations.push("derivatives_pressure_conflict");
16986
17006
  }
16987
- if (signalDirection === "SHORT" && !(shortBreadthShockPocket || shortBreadthNeutralPocket || referenceDerivativesRotationPocket)) {
17007
+ if (signalDirection === "SHORT" && !(shortBreadthShockPocket || shortBreadthNeutralPocket || shortCmcBenchmarkContractionPocket || referenceDerivativesRotationPocket)) {
16988
17008
  approvalBlockReasons.push("short_disabled");
16989
17009
  }
16990
17010
  if (signalDirection === "LONG" && cmcAltLiquidityRegime === "btc_favored") {
@@ -17046,14 +17066,18 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
17046
17066
  spreadBias,
17047
17067
  spreadSeverity,
17048
17068
  cmcAltLiquidityRegime,
17069
+ cmcTotalMarketCapUsd,
17049
17070
  cmcFearGreedValueChange7d,
17050
17071
  cmcBtcDominanceChange24hPct,
17072
+ benchmarkOiChangePct24h1h,
17073
+ btcReferenceTradeFlowNetBaseDelta,
17051
17074
  baseDecisionApproveBias,
17052
17075
  marketBreadthAdvancers,
17053
17076
  marketBreadthAdvanceDeclineRatio,
17054
17077
  marketBreadthReturn,
17055
17078
  shortBreadthShockPocket,
17056
17079
  shortBreadthNeutralPocket,
17080
+ shortCmcBenchmarkContractionPocket,
17057
17081
  referenceDerivativesRotationPocket,
17058
17082
  referenceXrpOiChangePct4h15m,
17059
17083
  referenceTrxOiChangePct4h15m,
@@ -17124,14 +17148,18 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
17124
17148
  spreadBias,
17125
17149
  spreadSeverity,
17126
17150
  cmcAltLiquidityRegime,
17151
+ cmcTotalMarketCapUsd,
17127
17152
  cmcFearGreedValueChange7d,
17128
17153
  cmcBtcDominanceChange24hPct,
17154
+ benchmarkOiChangePct24h1h,
17155
+ btcReferenceTradeFlowNetBaseDelta,
17129
17156
  baseDecisionApproveBias,
17130
17157
  marketBreadthAdvancers,
17131
17158
  marketBreadthAdvanceDeclineRatio,
17132
17159
  marketBreadthReturn,
17133
17160
  shortBreadthShockPocket,
17134
17161
  shortBreadthNeutralPocket,
17162
+ shortCmcBenchmarkContractionPocket,
17135
17163
  referenceDerivativesRotationPocket,
17136
17164
  referenceXrpOiChangePct4h15m,
17137
17165
  referenceTrxOiChangePct4h15m,
@@ -17270,14 +17298,18 @@ Additional AdaptiveMomentumRibbon context:
17270
17298
  - spreadBias=${context.spreadBias ?? "n/a"}
17271
17299
  - spreadSeverity=${context.spreadSeverity ?? "n/a"}
17272
17300
  - cmcAltLiquidityRegime=${context.cmcAltLiquidityRegime ?? "n/a"}
17301
+ - cmcTotalMarketCapUsd=${context.cmcTotalMarketCapUsd?.toFixed?.(0) ?? "n/a"}
17273
17302
  - cmcFearGreedValueChange7d=${context.cmcFearGreedValueChange7d?.toFixed?.(3) ?? "n/a"}
17274
17303
  - cmcBtcDominanceChange24hPct=${context.cmcBtcDominanceChange24hPct?.toFixed?.(3) ?? "n/a"}
17304
+ - benchmarkOiChangePct24h1h=${context.benchmarkOiChangePct24h1h?.toFixed?.(3) ?? "n/a"}
17305
+ - btcReferenceTradeFlowNetBaseDelta=${context.btcReferenceTradeFlowNetBaseDelta?.toFixed?.(3) ?? "n/a"}
17275
17306
  - baseDecisionApproveBias=${context.baseDecisionApproveBias ?? "n/a"}
17276
17307
  - marketBreadthAdvancers=${context.marketBreadthAdvancers?.toFixed?.(0) ?? "n/a"}
17277
17308
  - marketBreadthAdvanceDeclineRatio=${context.marketBreadthAdvanceDeclineRatio?.toFixed?.(3) ?? "n/a"}
17278
17309
  - marketBreadthReturn=${context.marketBreadthReturn?.toFixed?.(5) ?? "n/a"}
17279
17310
  - shortBreadthShockPocket=${context.shortBreadthShockPocket}
17280
17311
  - shortBreadthNeutralPocket=${context.shortBreadthNeutralPocket}
17312
+ - shortCmcBenchmarkContractionPocket=${context.shortCmcBenchmarkContractionPocket}
17281
17313
  - referenceDerivativesRotationPocket=${context.referenceDerivativesRotationPocket}
17282
17314
  - referenceXrpOiChangePct4h15m=${context.referenceXrpOiChangePct4h15m?.toFixed?.(3) ?? "n/a"}
17283
17315
  - referenceTrxOiChangePct4h15m=${context.referenceTrxOiChangePct4h15m?.toFixed?.(3) ?? "n/a"}
@@ -17345,6 +17377,9 @@ var MAX_REFERENCE_SHORT_RECOVERY_ETH_LIQ_IMBALANCE_1H = -0.99;
17345
17377
  var MAX_XRP_SHORT_RECOVERY_BTC_VS_ALT_RETURN_24H = -0.03;
17346
17378
  var MAX_XRP_SHORT_RECOVERY_FUNDING_Z_SCORE_1H = -1.8;
17347
17379
  var MIN_XRP_OI_REJECT_BIAS_BLOCK_15M = 25e7;
17380
+ var MAX_XRP_OI_RECOVERY_BTC_DOMINANCE_PCT = 58.45;
17381
+ var MIN_XRP_OI_RECOVERY_MARKET_BREADTH_SYMBOLS = 27;
17382
+ var MIN_XRP_OI_RECOVERY_BNB_FUNDING_CHANGE_1H = 0;
17348
17383
  var MAX_APPROVAL_RSI = 75;
17349
17384
  var MIN_APPROVAL_BB_WIDTH_RANK_100 = 50;
17350
17385
  var buildAdaptiveTrendChannelGuardrailContext = ({
@@ -17353,6 +17388,7 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17353
17388
  }) => {
17354
17389
  const targetDerivatives1h = baseContext?.derivatives?.intervals?.["1h"];
17355
17390
  const ethDerivatives1h = baseContext?.derivatives?.referenceContexts?.["ETHUSDT"]?.intervals?.["1h"];
17391
+ const bnbDerivativesSummary = baseContext?.derivatives?.referenceContexts?.["BNBUSDT"]?.summary;
17356
17392
  const xrpDerivatives15m = baseContext?.derivatives?.referenceContexts?.["XRPUSDT"]?.intervals?.["15m"];
17357
17393
  const xrpDerivatives1h = baseContext?.derivatives?.referenceContexts?.["XRPUSDT"]?.intervals?.["1h"];
17358
17394
  const targetDerivatives1hStale = targetDerivatives1h?.stale === true;
@@ -17370,10 +17406,17 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17370
17406
  baseContext?.regime?.volatility?.percentiles?.bbWidthRank100
17371
17407
  );
17372
17408
  const trendFollowState = baseContext?.regime?.trend?.trendFollow?.state ?? null;
17409
+ const volatilityState = baseContext?.regime?.volatility?.state ?? null;
17373
17410
  const h4VolatilityState = baseContext?.mtf?.summary?.h4VolatilityState ?? null;
17374
17411
  const benchmarkTrendAlignment = baseContext?.relative?.benchmark?.trendAlignment ?? null;
17375
17412
  const cmcExchangeLiquidityAligned = typeof baseContext?.gateFeatures?.relative?.cmcExchangeLiquidityAligned === "boolean" ? baseContext.gateFeatures.relative.cmcExchangeLiquidityAligned : null;
17376
17413
  const cmcExchangeLiquidityStale = typeof baseContext?.gateFeatures?.relative?.cmcExchangeLiquidityStale === "boolean" ? baseContext.gateFeatures.relative.cmcExchangeLiquidityStale : null;
17414
+ const cmcBtcDominancePct = asFiniteNumber(
17415
+ baseContext?.relative?.cmcGlobal?.btcDominancePct
17416
+ );
17417
+ const marketBreadthSymbolsCount = asFiniteNumber(
17418
+ baseContext?.relative?.marketBreadth?.symbolsCount
17419
+ );
17377
17420
  const baseApproveBias = baseContext?.gateFeatures?.decisionHints?.approveBias ?? null;
17378
17421
  const targetLiqImbalance1h = asFiniteNumber(
17379
17422
  targetDerivatives1h?.liqImbalance
@@ -17384,6 +17427,9 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17384
17427
  const targetLiqTotal1h = asFiniteNumber(targetDerivatives1h?.liqTotal);
17385
17428
  const ethLiqImbalance1h = asFiniteNumber(ethDerivatives1h?.liqImbalance);
17386
17429
  const ethFundingRate1h = asFiniteNumber(ethDerivatives1h?.fundingRate);
17430
+ const bnbFundingChange1h = asFiniteNumber(
17431
+ bnbDerivativesSummary?.fundingChange1h
17432
+ );
17387
17433
  const xrpOpenInterest15m = asFiniteNumber(xrpDerivatives15m?.openInterest);
17388
17434
  const xrpPriceOiDivergenceType = baseContext?.derivatives?.referenceContexts?.["XRPUSDT"]?.summary?.priceOiDivergenceType ?? null;
17389
17435
  const xrpFundingZScore1h = asFiniteNumber(xrpDerivatives1h?.fundingZScore);
@@ -17421,10 +17467,11 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17421
17467
  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;
17422
17468
  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;
17423
17469
  const xrpShortRecoverySetup = xrpBtcShortRecoverySetup || xrpEthShortRecoverySetup;
17424
- if (xrpOpenInterest15m != null && xrpOpenInterest15m >= MIN_XRP_OI_REJECT_BIAS_BLOCK_15M && baseApproveBias === "reject" && !xrpShortRecoverySetup) {
17470
+ 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;
17471
+ if (xrpOpenInterest15m != null && xrpOpenInterest15m >= MIN_XRP_OI_REJECT_BIAS_BLOCK_15M && baseApproveBias === "reject" && !xrpShortRecoverySetup && !xrpOiReferenceRecoverySetup) {
17425
17472
  hardBlockReasons.push("xrp_oi_reject_bias");
17426
17473
  }
17427
- const approvalSetup = longApprovalSetup || xrpShortRecoverySetup;
17474
+ const approvalSetup = longApprovalSetup || xrpShortRecoverySetup || xrpOiReferenceRecoverySetup;
17428
17475
  const highConfidenceSetup = longApprovalSetup && breakoutDistancePct >= MIN_HIGH_CONFIDENCE_BREAKOUT_DISTANCE_PCT && channelWidthPct >= MIN_HIGH_CONFIDENCE_CHANNEL_WIDTH_PCT;
17429
17476
  let deterministicQuality = 3;
17430
17477
  if (hardBlockReasons.length > 0) {
@@ -17482,15 +17529,19 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17482
17529
  rsi,
17483
17530
  bbWidthRank100,
17484
17531
  trendFollowState,
17532
+ volatilityState,
17485
17533
  h4VolatilityState,
17486
17534
  benchmarkTrendAlignment,
17487
17535
  cmcExchangeLiquidityAligned,
17488
17536
  cmcExchangeLiquidityStale,
17537
+ cmcBtcDominancePct,
17538
+ marketBreadthSymbolsCount,
17489
17539
  targetLiqImbalance1h,
17490
17540
  targetLiqSpikeRatio1h,
17491
17541
  targetLiqTotal1h,
17492
17542
  ethLiqImbalance1h,
17493
17543
  ethFundingRate1h,
17544
+ bnbFundingChange1h,
17494
17545
  xrpOpenInterest15m,
17495
17546
  xrpPriceOiDivergenceType,
17496
17547
  xrpFundingZScore1h,
@@ -17566,13 +17617,17 @@ Additional AdaptiveTrendChannel context:
17566
17617
  - rsi=${String(context.rsi ?? "n/a")}
17567
17618
  - bbWidthRank100=${String(context.bbWidthRank100 ?? "n/a")}
17568
17619
  - trendFollowState=${context.trendFollowState ?? "n/a"}
17620
+ - volatilityState=${context.volatilityState ?? "n/a"}
17569
17621
  - h4VolatilityState=${context.h4VolatilityState ?? "n/a"}
17570
17622
  - benchmarkTrendAlignment=${context.benchmarkTrendAlignment ?? "n/a"}
17623
+ - cmcBtcDominancePct=${String(context.cmcBtcDominancePct ?? "n/a")}
17624
+ - marketBreadthSymbolsCount=${String(context.marketBreadthSymbolsCount ?? "n/a")}
17571
17625
  - targetLiqImbalance1h=${String(context.targetLiqImbalance1h ?? "n/a")}
17572
17626
  - targetLiqSpikeRatio1h=${String(context.targetLiqSpikeRatio1h ?? "n/a")}
17573
17627
  - targetLiqTotal1h=${String(context.targetLiqTotal1h ?? "n/a")}
17574
17628
  - ethLiqImbalance1h=${String(context.ethLiqImbalance1h ?? "n/a")}
17575
17629
  - ethFundingRate1h=${String(context.ethFundingRate1h ?? "n/a")}
17630
+ - bnbFundingChange1h=${String(context.bnbFundingChange1h ?? "n/a")}
17576
17631
  - xrpOpenInterest15m=${String(context.xrpOpenInterest15m ?? "n/a")}
17577
17632
  - xrpPriceOiDivergenceType=${context.xrpPriceOiDivergenceType ?? "n/a"}
17578
17633
  - xrpFundingZScore1h=${String(context.xrpFundingZScore1h ?? "n/a")}
@@ -17590,7 +17645,7 @@ Interpretation rules for AdaptiveTrendChannel:
17590
17645
  - The centerline is the adaptive rail; floor/roof are volatility-scaled invalidation bands.
17591
17646
  - Prefer flips with reasonable distance from the centerline and confirmation from shared market context.
17592
17647
  - Thin participation, missing shared-context confirmation, or missing liquidation-shock recovery evidence should downgrade the setup.
17593
- - A high-XRP-OI reject bias should remain blocked unless a narrow XRP reference SHORT recovery setup is present.
17648
+ - 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.
17594
17649
  - Treat deterministicQuality and approvalAllowedNow as the local normalized gate result.
17595
17650
  `.trim();
17596
17651
  },
@@ -17807,6 +17862,7 @@ var buildEntryStopTargetFigures = ({
17807
17862
  var MFR_CALIBRATED_LONG_TARGET_VS_BTC_RATIO_RETURN_24H_MAX = -3.3;
17808
17863
  var MFR_CALIBRATED_LONG_ETH_VS_BTC_VOLUME_RATIO_MIN = 0.54;
17809
17864
  var MFR_CALIBRATED_LONG_H1_RANGE_POSITION_MAX = 0.08;
17865
+ var MFR_AI_LONG_STOP_DISTANCE_ATR_MIN = 24;
17810
17866
  var getMarketFlushReversalLongReboundPocketFeatures = (baseContext) => ({
17811
17867
  targetVsBtcRatioReturn24h: toFiniteNumberOrNull2(
17812
17868
  baseContext?.relative?.targetVsBtc?.ratioReturn24h
@@ -17824,6 +17880,21 @@ var isMarketFlushReversalCalibratedLongReboundPocket = ({
17824
17880
  ethVsBtcVolumeRatio,
17825
17881
  h1RangePosition
17826
17882
  }) => 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);
17883
+ var getMarketFlushReversalAiLongPocketFeatures = (baseContext) => ({
17884
+ stopDistanceAtr: toFiniteNumberOrNull2(
17885
+ baseContext?.gateFeatures?.setup?.stopDistanceAtr
17886
+ ),
17887
+ cmcIndexRegime: baseContext?.relative?.cmcIndexes?.indexRegime ?? null,
17888
+ cmcIndexStale: typeof baseContext?.relative?.cmcIndexes?.stale === "boolean" ? baseContext.relative.cmcIndexes.stale : null,
17889
+ rsiState: baseContext?.regime?.momentum?.rsiState ?? null
17890
+ });
17891
+ var isMarketFlushReversalValidatedAiLongPocket = ({
17892
+ direction,
17893
+ stopDistanceAtr,
17894
+ cmcIndexRegime,
17895
+ cmcIndexStale,
17896
+ rsiState
17897
+ }) => direction === "LONG" && stopDistanceAtr != null && stopDistanceAtr >= MFR_AI_LONG_STOP_DISTANCE_ATR_MIN && cmcIndexRegime === "risk_off" && cmcIndexStale === false && rsiState === "oversold";
17827
17898
 
17828
17899
  // src/MarketFlushReversal/guardrails.ts
17829
17900
  var toFiniteNumberOrNull3 = (value) => {
@@ -17913,6 +17984,12 @@ var buildMarketFlushReversalGuardrailContext = ({
17913
17984
  direction
17914
17985
  });
17915
17986
  const { targetVsBtcRatioReturn24h, ethVsBtcVolumeRatio, h1RangePosition } = longReboundPocketFeatures;
17987
+ const aiLongPocketFeatures = getMarketFlushReversalAiLongPocketFeatures(baseContext);
17988
+ const validatedAiLongPocket = isMarketFlushReversalValidatedAiLongPocket({
17989
+ ...aiLongPocketFeatures,
17990
+ direction
17991
+ });
17992
+ const { stopDistanceAtr, cmcIndexRegime, cmcIndexStale, rsiState } = aiLongPocketFeatures;
17916
17993
  const approvalBlockReasons = [];
17917
17994
  const riskAnnotations = [];
17918
17995
  if (direction == null) approvalBlockReasons.push("missing_direction");
@@ -17923,22 +18000,22 @@ var buildMarketFlushReversalGuardrailContext = ({
17923
18000
  approvalBlockReasons.push("local_participation_not_confirmed");
17924
18001
  }
17925
18002
  if (!marketContextAvailable) {
17926
- approvalBlockReasons.push("missing_broad_market_derivatives");
18003
+ riskAnnotations.push("missing_broad_market_derivatives");
17927
18004
  }
17928
18005
  if (marketRiskFlags.includes("stale_derivatives")) {
17929
- approvalBlockReasons.push("stale_broad_market_derivatives");
18006
+ riskAnnotations.push("stale_broad_market_derivatives");
17930
18007
  }
17931
18008
  if (marketContextAvailable && broadMarketFlushDirection == null) {
17932
- approvalBlockReasons.push("no_broad_market_flush");
18009
+ riskAnnotations.push("no_broad_market_flush");
17933
18010
  }
17934
18011
  if (direction != null && broadMarketFlushDirection != null && broadMarketFlushDirection !== direction) {
17935
- approvalBlockReasons.push("broad_market_flush_direction_mismatch");
18012
+ riskAnnotations.push("broad_market_flush_direction_mismatch");
17936
18013
  }
17937
18014
  if (direction === "SHORT") {
17938
18015
  approvalBlockReasons.push("short_flush_rebound_pocket_not_validated");
17939
18016
  }
17940
- if (direction === "LONG" && !calibratedLongRebound) {
17941
- approvalBlockReasons.push("calibrated_long_rebound_missing");
18017
+ if (direction === "LONG" && !validatedAiLongPocket) {
18018
+ approvalBlockReasons.push("validated_long_ai_pocket_missing");
17942
18019
  }
17943
18020
  if (signalContext.marketFlushConfirmed !== true) {
17944
18021
  riskAnnotations.push("market_flush_not_available_at_core_time");
@@ -17962,7 +18039,12 @@ var buildMarketFlushReversalGuardrailContext = ({
17962
18039
  targetVsBtcRatioReturn24h,
17963
18040
  ethVsBtcVolumeRatio,
17964
18041
  h1RangePosition,
17965
- calibratedLongRebound
18042
+ calibratedLongRebound,
18043
+ stopDistanceAtr,
18044
+ cmcIndexRegime,
18045
+ cmcIndexStale,
18046
+ rsiState,
18047
+ validatedAiLongPocket
17966
18048
  };
17967
18049
  return {
17968
18050
  ...signalContext,
@@ -18061,6 +18143,11 @@ Additional Market Flush Reversal context:
18061
18143
  - ethVsBtcVolumeRatio=${String(context.marketFlushReversalGateFeatures.ethVsBtcVolumeRatio ?? "n/a")}
18062
18144
  - h1RangePosition=${String(context.marketFlushReversalGateFeatures.h1RangePosition ?? "n/a")}
18063
18145
  - calibratedLongRebound=${String(context.marketFlushReversalGateFeatures.calibratedLongRebound)}
18146
+ - stopDistanceAtr=${String(context.marketFlushReversalGateFeatures.stopDistanceAtr ?? "n/a")}
18147
+ - cmcIndexRegime=${context.marketFlushReversalGateFeatures.cmcIndexRegime ?? "n/a"}
18148
+ - cmcIndexStale=${String(context.marketFlushReversalGateFeatures.cmcIndexStale ?? "n/a")}
18149
+ - rsiState=${context.marketFlushReversalGateFeatures.rsiState ?? "n/a"}
18150
+ - validatedAiLongPocket=${String(context.marketFlushReversalGateFeatures.validatedAiLongPocket)}
18064
18151
  - approvalAllowedNow=${String(context.approvalAllowedNow)}
18065
18152
  - deterministicQuality=${String(context.deterministicQuality)}
18066
18153
  - approvalBlockReasons=${context.approvalBlockReasons.join(",") || "none"}
@@ -18173,6 +18260,7 @@ var buildDoubleTapGateFeatures = ({
18173
18260
  defaultApprovalAllowed,
18174
18261
  q4AltDispersionOk,
18175
18262
  q4DerivativesCmcRiskOk,
18263
+ q4DerivativesDirectionSessionOk,
18176
18264
  strictMomentumApproved,
18177
18265
  strictMomentumRoc1dOk
18178
18266
  }) => {
@@ -18195,6 +18283,7 @@ var buildDoubleTapGateFeatures = ({
18195
18283
  q4AltDispersionOk,
18196
18284
  q4DerivativesPocket,
18197
18285
  q4DerivativesCmcRiskOk,
18286
+ q4DerivativesDirectionSessionOk,
18198
18287
  strictMomentumApproved,
18199
18288
  strictMomentumRoc1dOk
18200
18289
  };
@@ -18373,7 +18462,8 @@ var buildDoubleTapAiContext = (payload) => {
18373
18462
  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;
18374
18463
  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;
18375
18464
  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;
18376
- const q4DerivativesApproval = q4DerivativesPocket && !q4DerivativesBadCmcPocket;
18465
+ const q4DerivativesDirectionSessionOk = q4DerivativesPocket ? signalDirection === "LONG" ? primarySession === "europe" : signalDirection === "SHORT" ? true : false : null;
18466
+ const q4DerivativesApproval = q4DerivativesPocket && q4DerivativesDirectionSessionOk === true && !q4DerivativesBadCmcPocket;
18377
18467
  const softBlockReasons = [
18378
18468
  ...legacyShapeCandidate && sessionWindowPhase !== "active" ? ["inactive_session_window"] : [],
18379
18469
  ...legacyShapeCandidate && (executionScore == null || executionScore < MIN_EXECUTION_SCORE_FOR_AI_GATE) ? ["low_or_missing_execution_score"] : [],
@@ -18386,7 +18476,9 @@ var buildDoubleTapAiContext = (payload) => {
18386
18476
  ...legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && cmcBtcDominanceChange24hPct != null && (cmcBtcDominanceChange24hPct <= Q4_CMC_BTC_DOMINANCE_CHANGE_MIN || cmcBtcDominanceChange24hPct > Q4_CMC_BTC_DOMINANCE_CHANGE_MAX) ? ["cmc_btc_dominance_change_outside_band"] : [],
18387
18477
  ...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"] : [],
18388
18478
  ...legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && altDispersion24h != null && altDispersion24h >= Q4_ALT_DISPERSION_24H_MAX ? ["alt_dispersion_24h_too_high_for_q4"] : [],
18389
- ...q4CmcApproval ? ["legacy_q4_structural_observation_only"] : []
18479
+ ...q4CmcApproval ? ["legacy_q4_structural_observation_only"] : [],
18480
+ ...q4DerivativesPocket && signalDirection === "LONG" && q4DerivativesDirectionSessionOk === false ? ["long_q4_derivatives_outside_europe_session"] : [],
18481
+ ...q4DerivativesPocket && signalDirection == null ? ["missing_signal_direction_for_q4_derivatives"] : []
18390
18482
  ];
18391
18483
  const highPrecisionApprovalBlocked = legacyHighPrecisionShapeCandidate && !highPrecisionCmcApproval && !q4DerivativesApproval;
18392
18484
  const q4DerivativesApprovalBlocked = q4DerivativesPocket && !q4DerivativesApproval && !highPrecisionCmcApproval;
@@ -18422,6 +18514,7 @@ var buildDoubleTapAiContext = (payload) => {
18422
18514
  defaultApprovalAllowed,
18423
18515
  q4AltDispersionOk: altDispersion24h == null ? null : altDispersion24h < Q4_ALT_DISPERSION_24H_MAX,
18424
18516
  q4DerivativesCmcRiskOk: btcVsAltReturn24h == null || cmc20ToCmc100RatioChange24hPct == null ? null : !q4DerivativesBadCmcPocket,
18517
+ q4DerivativesDirectionSessionOk,
18425
18518
  strictMomentumApproved: strictMomentumApprovalAllowedNow,
18426
18519
  strictMomentumRoc1dOk
18427
18520
  });
@@ -18455,6 +18548,7 @@ var buildDoubleTapAiContext = (payload) => {
18455
18548
  ethCrowdingPersistenceBars,
18456
18549
  solFundingZScore15m,
18457
18550
  altDispersion24h,
18551
+ q4DerivativesDirectionSessionOk,
18458
18552
  doubleTapGateFeatures,
18459
18553
  structuralHardBlockReasons,
18460
18554
  softBlockReasons,
@@ -18559,6 +18653,7 @@ Additional DoubleTap context:
18559
18653
  - doubleTapGateQ4AltDispersionOk=${String(context.doubleTapGateFeatures.q4AltDispersionOk ?? "n/a")}
18560
18654
  - doubleTapGateQ4DerivativesPocket=${String(context.doubleTapGateFeatures.q4DerivativesPocket)}
18561
18655
  - doubleTapGateQ4DerivativesCmcRiskOk=${String(context.doubleTapGateFeatures.q4DerivativesCmcRiskOk ?? "n/a")}
18656
+ - doubleTapGateQ4DerivativesDirectionSessionOk=${String(context.doubleTapGateFeatures.q4DerivativesDirectionSessionOk ?? "n/a")}
18562
18657
  - doubleTapGateStrictMomentumApproved=${String(context.doubleTapGateFeatures.strictMomentumApproved)}
18563
18658
  - doubleTapGateStrictMomentumRoc1dOk=${String(context.doubleTapGateFeatures.strictMomentumRoc1dOk ?? "n/a")}
18564
18659
  - deterministicQuality=${String(context.deterministicQuality)}
@@ -18576,7 +18671,7 @@ Interpretation rules for DoubleTap:
18576
18671
  - Treat deterministicQuality and approvalAllowedNow as the normalized local gate result.
18577
18672
  - 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.
18578
18673
  - The legacy structural q4 CMC pocket is retained only as observation context and should not be treated as local approval.
18579
- - 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.
18674
+ - 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.
18580
18675
  - 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.
18581
18676
  - A good long has two comparable lows and a clean close above the neckline.
18582
18677
  - A good short has two comparable highs and a clean close below the neckline.
@@ -18660,6 +18755,8 @@ var MAX_APPROVAL_PRICE_DISTANCE_TO_MA_SLOW_ATR = 1.2;
18660
18755
  var MIN_APPROVAL_ACTIVE_LIQUIDITY_ZONES = 1;
18661
18756
  var MAX_DERIVATIVES_RISK_OFF_ALT_BASKET_RETURN_24H = -0.035;
18662
18757
  var MAX_DERIVATIVES_RISK_OFF_TRX_OI_CHANGE_PCT_4H = -1.8;
18758
+ var MIN_BENCHMARK_FLOW_BUY_PRESSURE_PCT = 0.61;
18759
+ var MIN_BENCHMARK_OI_ACCELERATION = 0.55;
18663
18760
  var Q4_APPROVAL_ATR_RANK_BUCKETS = /* @__PURE__ */ new Set(["high", "extreme"]);
18664
18761
  var buildLiquidityTailsGateFeatures = ({
18665
18762
  signalContext,
@@ -18764,10 +18861,17 @@ var buildLiquidityTailsGuardrailContext = ({
18764
18861
  const flushSupport = direction === "LONG" ? derivativesRiskFlags.includes("short_liquidation_spike") || derivativesPressure === "short_flush" : direction === "SHORT" ? derivativesRiskFlags.includes("long_liquidation_spike") || derivativesPressure === "long_flush" : false;
18765
18862
  const directionalCrowding = direction === "LONG" ? derivativesRiskFlags.includes("crowded_long") : direction === "SHORT" ? derivativesRiskFlags.includes("crowded_short") : false;
18766
18863
  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;
18767
- if (derivativesDirectionAligned === true && !flushSupport && !derivativesRiskOffLongRecoveryPocket) {
18864
+ const referenceTradeFlowBuyPressurePct = asFiniteNumber2(
18865
+ baseContext?.gateFeatures?.participation?.referenceTradeFlowBuyPressurePct
18866
+ );
18867
+ const benchmarkOiAcceleration = asFiniteNumber2(
18868
+ derivativesSummary?.oiAcceleration
18869
+ );
18870
+ const benchmarkFlowOiExpansionRecoveryPocket = (direction === "LONG" || direction === "SHORT") && q4AtrRankEligible && referenceTradeFlowBuyPressurePct != null && referenceTradeFlowBuyPressurePct >= MIN_BENCHMARK_FLOW_BUY_PRESSURE_PCT && benchmarkOiAcceleration != null && benchmarkOiAcceleration >= MIN_BENCHMARK_OI_ACCELERATION;
18871
+ if (derivativesDirectionAligned === true && !flushSupport && !derivativesRiskOffLongRecoveryPocket && !benchmarkFlowOiExpansionRecoveryPocket) {
18768
18872
  hardBlockReasons.push("derivatives_reversal_aligned");
18769
18873
  }
18770
- if (derivativesDirectionAligned === false && !flushSupport && !derivativesRiskOffLongRecoveryPocket) {
18874
+ if (derivativesDirectionAligned === false && !flushSupport && !derivativesRiskOffLongRecoveryPocket && !benchmarkFlowOiExpansionRecoveryPocket) {
18771
18875
  hardBlockReasons.push("derivatives_reversal_conflict");
18772
18876
  }
18773
18877
  if (volumeRel20 != null && volumeRel20 < 0.75) {
@@ -18857,6 +18961,9 @@ var buildLiquidityTailsGuardrailContext = ({
18857
18961
  softBlockReasons.push(...approvalContextReasons);
18858
18962
  }
18859
18963
  }
18964
+ if (deterministicQuality < 4 && hardBlockReasons.length === 0 && benchmarkFlowOiExpansionRecoveryPocket) {
18965
+ deterministicQuality = 4;
18966
+ }
18860
18967
  return {
18861
18968
  ...signalContext,
18862
18969
  baseContextAvailable: Boolean(baseContext),
@@ -18887,6 +18994,7 @@ var buildLiquidityTailsGuardrailContext = ({
18887
18994
  derivativesRiskFlags,
18888
18995
  cadenceUpgradePocket,
18889
18996
  derivativesRiskOffLongRecoveryPocket,
18997
+ benchmarkFlowOiExpansionRecoveryPocket,
18890
18998
  liquidityTailsGateFeatures,
18891
18999
  hardBlockReasons,
18892
19000
  softBlockReasons,
@@ -19057,6 +19165,9 @@ var isDirectionalPriceAboveLevel = ({
19057
19165
  price,
19058
19166
  level
19059
19167
  }) => direction === "LONG" ? price != null && level != null && price > level : direction === "SHORT" ? price != null && level != null && price < level : null;
19168
+ var TRANSITION_LOW_TOUCH_COUNT_MAX = 2;
19169
+ var ETH_REFERENCE_WEAK_NON_STRESS_OI_CHANGE_PCT_24H_MAX = -2.5;
19170
+ var LONG_DIRECT_INDICATOR_SUPPORT_MIN = 2;
19060
19171
  var buildLiquidityZonesGuardrailContext = ({
19061
19172
  signalContext,
19062
19173
  baseContext
@@ -19217,12 +19328,15 @@ var buildLiquidityZonesGuardrailContext = ({
19217
19328
  const isContinuationBreakoutRetest = direction === "LONG" ? breakoutState === "above_high_level" || entryLocation === "breakout" : direction === "SHORT" ? breakoutState === "below_low_level" || entryLocation === "breakdown" : false;
19218
19329
  const hasBaseRetestConfirmation = filterMetric >= 3 && hitCount >= 2 && reactionCloseDistancePct >= 0.08 && retestPenetrationPct <= 90;
19219
19330
  const ethReferenceOiWeakPocket = ethReferenceOiChangePct4h != null && ethReferenceOiChangePct4h <= -0.8;
19220
- const transitionStructureExpansionPocket = hasBaseRetestConfirmation && structureZoneState === "transition" && structureScore != null && structureScore >= 17 && adaptiveChannelFlipDown === false && !directionalCrowding && !ethReferenceOiWeakPocket;
19221
19331
  const ethReferenceStressPocket = hasBaseRetestConfirmation && lowTouchCount20 != null && lowTouchCount20 <= 3 && ethReferenceOiChangePct24h != null && ethReferenceOiChangePct24h <= -5.8 && ethReferenceFundingZScore != null && ethReferenceFundingZScore <= -1.05;
19332
+ const transitionStructureExpansionPocket = hasBaseRetestConfirmation && lowTouchCount20 != null && lowTouchCount20 <= TRANSITION_LOW_TOUCH_COUNT_MAX && structureZoneState === "transition" && structureScore != null && structureScore >= 17 && adaptiveChannelFlipDown === false && !directionalCrowding && !ethReferenceOiWeakPocket;
19222
19333
  const solReferenceStressPocket = hasBaseRetestConfirmation && lowTouchCount20 != null && lowTouchCount20 <= 3 && solReferenceOiChangePct24h != null && solReferenceOiChangePct24h <= -4.2 && solReferenceFundingZScore != null && solReferenceFundingZScore <= -1.2;
19223
19334
  const calibratedExpansionPocket = transitionStructureExpansionPocket || ethReferenceStressPocket || solReferenceStressPocket;
19335
+ const ethReferenceWeakNonStressPocket = ethReferenceOiChangePct24h != null && ethReferenceOiChangePct24h <= ETH_REFERENCE_WEAK_NON_STRESS_OI_CHANGE_PCT_24H_MAX && !ethReferenceStressPocket;
19336
+ const longDirectIndicatorSupportConfirmed = direction === "LONG" ? directIndicatorSupportCount != null && directIndicatorSupportCount >= LONG_DIRECT_INDICATOR_SUPPORT_MIN : null;
19224
19337
  const longRequiresCalibratedExpansion = direction === "LONG" && !calibratedExpansionPocket;
19225
- const approvalDisqualifiedByCalibration = !calibratedExpansionPocket && (longRequiresCalibratedExpansion || isContinuationBreakoutRetest || hasOverextendedVolumeConfirmation || hasIsolatedIndicatorSupport);
19338
+ const longDirectIndicatorSupportMissing = longDirectIndicatorSupportConfirmed === false;
19339
+ const approvalDisqualifiedByCalibration = !calibratedExpansionPocket && (longRequiresCalibratedExpansion || isContinuationBreakoutRetest || hasOverextendedVolumeConfirmation || hasIsolatedIndicatorSupport) || ethReferenceWeakNonStressPocket || longDirectIndicatorSupportMissing;
19226
19340
  if (longRequiresCalibratedExpansion) {
19227
19341
  softBlockReasons.push("long_liquidity_retest_requires_recalibration");
19228
19342
  }
@@ -19235,6 +19349,12 @@ var buildLiquidityZonesGuardrailContext = ({
19235
19349
  if (hasIsolatedIndicatorSupport) {
19236
19350
  softBlockReasons.push("isolated_indicator_support");
19237
19351
  }
19352
+ if (ethReferenceWeakNonStressPocket) {
19353
+ softBlockReasons.push("eth_reference_oi_weak_without_stress");
19354
+ }
19355
+ if (longDirectIndicatorSupportMissing) {
19356
+ softBlockReasons.push("long_direct_indicator_support_missing");
19357
+ }
19238
19358
  const hasLongBreakoutConfirmation = direction === "LONG" && (breakoutState === "below_low_level" || breakoutState === "above_high_level") && reactionCloseDistancePct >= 1 && volumeRel20 != null && volumeRel20 >= 2 && venueSpreadZScore != null && venueSpreadZScore >= 0;
19239
19359
  const hasShortContinuationConfirmation = direction === "SHORT" && hasVolumeConfirmation;
19240
19360
  let deterministicQuality = 3;
@@ -19301,6 +19421,8 @@ var buildLiquidityZonesGuardrailContext = ({
19301
19421
  transitionStructureExpansionPocket,
19302
19422
  ethReferenceStressPocket,
19303
19423
  solReferenceStressPocket,
19424
+ ethReferenceWeakNonStressPocket,
19425
+ longDirectIndicatorSupportConfirmed,
19304
19426
  hardBlockReasons,
19305
19427
  softBlockReasons,
19306
19428
  deterministicQuality,
@@ -19394,6 +19516,7 @@ Additional Liquidity Zones context:
19394
19516
  - obvLevelAligned=${String(context.obvLevelAligned ?? "n/a")}
19395
19517
  - obvSlopeAligned=${String(context.obvSlopeAligned ?? "n/a")}
19396
19518
  - directIndicatorSupportCount=${String(context.directIndicatorSupportCount ?? "n/a")}
19519
+ - longDirectIndicatorSupportConfirmed=${String(context.longDirectIndicatorSupportConfirmed ?? "n/a")}
19397
19520
  - venueSpreadZScore=${String(context.venueSpreadZScore ?? "n/a")}
19398
19521
  - benchmarkTrendAlignment=${context.benchmarkTrendAlignment ?? "n/a"}
19399
19522
  - btcCorrelation=${String(context.btcCorrelation ?? "n/a")}
@@ -19412,6 +19535,7 @@ Additional Liquidity Zones context:
19412
19535
  - transitionStructureExpansionPocket=${String(context.transitionStructureExpansionPocket)}
19413
19536
  - ethReferenceStressPocket=${String(context.ethReferenceStressPocket)}
19414
19537
  - solReferenceStressPocket=${String(context.solReferenceStressPocket)}
19538
+ - ethReferenceWeakNonStressPocket=${String(context.ethReferenceWeakNonStressPocket)}
19415
19539
  - deterministicQuality=${context.deterministicQuality}
19416
19540
  - approvalAllowedNow=${String(context.approvalAllowedNow)}
19417
19541
  - hardBlockReasons=${JSON.stringify(context.hardBlockReasons)}
@@ -19427,6 +19551,8 @@ Interpretation rules for Liquidity Zones:
19427
19551
  - Top-level derivatives context is BTC benchmark evidence; target-symbol derivatives require targetContext/targetDerived.
19428
19552
  - Do not treat derivatives points, rows, or loaded-history size as approval evidence.
19429
19553
  - A calibrated transition-structure pocket, ETH reference stress pocket, or SOL reference stress pocket can approve a structurally valid retest.
19554
+ - LONG approvals need at least two direct MA/MACD/OBV alignments after calibration.
19555
+ - Moderate ETH reference OI weakness blocks approval unless the deeper ETH reference stress pocket is active.
19430
19556
  - Treat deterministicQuality and approvalAllowedNow as the local normalized gate result.
19431
19557
  `.trim();
19432
19558
  },
@@ -19892,6 +20018,16 @@ var getNestedString2 = (value, path) => {
19892
20018
  }
19893
20019
  return typeof current === "string" ? current : null;
19894
20020
  };
20021
+ var getNestedBoolean2 = (value, path) => {
20022
+ let current = value;
20023
+ for (const segment of path) {
20024
+ if (!isRecord2(current)) {
20025
+ return null;
20026
+ }
20027
+ current = current[segment];
20028
+ }
20029
+ return typeof current === "boolean" ? current : null;
20030
+ };
19895
20031
  var isShortBtcOnlyRecoveryLane = (context, baseContext) => {
19896
20032
  const riskFlags = getNestedRecord2(baseContext, [
19897
20033
  "derivatives",
@@ -19916,23 +20052,59 @@ var isShortBtcOnlyRecoveryLane = (context, baseContext) => {
19916
20052
  const biasConflictState = getReverseTrendlineBiasConflictState(context);
19917
20053
  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;
19918
20054
  };
20055
+ var hasMissingDerivativesRisk = (baseContext) => {
20056
+ const riskFlags = getNestedRecord2(baseContext, [
20057
+ "derivatives",
20058
+ "summary"
20059
+ ])?.riskFlags;
20060
+ return Array.isArray(riskFlags) && riskFlags.includes("missing_derivatives");
20061
+ };
20062
+ var isExtremeVolatilityRecoveryLane = (context, baseContext) => {
20063
+ if (context.hardBlockReasons.length > 0) {
20064
+ return false;
20065
+ }
20066
+ const primaryIssue = getNestedString2(baseContext, [
20067
+ "gateFeatures",
20068
+ "decisionHints",
20069
+ "primaryIssue"
20070
+ ]);
20071
+ const approveBias = getNestedString2(baseContext, [
20072
+ "gateFeatures",
20073
+ "decisionHints",
20074
+ "approveBias"
20075
+ ]);
20076
+ const upCloseStreak = getNestedNumber2(baseContext, [
20077
+ "regime",
20078
+ "momentum",
20079
+ "upCloseStreak"
20080
+ ]);
20081
+ const adaptiveChannelFlipUp = getNestedBoolean2(baseContext, [
20082
+ "regime",
20083
+ "trend",
20084
+ "adaptiveChannel",
20085
+ "flipUp"
20086
+ ]);
20087
+ const atrPctRank100 = getNestedNumber2(baseContext, [
20088
+ "regime",
20089
+ "volatility",
20090
+ "percentiles",
20091
+ "atrPctRank100"
20092
+ ]);
20093
+ return primaryIssue === "extreme_volatility" && approveBias === "reject" && upCloseStreak != null && upCloseStreak <= 2 && adaptiveChannelFlipUp === false && atrPctRank100 != null && atrPctRank100 <= 99 && !hasMissingDerivativesRisk(baseContext);
20094
+ };
19919
20095
  var getBaseContextQualityPromotion = (context, signal) => {
19920
20096
  const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
19921
20097
  if (!baseContext) {
19922
20098
  return null;
19923
20099
  }
19924
- return isShortBtcOnlyRecoveryLane(context, baseContext) ? 4 : null;
20100
+ return isShortBtcOnlyRecoveryLane(context, baseContext) || isExtremeVolatilityRecoveryLane(context, baseContext) ? 4 : null;
19925
20101
  };
19926
20102
  var getBaseContextApprovalBlockReasons = (context, signal) => {
19927
20103
  const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
19928
20104
  if (!baseContext) {
19929
20105
  return [];
19930
20106
  }
19931
- const riskFlags = getNestedRecord2(baseContext, [
19932
- "derivatives",
19933
- "summary"
19934
- ])?.riskFlags;
19935
- const hasMissingDerivatives = Array.isArray(riskFlags) && riskFlags.includes("missing_derivatives");
20107
+ const hasMissingDerivatives = hasMissingDerivativesRisk(baseContext);
19936
20108
  const volumeRel20 = getNestedNumber2(baseContext, [
19937
20109
  "participation",
19938
20110
  "volume",
@@ -19968,6 +20140,10 @@ var getBaseContextApprovalBlockReasons = (context, signal) => {
19968
20140
  context,
19969
20141
  baseContext
19970
20142
  );
20143
+ const extremeVolatilityRecoveryLane = isExtremeVolatilityRecoveryLane(
20144
+ context,
20145
+ baseContext
20146
+ );
19971
20147
  const reasons = [];
19972
20148
  if (hasMissingDerivatives) {
19973
20149
  reasons.push("missing_derivatives");
@@ -19987,7 +20163,7 @@ var getBaseContextApprovalBlockReasons = (context, signal) => {
19987
20163
  if (context.signalDirection === "SHORT" && biasConflictState === "btc_only" && context.distance != null && context.distance <= 60) {
19988
20164
  reasons.push("short_btc_conflict_too_shallow");
19989
20165
  }
19990
- if (context.signalDirection === "SHORT" && atrPctZScore != null && atrPctZScore >= 2 && !shortBtcOnlyRecoveryLane) {
20166
+ if (context.signalDirection === "SHORT" && atrPctZScore != null && atrPctZScore >= 2 && !shortBtcOnlyRecoveryLane && !extremeVolatilityRecoveryLane) {
19991
20167
  reasons.push("short_extreme_volatility");
19992
20168
  }
19993
20169
  if (context.signalDirection === "SHORT" && rangePosition20 != null && rangePosition20 < 0.2) {
@@ -20008,7 +20184,9 @@ var buildReverseTrendLineGateFeatures = ({
20008
20184
  context,
20009
20185
  signal,
20010
20186
  approvalBlockReasons,
20011
- deterministicRejectionScore
20187
+ deterministicRejectionScore,
20188
+ approvalLane,
20189
+ extremeVolatilityRecoveryPocket
20012
20190
  }) => {
20013
20191
  const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
20014
20192
  const volumeRel20 = getNestedNumber2(baseContext, [
@@ -20042,6 +20220,8 @@ var buildReverseTrendLineGateFeatures = ({
20042
20220
  volatilityState,
20043
20221
  rangePositionState,
20044
20222
  highQualityBouncePocket: context.deterministicQuality >= 4 && approvalBlockReasons.length === 0 && (bounceAcceptance === "rejection" || bounceAcceptance === "follow_through"),
20223
+ extremeVolatilityRecoveryPocket,
20224
+ approvalLane,
20045
20225
  deterministicRejectionScore
20046
20226
  };
20047
20227
  };
@@ -20166,7 +20346,14 @@ var buildReverseTrendlineAiContext = (signal) => {
20166
20346
  },
20167
20347
  signal
20168
20348
  );
20169
- const reverseTrendLineGateFeatures = buildReverseTrendLineGateFeatures({
20349
+ const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
20350
+ const extremeVolatilityRecoveryPocket = baseContext != null ? isExtremeVolatilityRecoveryLane(
20351
+ {
20352
+ hardBlockReasons
20353
+ },
20354
+ baseContext
20355
+ ) : false;
20356
+ const baseReverseTrendLineGateFeatures = buildReverseTrendLineGateFeatures({
20170
20357
  context: {
20171
20358
  ...structural,
20172
20359
  ...timing,
@@ -20175,17 +20362,28 @@ var buildReverseTrendlineAiContext = (signal) => {
20175
20362
  },
20176
20363
  signal,
20177
20364
  approvalBlockReasons,
20178
- deterministicRejectionScore
20365
+ deterministicRejectionScore,
20366
+ approvalLane: "watch",
20367
+ extremeVolatilityRecoveryPocket
20179
20368
  });
20369
+ const highScoreBouncePocket = baseReverseTrendLineGateFeatures.highQualityBouncePocket && deterministicRejectionScore != null && deterministicRejectionScore >= 7;
20370
+ const approvalLane = highScoreBouncePocket ? "high_score_bounce" : extremeVolatilityRecoveryPocket ? "extreme_volatility_recovery" : "watch";
20371
+ const approvalAllowedNow = approvalLane !== "watch";
20372
+ const finalApprovalBlockReasons = !approvalAllowedNow && promotedDeterministicQuality >= 4 && approvalBlockReasons.length === 0 ? [...approvalBlockReasons, "rejection_score_below_gate"] : approvalBlockReasons;
20373
+ const finalDeterministicQuality = approvalAllowedNow ? Math.max(promotedDeterministicQuality, 4) : promotedDeterministicQuality;
20374
+ const reverseTrendLineGateFeatures = {
20375
+ ...baseReverseTrendLineGateFeatures,
20376
+ approvalLane
20377
+ };
20180
20378
  return {
20181
20379
  ...structural,
20182
20380
  ...timing,
20183
20381
  reverseTrendLineGateFeatures,
20184
- deterministicQuality: promotedDeterministicQuality,
20382
+ deterministicQuality: finalDeterministicQuality,
20185
20383
  deterministicRejectionScore,
20186
- approvalAllowedNow: promotedDeterministicQuality >= 4 && approvalBlockReasons.length === 0,
20384
+ approvalAllowedNow,
20187
20385
  hardBlockReasons,
20188
- approvalBlockReasons
20386
+ approvalBlockReasons: finalApprovalBlockReasons
20189
20387
  };
20190
20388
  };
20191
20389
  var withReverseTrendLineGateFeatures = ({
@@ -20230,6 +20428,8 @@ var getHardBlockReasonText2 = (reason) => {
20230
20428
  return "LONG bounce distance sits in a weak mid-distance pocket";
20231
20429
  case "short_follow_through_overrated":
20232
20430
  return "SHORT follow-through bounce is not reliable enough for quality 5";
20431
+ case "rejection_score_below_gate":
20432
+ return "deterministic rejection score is below the current strict gate";
20233
20433
  default:
20234
20434
  return reason;
20235
20435
  }
@@ -20314,6 +20514,8 @@ Additional ReverseTrendLine context:
20314
20514
  - reverseTrendLineGateVolatilityState=${context.reverseTrendLineGateFeatures.volatilityState}
20315
20515
  - reverseTrendLineGateRangePositionState=${context.reverseTrendLineGateFeatures.rangePositionState}
20316
20516
  - reverseTrendLineGateHighQualityBouncePocket=${String(context.reverseTrendLineGateFeatures.highQualityBouncePocket)}
20517
+ - reverseTrendLineGateExtremeVolatilityRecoveryPocket=${String(context.reverseTrendLineGateFeatures.extremeVolatilityRecoveryPocket)}
20518
+ - reverseTrendLineGateApprovalLane=${context.reverseTrendLineGateFeatures.approvalLane}
20317
20519
  - approvalAllowedNow=${context.approvalAllowedNow}
20318
20520
  - hardBlockReasons=${context.hardBlockReasons.join(", ") || "none"}
20319
20521
  - approvalBlockReasons=${context.approvalBlockReasons.join(", ") || "none"}
@@ -20731,6 +20933,7 @@ var buildTrendFollowGateFeatures = ({
20731
20933
  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;
20732
20934
  const referenceDerivativesCadencePocket = !referenceDerivativesLossBlock && (legacyCadencePocket || referenceDerivativesOiCompressionPocket || referenceDerivativesXrpFundingPocket || referenceDerivativesSolFlushPocket);
20733
20935
  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;
20936
+ const referenceDerivativesCleanCadencePocket = referenceDerivativesCadencePocket && !derivativesShortFlushOiPocket;
20734
20937
  const normalVolatilityCadencePocket = marketVolatilityState === TREND_FOLLOW_ALLOWED_VOLATILITY_STATE;
20735
20938
  return {
20736
20939
  setupStopDistanceAtr,
@@ -20773,9 +20976,10 @@ var buildTrendFollowGateFeatures = ({
20773
20976
  referenceDerivativesSolFlushPocket,
20774
20977
  referenceDerivativesLossBlock,
20775
20978
  referenceDerivativesCadencePocket,
20979
+ referenceDerivativesCleanCadencePocket,
20776
20980
  referenceDerivativesOpeningPocket,
20777
20981
  normalVolatilityCadencePocket,
20778
- highQualityCadencePocket: normalVolatilityCadencePocket && (referenceDerivativesCadencePocket || referenceDerivativesOpeningPocket)
20982
+ highQualityCadencePocket: normalVolatilityCadencePocket && referenceDerivativesCleanCadencePocket
20779
20983
  };
20780
20984
  };
20781
20985
  var buildTrendFollowGuardrailContext = ({
@@ -21035,6 +21239,7 @@ Additional TrendFollow context:
21035
21239
  - trendFollowGateReferenceDerivativesSolFlushPocket=${String(context.trendFollowGateFeatures.referenceDerivativesSolFlushPocket)}
21036
21240
  - trendFollowGateReferenceDerivativesLossBlock=${String(context.trendFollowGateFeatures.referenceDerivativesLossBlock)}
21037
21241
  - trendFollowGateReferenceDerivativesCadencePocket=${String(context.trendFollowGateFeatures.referenceDerivativesCadencePocket)}
21242
+ - trendFollowGateReferenceDerivativesCleanCadencePocket=${String(context.trendFollowGateFeatures.referenceDerivativesCleanCadencePocket)}
21038
21243
  - trendFollowGateReferenceDerivativesOpeningPocket=${String(context.trendFollowGateFeatures.referenceDerivativesOpeningPocket)}
21039
21244
  - trendFollowGateNormalVolatilityCadencePocket=${String(context.trendFollowGateFeatures.normalVolatilityCadencePocket)}
21040
21245
  - trendFollowGateHighQualityCadencePocket=${String(context.trendFollowGateFeatures.highQualityCadencePocket)}
@@ -21054,7 +21259,7 @@ Interpretation rules for TrendFollow:
21054
21259
  - The ATR trailing stop is the structural invalidation line and also updates while a position is open.
21055
21260
  - Prefer breakouts aligned with shared market context and backed by participation.
21056
21261
  - Late, thin, crowded, inside-range, adverse-delta, weak-momentum, or weak-volume-structure breakouts should be downgraded even if the pivot cross is valid.
21057
- - 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.
21262
+ - 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.
21058
21263
  - Treat deterministicQuality and approvalAllowedNow as the local normalized gate result.
21059
21264
  `.trim();
21060
21265
  },
@@ -21091,6 +21296,8 @@ var LONG_BROAD_MARKET_SHORT_FLUSH_PCT_ABOVE_MA20_MIN = 0.95;
21091
21296
  var LONG_BROAD_MARKET_SHORT_FLUSH_BTC_VS_ALT_RETURN_24H_MIN = 0;
21092
21297
  var SHORT_ASIA_LONG_FLUSH_LOW_CMC_FEAR_GREED_MAX = 18;
21093
21298
  var SHORT_ASIA_LONG_FLUSH_ADVANCERS_MAX = 2;
21299
+ var BNB_REFERENCE_OI_CHANGE_PCT_4H_RISK_MIN = 0;
21300
+ var DERIVATIVES_DATA_UNAVAILABLE_STRESS_CMC_FEAR_GREED_MAX = 25;
21094
21301
  var toMtfAlignmentForTrendShift = ({
21095
21302
  direction,
21096
21303
  mtfAlignment
@@ -21358,9 +21565,14 @@ var buildTrendShiftGuardrailContext = ({
21358
21565
  gateRelative?.cmcFearGreedValueChange24h ?? baseCmcFearGreed?.valueChange24h
21359
21566
  );
21360
21567
  const cmcFearGreedStale = gateRelative?.cmcFearGreedStale === true || baseCmcFearGreed?.stale === true;
21568
+ const derivativesDataUnavailable = derivativesRiskFlags.includes("missing_derivatives") || derivativesRiskFlags.includes("stale_derivatives");
21569
+ const derivativesDataUnavailableStressRisk = derivativesDataUnavailable && cmcFearGreedStale !== true && cmcFearGreedValue != null && cmcFearGreedValue <= DERIVATIVES_DATA_UNAVAILABLE_STRESS_CMC_FEAR_GREED_MAX;
21361
21570
  const derivatives1hLiqShort = asFiniteNumber6(
21362
21571
  baseContext?.derivatives?.intervals?.["1h"]?.liqShort
21363
21572
  );
21573
+ const bnbReferenceOiChangePct4h = asFiniteNumber6(
21574
+ baseContext?.derivatives?.referenceContexts?.BNBUSDT?.intervals?.["1h"]?.oiChangePct4h
21575
+ );
21364
21576
  const btcAltRegime = typeof gateRelative?.btcAltRegime === "string" ? gateRelative.btcAltRegime : null;
21365
21577
  const btcAltRegimeStale = gateRelative?.btcAltRegimeStale === true;
21366
21578
  const cmcExchangeLiquidityVolumeChange24hPct = asFiniteNumber6(
@@ -21385,8 +21597,8 @@ var buildTrendShiftGuardrailContext = ({
21385
21597
  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";
21386
21598
  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";
21387
21599
  const q4ShortAsiaFlushCandidate = signalContext.signalDirection === "SHORT" && derivativesPressure === "neutral" && derivativesFlushSupport && sessionPrimary === "asia" && !sessionIsOverlap && distanceAtrRatio < 0.7 && slopeAbs >= 0.08 && closeVsAvgPctAbs >= 0.12;
21388
- 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");
21389
- const shortNeutralBearChannelBreakdownCandidate = signalContext.signalDirection === "SHORT" && breakoutState === "below_low_level" && derivativesPressure === "neutral" && atrPctZScore != null && atrPctZScore >= 0 && atrPctZScore < 1 && adaptiveChannelDirection === "bear";
21600
+ 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");
21601
+ const shortNeutralBearChannelBreakdownCandidate = signalContext.signalDirection === "SHORT" && breakoutState === "below_low_level" && derivativesPressure === "neutral" && !derivativesDataUnavailableStressRisk && atrPctZScore != null && atrPctZScore >= 0 && atrPctZScore < 1 && adaptiveChannelDirection === "bear";
21390
21602
  let deterministicQuality = 3;
21391
21603
  if (hardBlockReasons.length > 0) {
21392
21604
  deterministicQuality = signalContext.confirmedFlip ? 2 : 1;
@@ -21454,6 +21666,10 @@ var buildTrendShiftGuardrailContext = ({
21454
21666
  hardBlockReasons.push("us_short_oi_not_expanding");
21455
21667
  }
21456
21668
  }
21669
+ if (deterministicQuality >= 5 && derivativesDataUnavailableStressRisk) {
21670
+ deterministicQuality = 4;
21671
+ hardBlockReasons.push("derivatives_data_unavailable_stress");
21672
+ }
21457
21673
  if (deterministicQuality >= 5 && hasDerivativesSummary && !selectiveNeutralQ4Candidate && !shortNeutralBearChannelBreakdownCandidate && derivativesPressure === "neutral" && !derivativesFlushSupport) {
21458
21674
  deterministicQuality = 4;
21459
21675
  hardBlockReasons.push("neutral_derivatives_pressure");
@@ -21476,6 +21692,7 @@ var buildTrendShiftGuardrailContext = ({
21476
21692
  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;
21477
21693
  const lowRewardToVolatilityRisk = rewardToVolatility != null && rewardToVolatility < 0.25;
21478
21694
  const defensiveRewardToVolatilityRisk = rewardToVolatility != null && rewardToVolatility >= 0.25 && rewardToVolatility < 8;
21695
+ const bnbReferenceOiExpansionRisk = bnbReferenceOiChangePct4h != null && bnbReferenceOiChangePct4h >= BNB_REFERENCE_OI_CHANGE_PCT_4H_RISK_MIN;
21479
21696
  const longBtcAltRegimeRisk = signalContext.signalDirection === "LONG" && btcAltRegimeStale !== true && (btcAltRegime === "btc_lead" || btcAltRegime === "risk_off");
21480
21697
  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;
21481
21698
  const cmcExchangeLiquidityVolumeChangeRisk = cmcExchangeLiquidityStale !== true && cmcExchangeLiquidityVolumeChange24hPct != null && (cmcExchangeLiquidityVolumeChange24hPct > -0.1 && cmcExchangeLiquidityVolumeChange24hPct < 0 || cmcExchangeLiquidityVolumeChange24hPct >= 0.1 && cmcExchangeLiquidityVolumeChange24hPct < 0.3);
@@ -21527,6 +21744,10 @@ var buildTrendShiftGuardrailContext = ({
21527
21744
  deterministicQuality = 4;
21528
21745
  hardBlockReasons.push("reward_to_volatility_below_defensive_threshold");
21529
21746
  }
21747
+ if (deterministicQuality >= 5 && bnbReferenceOiExpansionRisk) {
21748
+ deterministicQuality = 4;
21749
+ hardBlockReasons.push("bnb_reference_1h_oi4h_expansion_risk");
21750
+ }
21530
21751
  if (deterministicQuality >= 4 && longBtcAltRegimeRisk) {
21531
21752
  deterministicQuality = 4;
21532
21753
  hardBlockReasons.push("long_btc_alt_regime_risk");
@@ -21553,7 +21774,7 @@ var buildTrendShiftGuardrailContext = ({
21553
21774
  const q4UsClosingOiConfirmationRecoveryCandidate = deterministicQuality === 4 && signalContext.confirmedFlip === true && signalContext.flipDistanceOk === true && sessionPrimary === "us" && sessionWindowPhase === "closing" && hardBlockReasons.length > 0 && hardBlockReasons.every(
21554
21775
  (reason) => q4UsClosingOiConfirmationRecoveryAllowedReasons.includes(reason)
21555
21776
  );
21556
- 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;
21777
+ 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;
21557
21778
  const q4LongAltLeadershipRecoveryAllowedReasons = [
21558
21779
  "flat_or_mixed_oi",
21559
21780
  "neutral_derivatives_pressure",
@@ -21601,8 +21822,10 @@ var buildTrendShiftGuardrailContext = ({
21601
21822
  shortBullSwingStructureRisk,
21602
21823
  shortLowBollingerWidthRisk,
21603
21824
  shortAsiaLongFlushLowCmcBreadthRisk,
21825
+ derivativesDataUnavailableStressRisk,
21604
21826
  lowRewardToVolatilityRisk,
21605
21827
  defensiveRewardToVolatilityRisk,
21828
+ bnbReferenceOiExpansionRisk,
21606
21829
  longBtcAltRegimeRisk,
21607
21830
  longBroadMarketShortFlushRisk,
21608
21831
  cmcExchangeLiquidityVolumeChangeRisk,
@@ -21627,6 +21850,7 @@ var buildTrendShiftGuardrailContext = ({
21627
21850
  cmcFearGreedValue,
21628
21851
  cmcFearGreedValueChange24h,
21629
21852
  derivatives1hLiqShort,
21853
+ bnbReferenceOiChangePct4h,
21630
21854
  btcAltRegime,
21631
21855
  cmcExchangeLiquidityVolumeChange24hPct,
21632
21856
  trendShiftGateFeatures,
@@ -21694,10 +21918,14 @@ var getTrendShiftGuardrailReasonText = (reason) => {
21694
21918
  return "the SHORT flip is in a narrow Bollinger-width compression pocket that has been less reliable, so keep it in watch mode";
21695
21919
  case "short_asia_long_flush_low_cmc_breadth":
21696
21920
  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";
21921
+ case "derivatives_data_unavailable_stress":
21922
+ 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";
21697
21923
  case "low_reward_to_volatility":
21698
21924
  return "the expected reward is too small relative to current volatility after costs, so keep the flip in watch mode";
21699
21925
  case "reward_to_volatility_below_defensive_threshold":
21700
21926
  return "the expected reward is not large enough relative to current volatility for the defensive TrendShift gate after costs";
21927
+ case "bnb_reference_1h_oi4h_expansion_risk":
21928
+ return "BNB reference 1h open interest is expanding over 4h, a historically fragile cross-market state for TrendShift approvals";
21701
21929
  case "long_btc_alt_regime_risk":
21702
21930
  return "the LONG flip is fighting a BTC-led or risk-off alt regime, so keep it in watch mode";
21703
21931
  case "long_broad_market_short_flush_risk":
@@ -21850,8 +22078,11 @@ Additional TrendShift context:
21850
22078
  - defensiveRewardToVolatilityRisk=${String(context.defensiveRewardToVolatilityRisk)}
21851
22079
  - shortBullSwingStructureRisk=${String(context.shortBullSwingStructureRisk)}
21852
22080
  - shortAsiaLongFlushLowCmcBreadthRisk=${String(context.shortAsiaLongFlushLowCmcBreadthRisk)}
22081
+ - derivativesDataUnavailableStressRisk=${String(context.derivativesDataUnavailableStressRisk)}
21853
22082
  - longBtcAltRegimeRisk=${String(context.longBtcAltRegimeRisk)}
21854
22083
  - longBroadMarketShortFlushRisk=${String(context.longBroadMarketShortFlushRisk)}
22084
+ - bnbReferenceOiChangePct4h=${String(context.bnbReferenceOiChangePct4h ?? "n/a")}
22085
+ - bnbReferenceOiExpansionRisk=${String(context.bnbReferenceOiExpansionRisk)}
21855
22086
  - cmcExchangeLiquidityVolumeChangeRisk=${String(context.cmcExchangeLiquidityVolumeChangeRisk)}
21856
22087
  - q4TrendShiftGateFeaturesRecoveryCandidate=${String(context.q4TrendShiftGateFeaturesRecoveryCandidate)}
21857
22088
  - q4UsClosingOiConfirmationRecoveryCandidate=${String(context.q4UsClosingOiConfirmationRecoveryCandidate)}
@@ -21889,12 +22120,14 @@ Interpretation rules for TrendShift:
21889
22120
  - For SHORT, a bullish swing structure is a watch-only warning even when the immediate flip geometry looks q5-strong.
21890
22121
  - For SHORT, a narrow Bollinger-width compression pocket is watch-only even if another q4 recovery condition is present.
21891
22122
  - For SHORT, Asia-session long-flush setups are watch-only when CMC fear/greed and market breadth are already in capitulation.
22123
+ - 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.
21892
22124
  - The defensive live gate requires rewardToVolatility >= 8 when that field is available.
22125
+ - 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.
21893
22126
  - For LONG, BTC-led or risk-off BTC/alt regime is watch-only even when flip geometry is q5-strong.
21894
22127
  - 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.
21895
22128
  - 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.
21896
22129
  - 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.
21897
- - 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.
22130
+ - 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.
21898
22131
  - 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.
21899
22132
  - If hardBlockReasons is not empty, explain exactly what is still missing for confirmation.
21900
22133
  `.trim();
@@ -22210,6 +22443,9 @@ var TRENDLINE_PAYLOAD_PROMPT = `
22210
22443
  - It also includes 'atrPct / breakVsAtrRatio / coinMaSpreadPct / btcMaSpreadPct / aggressivePreBreakPressure / strongNearBreakPressure / weakCleanBreak / compressedCleanBreak / weakBtcLedBreak / weakLongFarBreak'.
22211
22444
  - 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.
22212
22445
  `;
22446
+ var MARKET_CONTEXT_PRIMARY_ISSUE = "market_context_against";
22447
+ var MARKET_CONTEXT_TOTAL_MARKET_CAP_USD_MIN = 233e10;
22448
+ var MARKET_CONTEXT_TREND_PERSISTENCE_MAX = 0.77;
22213
22449
  var getRecord2 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
22214
22450
  var getNestedRecord3 = (source, path) => {
22215
22451
  let current = source;
@@ -22285,6 +22521,22 @@ var buildTrendlineContext = (signal) => {
22285
22521
  const volumeStructurePocIndex = toFiniteNumberOrNull5(
22286
22522
  participationVolumeStructure?.pocIndex
22287
22523
  );
22524
+ const gateDecisionHints = getNestedRecord3(baseContext, [
22525
+ "gateFeatures",
22526
+ "decisionHints"
22527
+ ]);
22528
+ const gatePrimaryIssue = typeof gateDecisionHints?.primaryIssue === "string" ? gateDecisionHints.primaryIssue : null;
22529
+ const cmcGlobalContext = getNestedRecord3(baseContext, [
22530
+ "relative",
22531
+ "cmcGlobal"
22532
+ ]);
22533
+ const cmcTotalMarketCapUsd = toFiniteNumberOrNull5(
22534
+ cmcGlobalContext?.totalMarketCapUsd
22535
+ );
22536
+ const trendRegimeContext = getNestedRecord3(baseContext, ["regime", "trend"]);
22537
+ const trendPersistence = toFiniteNumberOrNull5(
22538
+ trendRegimeContext?.persistence
22539
+ );
22288
22540
  const benchmarkTrendAlignment = typeof benchmarkContext?.trendAlignment === "string" ? benchmarkContext.trendAlignment : null;
22289
22541
  const executionContext = getNestedRecord3(baseContext, [
22290
22542
  "relative",
@@ -22336,7 +22588,7 @@ var buildTrendlineContext = (signal) => {
22336
22588
  if (structural.signalDirection === "SHORT" && (entryTiming === "ready_follow_through" || entryTiming === "ready_retest") && (sessionPrimary === "off_hours" || sessionIsOverlap) && !hardBlockReasons.includes("short_session_risk")) {
22337
22589
  hardBlockReasons.push("short_session_risk");
22338
22590
  }
22339
- const deterministicQuality = getDeterministicTrendlineQuality({
22591
+ const baseDeterministicQuality = getDeterministicTrendlineQuality({
22340
22592
  signalDirection: structural.signalDirection,
22341
22593
  clearBreak: structural.clearBreak,
22342
22594
  nearLineNoise: structural.nearLineNoise,
@@ -22351,16 +22603,18 @@ var buildTrendlineContext = (signal) => {
22351
22603
  entryTiming,
22352
22604
  coinMaSpreadPct
22353
22605
  });
22606
+ 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;
22607
+ const deterministicQuality = marketContextApprovalPocket ? 4 : baseDeterministicQuality;
22354
22608
  const maxAllowedQuality = deterministicQuality;
22355
22609
  const longUsLowVolumeCrowdedShortSqueeze = structural.signalDirection === "LONG" && sessionPrimary === "us" && volumeRel20 != null && volumeRel20 < 0.8 && derivativesRiskFlags.includes("crowded_short") && benchmarkTrendAlignment !== "against_benchmark";
22356
22610
  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";
22357
- const longHighQualitySessionApproval = deterministicQuality >= 5 && sessionPrimary !== "asia";
22611
+ const longHighQualitySessionApproval = baseDeterministicQuality >= 5 && sessionPrimary !== "asia";
22358
22612
  const longStrongDerivativesAlignedApproval = volumeRel20 != null && volumeRel20 >= 1.5 && derivativesDirectionAligned === true;
22359
- 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;
22613
+ 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;
22360
22614
  const longBaseContextApprovalPocket = structural.signalDirection !== "LONG" || longModerateRetestLiquidSessionApproval || longHistoricalApprovalPocket && (longHighQualitySessionApproval || longStrongDerivativesAlignedApproval);
22361
22615
  const shortThinNeutralBenchmarkRisk = structural.signalDirection === "SHORT" && volumeRel20 != null && volumeRel20 < 0.8 && benchmarkTrendAlignment === "neutral";
22362
- const q4ReferenceOiPocApproval = deterministicQuality === 4 && volumeStructurePocIndex != null && volumeStructurePocIndex >= 5 && ethReferenceOiAcceleration != null && ethReferenceOiAcceleration <= -0.5906;
22363
- const approvalAllowedNow = deterministicQuality >= 4 && longBaseContextApprovalPocket && !shortThinNeutralBenchmarkRisk && (deterministicQuality >= 5 || q4ReferenceOiPocApproval);
22616
+ const q4ReferenceOiPocApproval = baseDeterministicQuality === 4 && volumeStructurePocIndex != null && volumeStructurePocIndex >= 5 && ethReferenceOiAcceleration != null && ethReferenceOiAcceleration <= -0.5906;
22617
+ const approvalAllowedNow = marketContextApprovalPocket;
22364
22618
  const trendLineGateFeatures = buildTrendLineGateFeatures({
22365
22619
  structural,
22366
22620
  entryTiming,
@@ -22396,6 +22650,11 @@ var buildTrendlineContext = (signal) => {
22396
22650
  derivativesRiskFlags,
22397
22651
  ethReferenceOiAcceleration,
22398
22652
  oiNotConfirming,
22653
+ gatePrimaryIssue,
22654
+ cmcTotalMarketCapUsd,
22655
+ trendPersistence,
22656
+ marketContextApprovalPocket,
22657
+ baseDeterministicQuality,
22399
22658
  longUsLowVolumeCrowdedShortSqueeze,
22400
22659
  longHighQualitySessionApproval,
22401
22660
  longStrongDerivativesAlignedApproval,
@@ -22645,6 +22904,11 @@ Additional TrendLine context:
22645
22904
  - trendline.volumeStructurePocIndex=${formatPromptNumber(trendlineContext.volumeStructurePocIndex, 0)}
22646
22905
  - trendline.ethReferenceOiAcceleration=${formatPromptNumber(trendlineContext.ethReferenceOiAcceleration, 3)}
22647
22906
  - trendline.q4ReferenceOiPocApproval=${String(trendlineContext.q4ReferenceOiPocApproval)}
22907
+ - trendline.gatePrimaryIssue=${trendlineContext.gatePrimaryIssue ?? "n/a"}
22908
+ - trendline.cmcTotalMarketCapUsd=${formatPromptNumber(trendlineContext.cmcTotalMarketCapUsd, 0)}
22909
+ - trendline.trendPersistence=${formatPromptNumber(trendlineContext.trendPersistence, 3)}
22910
+ - trendline.marketContextApprovalPocket=${String(trendlineContext.marketContextApprovalPocket)}
22911
+ - trendline.baseDeterministicQuality=${String(trendlineContext.baseDeterministicQuality)}
22648
22912
  - trendline.weakCleanBreak=${String(trendlineContext.weakCleanBreak)}
22649
22913
  - trendline.compressedCleanBreak=${String(trendlineContext.compressedCleanBreak)}
22650
22914
  - trendline.weakBtcLedBreak=${String(trendlineContext.weakBtcLedBreak)}
@@ -22923,10 +23187,13 @@ VolumeDivergence addon:
22923
23187
  `;
22924
23188
  var VOLUME_DIVERGENCE_PAYLOAD_PROMPT = `
22925
23189
  - \`payload.additionalIndicators.volumeDivergenceContext\` contains a compact divergence-strength summary:
22926
- divergenceKind / confirmationPrice / confirmationReady / structureAdvanced / reboundFromPivotPct / confirmationDistancePct / priceDisplacementPct / divergenceAmplitudeAtrRatio / reclaimPct / confirmationCandleQuality / volumeDivergenceStrength / deltaAligned / coinBiasAligned / btcBiasAligned / derivativesDirectionAligned / derivativesRiskFlags / derivativesLiqSpikeRatio / venueSpreadZScore / volumeRel20 / rangePosition20 / deterministicQuality / approvalAllowedNow / structuralHardBlockReasons / maxAllowedQuality.
23190
+ 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.
22927
23191
  - Use this context as the explicit strategy-specific summary instead of trying to derive the same conclusion again only from generic candles.
22928
23192
  - 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.
22929
23193
  `;
23194
+ var BTC_OI_CHANGE_PCT_1H_15M_MAX = -0.32;
23195
+ var SOL_OPEN_INTEREST_15M_MIN = 101e5;
23196
+ var XRP_FUNDING_Z_SCORE_15M_MAX = -1.2;
22930
23197
  var toFiniteNumberOrNull6 = (value) => {
22931
23198
  if (typeof value === "number" && Number.isFinite(value)) {
22932
23199
  return value;
@@ -23293,6 +23560,23 @@ var getVolumeDivergenceContext = (signal) => {
23293
23560
  const derivativesRiskFlags = getStringArray3(derivativesSummary?.riskFlags);
23294
23561
  const derivativesFundingZScore = toFiniteNumberOrNull6(derivatives15m?.fundingZScore) ?? toFiniteNumberOrNull6(derivatives1h?.fundingZScore);
23295
23562
  const derivativesLiqSpikeRatio = toFiniteNumberOrNull6(derivatives15m?.liqSpikeRatio) ?? toFiniteNumberOrNull6(derivatives1h?.liqSpikeRatio);
23563
+ const btcOiChangePct1h15m = toFiniteNumberOrNull6(
23564
+ derivatives15m?.oiChangePct1h
23565
+ );
23566
+ const solOpenInterest15m = getNestedNumber3(derivativesContext, [
23567
+ "referenceContexts",
23568
+ "SOLUSDT",
23569
+ "intervals",
23570
+ "15m",
23571
+ "openInterest"
23572
+ ]);
23573
+ const xrpFundingZScore15m = getNestedNumber3(derivativesContext, [
23574
+ "referenceContexts",
23575
+ "XRPUSDT",
23576
+ "intervals",
23577
+ "15m",
23578
+ "fundingZScore"
23579
+ ]);
23296
23580
  const marketContext = getRecord3(additional?.marketContext);
23297
23581
  const venueSpreadZScore = getNestedNumber3(marketContext, [
23298
23582
  "execution",
@@ -23392,9 +23676,9 @@ var getVolumeDivergenceContext = (signal) => {
23392
23676
  entryThresholds,
23393
23677
  aiThresholds
23394
23678
  }) : hardBlockReasons.length > 0 ? 2 : 3;
23395
- const longApprovalPocket = signalDirection !== "LONG" || isAtLeast2(confirmationDistancePct, 2) && isAtLeast2(volumeRel20, 1) && isAtLeast2(venueSpreadZScore, 1.5365);
23396
- const shortApprovalPocket = signalDirection !== "SHORT" || isAtMost(venueSpreadZScore, 0) && rangePosition20 != null && rangePosition20 < 0.2;
23397
- const approvalAllowedNow = hardBlockReasons.length === 0 && deterministicQuality >= 4 && confirmationReady && longApprovalPocket && shortApprovalPocket;
23679
+ 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);
23680
+ const maxAllowedQuality = derivativesRegimePocket ? Math.max(deterministicQuality, 4) : deterministicQuality;
23681
+ const approvalAllowedNow = hardBlockReasons.length === 0 && confirmationReady && derivativesRegimePocket && maxAllowedQuality >= 4;
23398
23682
  return {
23399
23683
  signalDirection,
23400
23684
  divergenceKind,
@@ -23427,12 +23711,16 @@ var getVolumeDivergenceContext = (signal) => {
23427
23711
  venueSpreadZScore,
23428
23712
  volumeRel20,
23429
23713
  rangePosition20,
23714
+ btcOiChangePct1h15m,
23715
+ solOpenInterest15m,
23716
+ xrpFundingZScore15m,
23717
+ derivativesRegimePocket,
23430
23718
  sessionPhase,
23431
23719
  hardBlockReasons,
23432
23720
  structuralHardBlockReasons: [...hardBlockReasons],
23433
23721
  deterministicQuality,
23434
23722
  approvalAllowedNow,
23435
- maxAllowedQuality: deterministicQuality
23723
+ maxAllowedQuality
23436
23724
  };
23437
23725
  };
23438
23726
  var getVolumeDivergenceContextFromPayload = (payload, signal) => {
@@ -23483,6 +23771,7 @@ var postProcessAnalysis2 = ({
23483
23771
  );
23484
23772
  const needRetest = finalDirection == null;
23485
23773
  const retestPrice = needRetest ? context.confirmationPrice : null;
23774
+ const approvedQuality = finalDirection != null && context.maxAllowedQuality >= 4 ? Math.max(finalQuality, 4) : finalQuality;
23486
23775
  if (finalDirection == null) {
23487
23776
  return {
23488
23777
  ...analysis,
@@ -23500,7 +23789,7 @@ var postProcessAnalysis2 = ({
23500
23789
  return {
23501
23790
  ...analysis,
23502
23791
  direction: finalDirection,
23503
- quality: finalQuality,
23792
+ quality: approvedQuality,
23504
23793
  needRetest,
23505
23794
  retestPrice,
23506
23795
  takeProfitPrice: signal.prices?.takeProfitPrice ?? null,
@@ -23546,6 +23835,10 @@ Additional VolumeDivergence context:
23546
23835
  - venueSpreadZScore=${context.venueSpreadZScore?.toFixed?.(3) ?? "n/a"}
23547
23836
  - volumeRel20=${context.volumeRel20?.toFixed?.(3) ?? "n/a"}
23548
23837
  - rangePosition20=${context.rangePosition20?.toFixed?.(3) ?? "n/a"}
23838
+ - btcOiChangePct1h15m=${context.btcOiChangePct1h15m?.toFixed?.(3) ?? "n/a"}
23839
+ - solOpenInterest15m=${context.solOpenInterest15m?.toFixed?.(0) ?? "n/a"}
23840
+ - xrpFundingZScore15m=${context.xrpFundingZScore15m?.toFixed?.(3) ?? "n/a"}
23841
+ - derivativesRegimePocket=${context.derivativesRegimePocket}
23549
23842
  - barsSincePivot=${context.barsSincePivot ?? "n/a"}
23550
23843
  - barsBetweenPivotConfirmations=${context.barsBetweenPivotConfirmations ?? "n/a"}
23551
23844
  - entryTiming=${context.entryTiming ?? "n/a"}