@tradejs/strategies 2.0.0 → 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 +502 -68
  2. package/dist/index.mjs +502 -68
  3. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -16516,9 +16516,10 @@ AdaptiveMomentumRibbon addon:
16516
16516
  - \`quality=4\` additionally allows two narrower continuation pockets: oscillatorStrength >= 1.2 with coin bias conflict, structuralRewardRiskRatio >= 2.2 and volumeRel20 <= 1.2, or Europe-session oscillatorStrength >= 1.5 with effortVsResult <= 120.
16517
16517
  - If signal candle range is available, \`signalRangeAtrRatio\` must be >= 1.05 for live approval; weaker signal candles stay in watch mode.
16518
16518
  - The local deterministic gate approves LONG by default. SHORT stays in watch mode except for separately calibrated market-breadth shock pockets.
16519
- - SHORT breadth-shock approvals use two calibrated pockets: BTC-favored breadth shock, or a neutral shared-context breadth exhaustion pocket with marketBreadth.advancers <= 0 and effortVsResult <= 800.
16519
+ - SHORT watch-mode approvals use three calibrated pockets: BTC-favored breadth shock, neutral shared-context breadth exhaustion with marketBreadth.advancers <= 0 and effortVsResult <= 800, or low-CMC benchmark OI contraction with BTC net flow <= 0.
16520
16520
  - A reference-derivatives rotation pocket can approve q4 when XRP 15m OI 4h change >= 1.6 and TRX 15m OI 4h change <= -0.2. It may override weak signal range and the default SHORT watch mode, but never hard signal invalidation.
16521
16521
  - Non-derivatives approvals are demoted when stopDistanceAtr > 4.5 and breakoutBodyAtr > 2.25, because that combination behaves like a chase entry.
16522
+ - All live approvals require a calibrated market-regime floor: tpDistanceAtr >= 2.9, trendAdx >= 15, and benchmarkRelativeStrength1d <= 4 when available.
16522
16523
  - LONG approvals require cmcAltLiquidityRegime to be anything except \`btc_favored\` when that CMC field is available.
16523
16524
  - Non-q5 LONG approvals require targetVsBtcAlpha1h <= 2.4 when that field is available, to avoid chase entries after target already outran BTC.
16524
16525
  - \`quality=4\` continuation approvals require targetVsBtcAlpha4h >= 1, spreadBps >= -10, and cmcFearGreedValueChange7d >= -15 when those fields are available. \`quality=5\` is not capped by this q4-only continuation guard.
@@ -16527,16 +16528,22 @@ AdaptiveMomentumRibbon addon:
16527
16528
  `;
16528
16529
  var ADAPTIVE_MOMENTUM_RIBBON_PAYLOAD_PROMPT = `
16529
16530
  - \`payload.additionalIndicators.adaptiveMomentumRibbonContext\` contains a compact signal summary:
16530
- signalOsc / oscillatorStrength / signalRangeAtrRatio / stopDistanceAtr / breakoutBodyAtr / chaseRiskBlocked / channelState / channelExtensionPct / invalidationDistancePct / structuralRewardRiskRatio / coinBiasAligned / btcBiasAligned / targetVsBtcAlpha1h / targetVsBtcAlpha4h / spreadBps / cmcAltLiquidityRegime / cmcFearGreedValueChange7d / cmcBtcDominanceChange24hPct / baseDecisionApproveBias / marketBreadthAdvancers / marketBreadthAdvanceDeclineRatio / marketBreadthReturn / shortBreadthShockPocket / shortBreadthNeutralPocket / referenceDerivativesRotationPocket / referenceXrpOiChangePct4h15m / referenceTrxOiChangePct4h15m / q4TargetAlpha1Allowed / q4ContinuationAllowed / q4ContinuationBlockReasons / q4ContinuationRecoveryAllowed / derivativesDirectionAligned / derivativesRiskFlags / derivativesFundingZScore / deterministicQuality / approvalAllowedNow / approvalBlockReasons / riskAnnotations.
16531
+ signalOsc / oscillatorStrength / signalRangeAtrRatio / stopDistanceAtr / tpDistanceAtr / breakoutBodyAtr / trendAdx / benchmarkRelativeStrength1d / chaseRiskBlocked / approvalRegimeAllowed / approvalRegimeBlockReasons / channelState / channelExtensionPct / invalidationDistancePct / structuralRewardRiskRatio / coinBiasAligned / btcBiasAligned / targetVsBtcAlpha1h / targetVsBtcAlpha4h / spreadBps / cmcAltLiquidityRegime / cmcTotalMarketCapUsd / cmcFearGreedValueChange7d / cmcBtcDominanceChange24hPct / benchmarkOiChangePct24h1h / btcReferenceTradeFlowNetBaseDelta / baseDecisionApproveBias / marketBreadthAdvancers / marketBreadthAdvanceDeclineRatio / marketBreadthReturn / shortBreadthShockPocket / shortBreadthNeutralPocket / shortCmcBenchmarkContractionPocket / referenceDerivativesRotationPocket / referenceXrpOiChangePct4h15m / referenceTrxOiChangePct4h15m / q4TargetAlpha1Allowed / q4ContinuationAllowed / q4ContinuationBlockReasons / q4ContinuationRecoveryAllowed / derivativesDirectionAligned / derivativesRiskFlags / derivativesFundingZScore / deterministicQuality / approvalAllowedNow / approvalBlockReasons / riskAnnotations.
16531
16532
  - Use this context as the primary strategy-specific interpretation instead of re-deriving it only from generic series.
16532
16533
  `;
16533
16534
  var SHORT_BREADTH_SHOCK_MARKET_BREADTH_RETURN_MAX = -0.01;
16534
16535
  var SHORT_BREADTH_NEUTRAL_EFFORT_VS_RESULT_MAX = 800;
16536
+ var SHORT_CMC_TOTAL_MARKET_CAP_USD_MAX = 229e10;
16537
+ var SHORT_BENCHMARK_OI_CHANGE_PCT_24H_1H_MAX = -4;
16538
+ var SHORT_BTC_REFERENCE_TRADE_FLOW_NET_BASE_DELTA_MAX = 0;
16535
16539
  var Q4_TARGET_VS_BTC_ALPHA_1H_MAX = 2.4;
16536
16540
  var REFERENCE_XRP_OI_CHANGE_PCT_4H_15M_MIN = 1.6;
16537
16541
  var REFERENCE_TRX_OI_CHANGE_PCT_4H_15M_MAX = -0.2;
16538
16542
  var CHASE_STOP_DISTANCE_ATR_MAX = 4.5;
16539
16543
  var CHASE_BREAKOUT_BODY_ATR_MAX = 2.25;
16544
+ var MIN_APPROVAL_TP_DISTANCE_ATR = 2.9;
16545
+ var MIN_APPROVAL_TREND_ADX = 15;
16546
+ var MAX_APPROVAL_BENCHMARK_RELATIVE_STRENGTH_1D = 4;
16540
16547
  var toFiniteNumberOrNull = (value) => {
16541
16548
  if (typeof value === "number" && Number.isFinite(value)) {
16542
16549
  return value;
@@ -16711,6 +16718,19 @@ var getQ4ContinuationBlockReasons = (context) => {
16711
16718
  return reasons;
16712
16719
  };
16713
16720
  var getQ4ContinuationRecoveryAllowed = (context) => context.q4TargetAlpha1Allowed && !context.q4ContinuationAllowed && isInRange(context.effortVsResult, 0, 60) && context.cmcBtcDominanceChange24hPct != null && context.cmcBtcDominanceChange24hPct <= 0;
16721
+ var getApprovalRegimeBlockReasons = (context) => {
16722
+ const reasons = [];
16723
+ if (context.tpDistanceAtr == null || context.tpDistanceAtr < MIN_APPROVAL_TP_DISTANCE_ATR) {
16724
+ reasons.push("low_tp_distance_atr");
16725
+ }
16726
+ if (context.trendAdx == null || context.trendAdx < MIN_APPROVAL_TREND_ADX) {
16727
+ reasons.push("weak_trend_adx");
16728
+ }
16729
+ if (context.benchmarkRelativeStrength1d != null && context.benchmarkRelativeStrength1d > MAX_APPROVAL_BENCHMARK_RELATIVE_STRENGTH_1D) {
16730
+ reasons.push("benchmark_1d_chase_risk");
16731
+ }
16732
+ return reasons;
16733
+ };
16714
16734
  var getDeterministicAdaptiveMomentumRibbonQuality = (context) => {
16715
16735
  if (context.hardBlockReasons.length > 0) {
16716
16736
  return 2;
@@ -16724,8 +16744,11 @@ var getDeterministicAdaptiveMomentumRibbonQuality = (context) => {
16724
16744
  if (context.chaseRiskBlocked && !context.referenceDerivativesRotationPocket) {
16725
16745
  return 3;
16726
16746
  }
16747
+ if (!context.approvalRegimeAllowed) {
16748
+ return 3;
16749
+ }
16727
16750
  if (context.signalDirection === "SHORT") {
16728
- return context.shortBreadthShockPocket || context.shortBreadthNeutralPocket || context.referenceDerivativesRotationPocket ? 4 : 3;
16751
+ return context.shortBreadthShockPocket || context.shortBreadthNeutralPocket || context.shortCmcBenchmarkContractionPocket || context.referenceDerivativesRotationPocket ? 4 : 3;
16729
16752
  }
16730
16753
  if (context.signalDirection === "LONG" && context.cmcAltLiquidityRegime === "btc_favored") {
16731
16754
  return 3;
@@ -16736,12 +16759,12 @@ var getDeterministicAdaptiveMomentumRibbonQuality = (context) => {
16736
16759
  if (causalMomentumLowEffortPocket) {
16737
16760
  return 5;
16738
16761
  }
16762
+ if (context.signalDirection === "LONG" && !context.q4TargetAlpha1Allowed) {
16763
+ return 3;
16764
+ }
16739
16765
  if (context.referenceDerivativesRotationPocket) {
16740
16766
  return 4;
16741
16767
  }
16742
- if (!context.q4TargetAlpha1Allowed) {
16743
- return 3;
16744
- }
16745
16768
  if (context.q4ContinuationRecoveryAllowed) {
16746
16769
  return 4;
16747
16770
  }
@@ -16838,6 +16861,8 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16838
16861
  const candle = getRecord(baseContext?.candle);
16839
16862
  const raw = getRecord(baseContext?.raw);
16840
16863
  const regime = getRecord(baseContext?.regime);
16864
+ const regimeTrend = getRecord(regime?.trend);
16865
+ const regimeTrendAdx = getRecord(regimeTrend?.adx);
16841
16866
  const regimeSession = getRecord(regime?.session);
16842
16867
  const structure = getRecord(baseContext?.structure);
16843
16868
  const localRange = getRecord(structure?.localRange);
@@ -16849,6 +16874,8 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16849
16874
  const gateFeaturesRelative = getRecord(gateFeatures?.relative);
16850
16875
  const gateFeaturesDecisionHints = getRecord(gateFeatures?.decisionHints);
16851
16876
  const baseDerivativesContext = getRecord(baseContext?.derivatives);
16877
+ const baseDerivativesIntervals = getRecord(baseDerivativesContext?.intervals);
16878
+ const baseDerivatives1h = getRecord(baseDerivativesIntervals?.["1h"]);
16852
16879
  const referenceDerivativeContexts = getRecord(
16853
16880
  baseDerivativesContext?.referenceContexts
16854
16881
  );
@@ -16862,6 +16889,11 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16862
16889
  const targetVsBtc = getRecord(relative?.targetVsBtc);
16863
16890
  const cmcGlobal = getRecord(relative?.cmcGlobal);
16864
16891
  const cmcFearGreed = getRecord(relative?.cmcFearGreed);
16892
+ const referenceTradeFlow = getRecord(relative?.referenceTradeFlow);
16893
+ const referenceTradeFlowBySymbol = getRecord(
16894
+ referenceTradeFlow?.tradeFlowBySymbol
16895
+ );
16896
+ const btcReferenceTradeFlow = getRecord(referenceTradeFlowBySymbol?.BTCUSDT);
16865
16897
  const baseMarketBreadth = getRecord(relative?.marketBreadth);
16866
16898
  const structureAcceptance = getRecord(structure?.acceptance);
16867
16899
  const marketContext = getRecord(additional?.marketContext);
@@ -16877,6 +16909,9 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16877
16909
  const benchmarkRelativeStrength1h = toFiniteNumberOrNull(
16878
16910
  benchmark?.relativeStrength1h
16879
16911
  );
16912
+ const benchmarkRelativeStrength1d = toFiniteNumberOrNull(
16913
+ benchmark?.relativeStrength1d
16914
+ );
16880
16915
  const benchmarkTrendAlignment = typeof benchmark?.trendAlignment === "string" ? benchmark.trendAlignment : null;
16881
16916
  const targetVsBtcAlpha1h = toFiniteNumberOrNull(targetVsBtc?.alphaVsBtc1h);
16882
16917
  const targetVsBtcAlpha4h = toFiniteNumberOrNull(targetVsBtc?.alphaVsBtc4h);
@@ -16895,6 +16930,8 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16895
16930
  const stopDistanceAtr = toFiniteNumberOrNull(
16896
16931
  gateFeaturesSetup?.stopDistanceAtr
16897
16932
  );
16933
+ const tpDistanceAtr = toFiniteNumberOrNull(gateFeaturesSetup?.tpDistanceAtr);
16934
+ const trendAdx = toFiniteNumberOrNull(regimeTrendAdx?.adx);
16898
16935
  const breakoutBodyAtr = toFiniteNumberOrNull(
16899
16936
  structureAcceptance?.breakoutBodyAtr
16900
16937
  );
@@ -16907,12 +16944,21 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16907
16944
  );
16908
16945
  const referenceDerivativesRotationPocket = referenceXrpOiChangePct4h15m != null && referenceXrpOiChangePct4h15m >= REFERENCE_XRP_OI_CHANGE_PCT_4H_15M_MIN && referenceTrxOiChangePct4h15m != null && referenceTrxOiChangePct4h15m <= REFERENCE_TRX_OI_CHANGE_PCT_4H_15M_MAX;
16909
16946
  const cmcAltLiquidityRegime = typeof cmcGlobal?.altLiquidityRegime === "string" && cmcGlobal.altLiquidityRegime.trim().length > 0 ? cmcGlobal.altLiquidityRegime : null;
16947
+ const cmcTotalMarketCapUsd = toFiniteNumberOrNull(
16948
+ cmcGlobal?.totalMarketCapUsd
16949
+ );
16910
16950
  const cmcFearGreedValueChange7d = toFiniteNumberOrNull(
16911
16951
  cmcFearGreed?.valueChange7d
16912
16952
  );
16913
16953
  const cmcBtcDominanceChange24hPct = toFiniteNumberOrNull(
16914
16954
  cmcGlobal?.btcDominanceChange24hPct
16915
16955
  );
16956
+ const benchmarkOiChangePct24h1h = toFiniteNumberOrNull(
16957
+ baseDerivatives1h?.oiChangePct24h
16958
+ );
16959
+ const btcReferenceTradeFlowNetBaseDelta = toFiniteNumberOrNull(
16960
+ btcReferenceTradeFlow?.netBaseDelta
16961
+ );
16916
16962
  const baseDecisionApproveBias = gateFeaturesDecisionHints?.approveBias === "support" || gateFeaturesDecisionHints?.approveBias === "neutral" || gateFeaturesDecisionHints?.approveBias === "reject" ? gateFeaturesDecisionHints.approveBias : null;
16917
16963
  const marketBreadthAdvanceDeclineRatio = toFiniteNumberOrNull(
16918
16964
  marketBreadth?.advanceDeclineRatio
@@ -16921,6 +16967,7 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16921
16967
  const marketBreadthReturn = toFiniteNumberOrNull(gateFeaturesRelative?.marketBreadthReturn) ?? toFiniteNumberOrNull(marketBreadth?.equalWeightedReturn);
16922
16968
  const shortBreadthShockPocket = signalDirection === "SHORT" && cmcAltLiquidityRegime === "btc_favored" && marketBreadthAdvanceDeclineRatio != null && marketBreadthAdvanceDeclineRatio <= 0 && marketBreadthReturn != null && marketBreadthReturn <= SHORT_BREADTH_SHOCK_MARKET_BREADTH_RETURN_MAX;
16923
16969
  const shortBreadthNeutralPocket = signalDirection === "SHORT" && baseDecisionApproveBias === "neutral" && marketBreadthAdvancers != null && marketBreadthAdvancers <= 0 && marketBreadthReturn != null && marketBreadthReturn <= 0 && isInRange(effortVsResult, 0, SHORT_BREADTH_NEUTRAL_EFFORT_VS_RESULT_MAX);
16970
+ const shortCmcBenchmarkContractionPocket = signalDirection === "SHORT" && cmcTotalMarketCapUsd != null && cmcTotalMarketCapUsd <= SHORT_CMC_TOTAL_MARKET_CAP_USD_MAX && benchmarkOiChangePct24h1h != null && benchmarkOiChangePct24h1h <= SHORT_BENCHMARK_OI_CHANGE_PCT_24H_1H_MAX && btcReferenceTradeFlowNetBaseDelta != null && btcReferenceTradeFlowNetBaseDelta <= SHORT_BTC_REFERENCE_TRADE_FLOW_NET_BASE_DELTA_MAX;
16924
16971
  const q4TargetAlpha1Allowed = targetVsBtcAlpha1h == null || targetVsBtcAlpha1h <= Q4_TARGET_VS_BTC_ALPHA_1H_MAX;
16925
16972
  const q4ContinuationBlockReasons = getQ4ContinuationBlockReasons({
16926
16973
  targetVsBtcAlpha4h,
@@ -16934,6 +16981,12 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16934
16981
  effortVsResult,
16935
16982
  cmcBtcDominanceChange24hPct
16936
16983
  });
16984
+ const approvalRegimeBlockReasons = baseContextAvailable ? getApprovalRegimeBlockReasons({
16985
+ tpDistanceAtr,
16986
+ trendAdx,
16987
+ benchmarkRelativeStrength1d
16988
+ }) : [];
16989
+ const approvalRegimeAllowed = approvalRegimeBlockReasons.length === 0;
16937
16990
  const hardBlockReasons = [];
16938
16991
  if (invalidated) {
16939
16992
  hardBlockReasons.push("invalidated");
@@ -16973,6 +17026,7 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16973
17026
  if (chaseRiskBlocked && !referenceDerivativesRotationPocket) {
16974
17027
  approvalBlockReasons.push("chase_entry_risk");
16975
17028
  }
17029
+ approvalBlockReasons.push(...approvalRegimeBlockReasons);
16976
17030
  if (breakoutRetestQuality != null && breakoutRetestQuality < 0.25) {
16977
17031
  riskAnnotations.push("weak_retest_quality");
16978
17032
  }
@@ -16985,7 +17039,7 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16985
17039
  if (signalDirection === "LONG" && derivativesPressure === "crowded_long" || signalDirection === "SHORT" && derivativesPressure === "crowded_short") {
16986
17040
  riskAnnotations.push("derivatives_pressure_conflict");
16987
17041
  }
16988
- if (signalDirection === "SHORT" && !(shortBreadthShockPocket || shortBreadthNeutralPocket || referenceDerivativesRotationPocket)) {
17042
+ if (signalDirection === "SHORT" && !(shortBreadthShockPocket || shortBreadthNeutralPocket || shortCmcBenchmarkContractionPocket || referenceDerivativesRotationPocket)) {
16989
17043
  approvalBlockReasons.push("short_disabled");
16990
17044
  }
16991
17045
  if (signalDirection === "LONG" && cmcAltLiquidityRegime === "btc_favored") {
@@ -17004,8 +17058,13 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
17004
17058
  oscillatorStrength,
17005
17059
  signalRangeAtrRatio,
17006
17060
  stopDistanceAtr,
17061
+ tpDistanceAtr,
17007
17062
  breakoutBodyAtr,
17063
+ trendAdx,
17064
+ benchmarkRelativeStrength1d,
17008
17065
  chaseRiskBlocked,
17066
+ approvalRegimeAllowed,
17067
+ approvalRegimeBlockReasons,
17009
17068
  kcMidline,
17010
17069
  kcUpper,
17011
17070
  kcLower,
@@ -17042,14 +17101,18 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
17042
17101
  spreadBias,
17043
17102
  spreadSeverity,
17044
17103
  cmcAltLiquidityRegime,
17104
+ cmcTotalMarketCapUsd,
17045
17105
  cmcFearGreedValueChange7d,
17046
17106
  cmcBtcDominanceChange24hPct,
17107
+ benchmarkOiChangePct24h1h,
17108
+ btcReferenceTradeFlowNetBaseDelta,
17047
17109
  baseDecisionApproveBias,
17048
17110
  marketBreadthAdvancers,
17049
17111
  marketBreadthAdvanceDeclineRatio,
17050
17112
  marketBreadthReturn,
17051
17113
  shortBreadthShockPocket,
17052
17114
  shortBreadthNeutralPocket,
17115
+ shortCmcBenchmarkContractionPocket,
17053
17116
  referenceDerivativesRotationPocket,
17054
17117
  referenceXrpOiChangePct4h15m,
17055
17118
  referenceTrxOiChangePct4h15m,
@@ -17077,8 +17140,13 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
17077
17140
  oscillatorStrength,
17078
17141
  signalRangeAtrRatio,
17079
17142
  stopDistanceAtr,
17143
+ tpDistanceAtr,
17080
17144
  breakoutBodyAtr,
17145
+ trendAdx,
17146
+ benchmarkRelativeStrength1d,
17081
17147
  chaseRiskBlocked,
17148
+ approvalRegimeAllowed,
17149
+ approvalRegimeBlockReasons,
17082
17150
  kcMidline,
17083
17151
  kcUpper,
17084
17152
  kcLower,
@@ -17115,14 +17183,18 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
17115
17183
  spreadBias,
17116
17184
  spreadSeverity,
17117
17185
  cmcAltLiquidityRegime,
17186
+ cmcTotalMarketCapUsd,
17118
17187
  cmcFearGreedValueChange7d,
17119
17188
  cmcBtcDominanceChange24hPct,
17189
+ benchmarkOiChangePct24h1h,
17190
+ btcReferenceTradeFlowNetBaseDelta,
17120
17191
  baseDecisionApproveBias,
17121
17192
  marketBreadthAdvancers,
17122
17193
  marketBreadthAdvanceDeclineRatio,
17123
17194
  marketBreadthReturn,
17124
17195
  shortBreadthShockPocket,
17125
17196
  shortBreadthNeutralPocket,
17197
+ shortCmcBenchmarkContractionPocket,
17126
17198
  referenceDerivativesRotationPocket,
17127
17199
  referenceXrpOiChangePct4h15m,
17128
17200
  referenceTrxOiChangePct4h15m,
@@ -17225,8 +17297,13 @@ Additional AdaptiveMomentumRibbon context:
17225
17297
  - oscillatorStrength=${context.oscillatorStrength?.toFixed?.(3) ?? "n/a"}
17226
17298
  - signalRangeAtrRatio=${context.signalRangeAtrRatio?.toFixed?.(3) ?? "n/a"}
17227
17299
  - stopDistanceAtr=${context.stopDistanceAtr?.toFixed?.(3) ?? "n/a"}
17300
+ - tpDistanceAtr=${context.tpDistanceAtr?.toFixed?.(3) ?? "n/a"}
17228
17301
  - breakoutBodyAtr=${context.breakoutBodyAtr?.toFixed?.(3) ?? "n/a"}
17302
+ - trendAdx=${context.trendAdx?.toFixed?.(3) ?? "n/a"}
17303
+ - benchmarkRelativeStrength1d=${context.benchmarkRelativeStrength1d?.toFixed?.(3) ?? "n/a"}
17229
17304
  - chaseRiskBlocked=${context.chaseRiskBlocked}
17305
+ - approvalRegimeAllowed=${context.approvalRegimeAllowed}
17306
+ - approvalRegimeBlockReasons=${context.approvalRegimeBlockReasons.join(", ") || "none"}
17230
17307
  - channelState=${context.channelState}
17231
17308
  - channelBiasAligned=${context.channelBiasAligned}
17232
17309
  - channelExtensionPct=${context.channelExtensionPct?.toFixed?.(3) ?? "n/a"}%
@@ -17256,14 +17333,18 @@ Additional AdaptiveMomentumRibbon context:
17256
17333
  - spreadBias=${context.spreadBias ?? "n/a"}
17257
17334
  - spreadSeverity=${context.spreadSeverity ?? "n/a"}
17258
17335
  - cmcAltLiquidityRegime=${context.cmcAltLiquidityRegime ?? "n/a"}
17336
+ - cmcTotalMarketCapUsd=${context.cmcTotalMarketCapUsd?.toFixed?.(0) ?? "n/a"}
17259
17337
  - cmcFearGreedValueChange7d=${context.cmcFearGreedValueChange7d?.toFixed?.(3) ?? "n/a"}
17260
17338
  - cmcBtcDominanceChange24hPct=${context.cmcBtcDominanceChange24hPct?.toFixed?.(3) ?? "n/a"}
17339
+ - benchmarkOiChangePct24h1h=${context.benchmarkOiChangePct24h1h?.toFixed?.(3) ?? "n/a"}
17340
+ - btcReferenceTradeFlowNetBaseDelta=${context.btcReferenceTradeFlowNetBaseDelta?.toFixed?.(3) ?? "n/a"}
17261
17341
  - baseDecisionApproveBias=${context.baseDecisionApproveBias ?? "n/a"}
17262
17342
  - marketBreadthAdvancers=${context.marketBreadthAdvancers?.toFixed?.(0) ?? "n/a"}
17263
17343
  - marketBreadthAdvanceDeclineRatio=${context.marketBreadthAdvanceDeclineRatio?.toFixed?.(3) ?? "n/a"}
17264
17344
  - marketBreadthReturn=${context.marketBreadthReturn?.toFixed?.(5) ?? "n/a"}
17265
17345
  - shortBreadthShockPocket=${context.shortBreadthShockPocket}
17266
17346
  - shortBreadthNeutralPocket=${context.shortBreadthNeutralPocket}
17347
+ - shortCmcBenchmarkContractionPocket=${context.shortCmcBenchmarkContractionPocket}
17267
17348
  - referenceDerivativesRotationPocket=${context.referenceDerivativesRotationPocket}
17268
17349
  - referenceXrpOiChangePct4h15m=${context.referenceXrpOiChangePct4h15m?.toFixed?.(3) ?? "n/a"}
17269
17350
  - referenceTrxOiChangePct4h15m=${context.referenceTrxOiChangePct4h15m?.toFixed?.(3) ?? "n/a"}
@@ -17327,12 +17408,13 @@ var MIN_APPROVAL_CHANNEL_WIDTH_PCT = 2;
17327
17408
  var MIN_HIGH_CONFIDENCE_CHANNEL_WIDTH_PCT = 2;
17328
17409
  var MIN_APPROVAL_VOLUME_REL20 = 10;
17329
17410
  var MIN_SHORT_APPROVAL_VOLUME_REL20 = 7;
17330
- var MAX_SHORT_RECOVERY_TARGET_LIQ_IMBALANCE_1H = -0.97;
17331
- var MIN_SHORT_RECOVERY_TARGET_LIQ_SPIKE_RATIO_1H = 5.7;
17332
- var MAX_SHORT_RECOVERY_ETH_FUNDING_RATE_1H = 37e-4;
17411
+ var MAX_REFERENCE_SHORT_RECOVERY_ETH_LIQ_IMBALANCE_1H = -0.99;
17333
17412
  var MAX_XRP_SHORT_RECOVERY_BTC_VS_ALT_RETURN_24H = -0.03;
17334
17413
  var MAX_XRP_SHORT_RECOVERY_FUNDING_Z_SCORE_1H = -1.8;
17335
17414
  var MIN_XRP_OI_REJECT_BIAS_BLOCK_15M = 25e7;
17415
+ var MAX_XRP_OI_RECOVERY_BTC_DOMINANCE_PCT = 58.45;
17416
+ var MIN_XRP_OI_RECOVERY_MARKET_BREADTH_SYMBOLS = 27;
17417
+ var MIN_XRP_OI_RECOVERY_BNB_FUNDING_CHANGE_1H = 0;
17336
17418
  var MAX_APPROVAL_RSI = 75;
17337
17419
  var MIN_APPROVAL_BB_WIDTH_RANK_100 = 50;
17338
17420
  var buildAdaptiveTrendChannelGuardrailContext = ({
@@ -17341,6 +17423,7 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17341
17423
  }) => {
17342
17424
  const targetDerivatives1h = baseContext?.derivatives?.intervals?.["1h"];
17343
17425
  const ethDerivatives1h = baseContext?.derivatives?.referenceContexts?.["ETHUSDT"]?.intervals?.["1h"];
17426
+ const bnbDerivativesSummary = baseContext?.derivatives?.referenceContexts?.["BNBUSDT"]?.summary;
17344
17427
  const xrpDerivatives15m = baseContext?.derivatives?.referenceContexts?.["XRPUSDT"]?.intervals?.["15m"];
17345
17428
  const xrpDerivatives1h = baseContext?.derivatives?.referenceContexts?.["XRPUSDT"]?.intervals?.["1h"];
17346
17429
  const targetDerivatives1hStale = targetDerivatives1h?.stale === true;
@@ -17358,10 +17441,17 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17358
17441
  baseContext?.regime?.volatility?.percentiles?.bbWidthRank100
17359
17442
  );
17360
17443
  const trendFollowState = baseContext?.regime?.trend?.trendFollow?.state ?? null;
17444
+ const volatilityState = baseContext?.regime?.volatility?.state ?? null;
17361
17445
  const h4VolatilityState = baseContext?.mtf?.summary?.h4VolatilityState ?? null;
17362
17446
  const benchmarkTrendAlignment = baseContext?.relative?.benchmark?.trendAlignment ?? null;
17363
17447
  const cmcExchangeLiquidityAligned = typeof baseContext?.gateFeatures?.relative?.cmcExchangeLiquidityAligned === "boolean" ? baseContext.gateFeatures.relative.cmcExchangeLiquidityAligned : null;
17364
17448
  const cmcExchangeLiquidityStale = typeof baseContext?.gateFeatures?.relative?.cmcExchangeLiquidityStale === "boolean" ? baseContext.gateFeatures.relative.cmcExchangeLiquidityStale : null;
17449
+ const cmcBtcDominancePct = asFiniteNumber(
17450
+ baseContext?.relative?.cmcGlobal?.btcDominancePct
17451
+ );
17452
+ const marketBreadthSymbolsCount = asFiniteNumber(
17453
+ baseContext?.relative?.marketBreadth?.symbolsCount
17454
+ );
17365
17455
  const baseApproveBias = baseContext?.gateFeatures?.decisionHints?.approveBias ?? null;
17366
17456
  const targetLiqImbalance1h = asFiniteNumber(
17367
17457
  targetDerivatives1h?.liqImbalance
@@ -17370,7 +17460,11 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17370
17460
  targetDerivatives1h?.liqSpikeRatio
17371
17461
  );
17372
17462
  const targetLiqTotal1h = asFiniteNumber(targetDerivatives1h?.liqTotal);
17463
+ const ethLiqImbalance1h = asFiniteNumber(ethDerivatives1h?.liqImbalance);
17373
17464
  const ethFundingRate1h = asFiniteNumber(ethDerivatives1h?.fundingRate);
17465
+ const bnbFundingChange1h = asFiniteNumber(
17466
+ bnbDerivativesSummary?.fundingChange1h
17467
+ );
17374
17468
  const xrpOpenInterest15m = asFiniteNumber(xrpDerivatives15m?.openInterest);
17375
17469
  const xrpPriceOiDivergenceType = baseContext?.derivatives?.referenceContexts?.["XRPUSDT"]?.summary?.priceOiDivergenceType ?? null;
17376
17470
  const xrpFundingZScore1h = asFiniteNumber(xrpDerivatives1h?.fundingZScore);
@@ -17405,12 +17499,14 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17405
17499
  const cmcExchangeLiquiditySupportsApproval = direction === "LONG" && cmcExchangeLiquidityAligned === true && cmcExchangeLiquidityStale !== true;
17406
17500
  const trendFollowSupportsApproval = direction === "LONG" && trendFollowState === "bull";
17407
17501
  const longApprovalSetup = direction === "LONG" && breakoutAligned && h4VolatilityState === "expanded" && cmcExchangeLiquiditySupportsApproval && trendFollowSupportsApproval && breakoutDistancePct >= minApprovalBreakoutDistancePct && channelWidthPct >= MIN_APPROVAL_CHANNEL_WIDTH_PCT && (volumeRel20 ?? 0) >= minApprovalVolumeRel20 && (rsi ?? Number.POSITIVE_INFINITY) <= MAX_APPROVAL_RSI && (bbWidthRank100 ?? 0) >= MIN_APPROVAL_BB_WIDTH_RANK_100;
17408
- const shortRecoverySetup = direction === "SHORT" && targetDerivatives1hStale !== true && ethDerivatives1hStale !== true && targetLiqImbalance1h != null && targetLiqSpikeRatio1h != null && ethFundingRate1h != null && targetLiqImbalance1h <= MAX_SHORT_RECOVERY_TARGET_LIQ_IMBALANCE_1H && targetLiqSpikeRatio1h >= MIN_SHORT_RECOVERY_TARGET_LIQ_SPIKE_RATIO_1H && ethFundingRate1h <= MAX_SHORT_RECOVERY_ETH_FUNDING_RATE_1H;
17409
- const xrpShortRecoverySetup = 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;
17410
- if (xrpOpenInterest15m != null && xrpOpenInterest15m >= MIN_XRP_OI_REJECT_BIAS_BLOCK_15M && baseApproveBias === "reject" && !xrpShortRecoverySetup) {
17502
+ const xrpBtcShortRecoverySetup = direction === "SHORT" && xrpDerivatives1hStale !== true && xrpPriceOiDivergenceType === "price_down_oi_up" && btcVsAltReturn24h != null && btcVsAltReturn24h <= MAX_XRP_SHORT_RECOVERY_BTC_VS_ALT_RETURN_24H && xrpFundingZScore1h != null && xrpFundingZScore1h <= MAX_XRP_SHORT_RECOVERY_FUNDING_Z_SCORE_1H;
17503
+ const xrpEthShortRecoverySetup = direction === "SHORT" && xrpDerivatives1hStale !== true && ethDerivatives1hStale !== true && xrpPriceOiDivergenceType === "price_down_oi_up" && xrpFundingZScore1h != null && xrpFundingZScore1h <= MAX_XRP_SHORT_RECOVERY_FUNDING_Z_SCORE_1H && ethLiqImbalance1h != null && ethLiqImbalance1h <= MAX_REFERENCE_SHORT_RECOVERY_ETH_LIQ_IMBALANCE_1H;
17504
+ const xrpShortRecoverySetup = xrpBtcShortRecoverySetup || xrpEthShortRecoverySetup;
17505
+ const xrpOiReferenceRecoverySetup = xrpOpenInterest15m != null && xrpOpenInterest15m >= MIN_XRP_OI_REJECT_BIAS_BLOCK_15M && baseApproveBias === "reject" && volatilityState === "expanded" && cmcBtcDominancePct != null && cmcBtcDominancePct <= MAX_XRP_OI_RECOVERY_BTC_DOMINANCE_PCT && marketBreadthSymbolsCount != null && marketBreadthSymbolsCount >= MIN_XRP_OI_RECOVERY_MARKET_BREADTH_SYMBOLS && bnbFundingChange1h != null && bnbFundingChange1h >= MIN_XRP_OI_RECOVERY_BNB_FUNDING_CHANGE_1H;
17506
+ if (xrpOpenInterest15m != null && xrpOpenInterest15m >= MIN_XRP_OI_REJECT_BIAS_BLOCK_15M && baseApproveBias === "reject" && !xrpShortRecoverySetup && !xrpOiReferenceRecoverySetup) {
17411
17507
  hardBlockReasons.push("xrp_oi_reject_bias");
17412
17508
  }
17413
- const approvalSetup = longApprovalSetup || shortRecoverySetup || xrpShortRecoverySetup;
17509
+ const approvalSetup = longApprovalSetup || xrpShortRecoverySetup || xrpOiReferenceRecoverySetup;
17414
17510
  const highConfidenceSetup = longApprovalSetup && breakoutDistancePct >= MIN_HIGH_CONFIDENCE_BREAKOUT_DISTANCE_PCT && channelWidthPct >= MIN_HIGH_CONFIDENCE_CHANNEL_WIDTH_PCT;
17415
17511
  let deterministicQuality = 3;
17416
17512
  if (hardBlockReasons.length > 0) {
@@ -17468,14 +17564,19 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17468
17564
  rsi,
17469
17565
  bbWidthRank100,
17470
17566
  trendFollowState,
17567
+ volatilityState,
17471
17568
  h4VolatilityState,
17472
17569
  benchmarkTrendAlignment,
17473
17570
  cmcExchangeLiquidityAligned,
17474
17571
  cmcExchangeLiquidityStale,
17572
+ cmcBtcDominancePct,
17573
+ marketBreadthSymbolsCount,
17475
17574
  targetLiqImbalance1h,
17476
17575
  targetLiqSpikeRatio1h,
17477
17576
  targetLiqTotal1h,
17577
+ ethLiqImbalance1h,
17478
17578
  ethFundingRate1h,
17579
+ bnbFundingChange1h,
17479
17580
  xrpOpenInterest15m,
17480
17581
  xrpPriceOiDivergenceType,
17481
17582
  xrpFundingZScore1h,
@@ -17551,12 +17652,17 @@ Additional AdaptiveTrendChannel context:
17551
17652
  - rsi=${String(context.rsi ?? "n/a")}
17552
17653
  - bbWidthRank100=${String(context.bbWidthRank100 ?? "n/a")}
17553
17654
  - trendFollowState=${context.trendFollowState ?? "n/a"}
17655
+ - volatilityState=${context.volatilityState ?? "n/a"}
17554
17656
  - h4VolatilityState=${context.h4VolatilityState ?? "n/a"}
17555
17657
  - benchmarkTrendAlignment=${context.benchmarkTrendAlignment ?? "n/a"}
17658
+ - cmcBtcDominancePct=${String(context.cmcBtcDominancePct ?? "n/a")}
17659
+ - marketBreadthSymbolsCount=${String(context.marketBreadthSymbolsCount ?? "n/a")}
17556
17660
  - targetLiqImbalance1h=${String(context.targetLiqImbalance1h ?? "n/a")}
17557
17661
  - targetLiqSpikeRatio1h=${String(context.targetLiqSpikeRatio1h ?? "n/a")}
17558
17662
  - targetLiqTotal1h=${String(context.targetLiqTotal1h ?? "n/a")}
17663
+ - ethLiqImbalance1h=${String(context.ethLiqImbalance1h ?? "n/a")}
17559
17664
  - ethFundingRate1h=${String(context.ethFundingRate1h ?? "n/a")}
17665
+ - bnbFundingChange1h=${String(context.bnbFundingChange1h ?? "n/a")}
17560
17666
  - xrpOpenInterest15m=${String(context.xrpOpenInterest15m ?? "n/a")}
17561
17667
  - xrpPriceOiDivergenceType=${context.xrpPriceOiDivergenceType ?? "n/a"}
17562
17668
  - xrpFundingZScore1h=${String(context.xrpFundingZScore1h ?? "n/a")}
@@ -17574,7 +17680,7 @@ Interpretation rules for AdaptiveTrendChannel:
17574
17680
  - The centerline is the adaptive rail; floor/roof are volatility-scaled invalidation bands.
17575
17681
  - Prefer flips with reasonable distance from the centerline and confirmation from shared market context.
17576
17682
  - Thin participation, missing shared-context confirmation, or missing liquidation-shock recovery evidence should downgrade the setup.
17577
- - A high-XRP-OI reject bias should remain blocked unless a narrow XRP reference SHORT recovery setup is present.
17683
+ - A high-XRP-OI reject bias should remain blocked unless a narrow XRP reference SHORT recovery setup or expanded CMC/BNB/breadth recovery setup is present.
17578
17684
  - Treat deterministicQuality and approvalAllowedNow as the local normalized gate result.
17579
17685
  `.trim();
17580
17686
  },
@@ -17791,6 +17897,7 @@ var buildEntryStopTargetFigures = ({
17791
17897
  var MFR_CALIBRATED_LONG_TARGET_VS_BTC_RATIO_RETURN_24H_MAX = -3.3;
17792
17898
  var MFR_CALIBRATED_LONG_ETH_VS_BTC_VOLUME_RATIO_MIN = 0.54;
17793
17899
  var MFR_CALIBRATED_LONG_H1_RANGE_POSITION_MAX = 0.08;
17900
+ var MFR_AI_LONG_STOP_DISTANCE_ATR_MIN = 24;
17794
17901
  var getMarketFlushReversalLongReboundPocketFeatures = (baseContext) => ({
17795
17902
  targetVsBtcRatioReturn24h: toFiniteNumberOrNull2(
17796
17903
  baseContext?.relative?.targetVsBtc?.ratioReturn24h
@@ -17808,6 +17915,21 @@ var isMarketFlushReversalCalibratedLongReboundPocket = ({
17808
17915
  ethVsBtcVolumeRatio,
17809
17916
  h1RangePosition
17810
17917
  }) => direction === "LONG" && targetVsBtcRatioReturn24h != null && targetVsBtcRatioReturn24h <= MFR_CALIBRATED_LONG_TARGET_VS_BTC_RATIO_RETURN_24H_MAX && (ethVsBtcVolumeRatio != null && ethVsBtcVolumeRatio >= MFR_CALIBRATED_LONG_ETH_VS_BTC_VOLUME_RATIO_MIN || h1RangePosition != null && h1RangePosition <= MFR_CALIBRATED_LONG_H1_RANGE_POSITION_MAX);
17918
+ var getMarketFlushReversalAiLongPocketFeatures = (baseContext) => ({
17919
+ stopDistanceAtr: toFiniteNumberOrNull2(
17920
+ baseContext?.gateFeatures?.setup?.stopDistanceAtr
17921
+ ),
17922
+ cmcIndexRegime: baseContext?.relative?.cmcIndexes?.indexRegime ?? null,
17923
+ cmcIndexStale: typeof baseContext?.relative?.cmcIndexes?.stale === "boolean" ? baseContext.relative.cmcIndexes.stale : null,
17924
+ rsiState: baseContext?.regime?.momentum?.rsiState ?? null
17925
+ });
17926
+ var isMarketFlushReversalValidatedAiLongPocket = ({
17927
+ direction,
17928
+ stopDistanceAtr,
17929
+ cmcIndexRegime,
17930
+ cmcIndexStale,
17931
+ rsiState
17932
+ }) => direction === "LONG" && stopDistanceAtr != null && stopDistanceAtr >= MFR_AI_LONG_STOP_DISTANCE_ATR_MIN && cmcIndexRegime === "risk_off" && cmcIndexStale === false && rsiState === "oversold";
17811
17933
 
17812
17934
  // src/MarketFlushReversal/guardrails.ts
17813
17935
  var toFiniteNumberOrNull3 = (value) => {
@@ -17897,6 +18019,12 @@ var buildMarketFlushReversalGuardrailContext = ({
17897
18019
  direction
17898
18020
  });
17899
18021
  const { targetVsBtcRatioReturn24h, ethVsBtcVolumeRatio, h1RangePosition } = longReboundPocketFeatures;
18022
+ const aiLongPocketFeatures = getMarketFlushReversalAiLongPocketFeatures(baseContext);
18023
+ const validatedAiLongPocket = isMarketFlushReversalValidatedAiLongPocket({
18024
+ ...aiLongPocketFeatures,
18025
+ direction
18026
+ });
18027
+ const { stopDistanceAtr, cmcIndexRegime, cmcIndexStale, rsiState } = aiLongPocketFeatures;
17900
18028
  const approvalBlockReasons = [];
17901
18029
  const riskAnnotations = [];
17902
18030
  if (direction == null) approvalBlockReasons.push("missing_direction");
@@ -17907,22 +18035,22 @@ var buildMarketFlushReversalGuardrailContext = ({
17907
18035
  approvalBlockReasons.push("local_participation_not_confirmed");
17908
18036
  }
17909
18037
  if (!marketContextAvailable) {
17910
- approvalBlockReasons.push("missing_broad_market_derivatives");
18038
+ riskAnnotations.push("missing_broad_market_derivatives");
17911
18039
  }
17912
18040
  if (marketRiskFlags.includes("stale_derivatives")) {
17913
- approvalBlockReasons.push("stale_broad_market_derivatives");
18041
+ riskAnnotations.push("stale_broad_market_derivatives");
17914
18042
  }
17915
18043
  if (marketContextAvailable && broadMarketFlushDirection == null) {
17916
- approvalBlockReasons.push("no_broad_market_flush");
18044
+ riskAnnotations.push("no_broad_market_flush");
17917
18045
  }
17918
18046
  if (direction != null && broadMarketFlushDirection != null && broadMarketFlushDirection !== direction) {
17919
- approvalBlockReasons.push("broad_market_flush_direction_mismatch");
18047
+ riskAnnotations.push("broad_market_flush_direction_mismatch");
17920
18048
  }
17921
18049
  if (direction === "SHORT") {
17922
18050
  approvalBlockReasons.push("short_flush_rebound_pocket_not_validated");
17923
18051
  }
17924
- if (direction === "LONG" && !calibratedLongRebound) {
17925
- approvalBlockReasons.push("calibrated_long_rebound_missing");
18052
+ if (direction === "LONG" && !validatedAiLongPocket) {
18053
+ approvalBlockReasons.push("validated_long_ai_pocket_missing");
17926
18054
  }
17927
18055
  if (signalContext.marketFlushConfirmed !== true) {
17928
18056
  riskAnnotations.push("market_flush_not_available_at_core_time");
@@ -17946,7 +18074,12 @@ var buildMarketFlushReversalGuardrailContext = ({
17946
18074
  targetVsBtcRatioReturn24h,
17947
18075
  ethVsBtcVolumeRatio,
17948
18076
  h1RangePosition,
17949
- calibratedLongRebound
18077
+ calibratedLongRebound,
18078
+ stopDistanceAtr,
18079
+ cmcIndexRegime,
18080
+ cmcIndexStale,
18081
+ rsiState,
18082
+ validatedAiLongPocket
17950
18083
  };
17951
18084
  return {
17952
18085
  ...signalContext,
@@ -18045,6 +18178,11 @@ Additional Market Flush Reversal context:
18045
18178
  - ethVsBtcVolumeRatio=${String(context.marketFlushReversalGateFeatures.ethVsBtcVolumeRatio ?? "n/a")}
18046
18179
  - h1RangePosition=${String(context.marketFlushReversalGateFeatures.h1RangePosition ?? "n/a")}
18047
18180
  - calibratedLongRebound=${String(context.marketFlushReversalGateFeatures.calibratedLongRebound)}
18181
+ - stopDistanceAtr=${String(context.marketFlushReversalGateFeatures.stopDistanceAtr ?? "n/a")}
18182
+ - cmcIndexRegime=${context.marketFlushReversalGateFeatures.cmcIndexRegime ?? "n/a"}
18183
+ - cmcIndexStale=${String(context.marketFlushReversalGateFeatures.cmcIndexStale ?? "n/a")}
18184
+ - rsiState=${context.marketFlushReversalGateFeatures.rsiState ?? "n/a"}
18185
+ - validatedAiLongPocket=${String(context.marketFlushReversalGateFeatures.validatedAiLongPocket)}
18048
18186
  - approvalAllowedNow=${String(context.approvalAllowedNow)}
18049
18187
  - deterministicQuality=${String(context.deterministicQuality)}
18050
18188
  - approvalBlockReasons=${context.approvalBlockReasons.join(",") || "none"}
@@ -18157,6 +18295,7 @@ var buildDoubleTapGateFeatures = ({
18157
18295
  defaultApprovalAllowed,
18158
18296
  q4AltDispersionOk,
18159
18297
  q4DerivativesCmcRiskOk,
18298
+ q4DerivativesDirectionSessionOk,
18160
18299
  strictMomentumApproved,
18161
18300
  strictMomentumRoc1dOk
18162
18301
  }) => {
@@ -18179,6 +18318,7 @@ var buildDoubleTapGateFeatures = ({
18179
18318
  q4AltDispersionOk,
18180
18319
  q4DerivativesPocket,
18181
18320
  q4DerivativesCmcRiskOk,
18321
+ q4DerivativesDirectionSessionOk,
18182
18322
  strictMomentumApproved,
18183
18323
  strictMomentumRoc1dOk
18184
18324
  };
@@ -18357,7 +18497,8 @@ var buildDoubleTapAiContext = (payload) => {
18357
18497
  const q4CmcApproval = legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && baseIndicatorCandidate && cmcBtcDominanceChange24hPct != null && cmcBtcDominanceChange24hPct > Q4_CMC_BTC_DOMINANCE_CHANGE_MIN && cmcBtcDominanceChange24hPct <= Q4_CMC_BTC_DOMINANCE_CHANGE_MAX && altDispersion24h != null && altDispersion24h < Q4_ALT_DISPERSION_24H_MAX;
18358
18498
  const q4DerivativesBadCmcPocket = btcVsAltReturn24h != null && cmc20ToCmc100RatioChange24hPct != null && btcVsAltReturn24h <= Q4_DERIVATIVES_BAD_BTC_VS_ALT_RETURN_24H_MAX && cmc20ToCmc100RatioChange24hPct <= Q4_DERIVATIVES_BAD_CMC20_TO_CMC100_CHANGE_24H_MAX;
18359
18499
  const q4DerivativesPocket = baseContextAvailable && btcVsAltReturn24h != null && ethCrowdingPersistenceBars != null && solFundingZScore15m != null && btcVsAltReturn24h <= Q4_DERIVATIVES_BTC_VS_ALT_RETURN_24H_MAX && ethCrowdingPersistenceBars >= Q4_DERIVATIVES_ETH_CROWDING_PERSISTENCE_MIN && solFundingZScore15m <= Q4_DERIVATIVES_SOL_FUNDING_Z_SCORE_15M_MAX;
18360
- const q4DerivativesApproval = q4DerivativesPocket && !q4DerivativesBadCmcPocket;
18500
+ const q4DerivativesDirectionSessionOk = q4DerivativesPocket ? signalDirection === "LONG" ? primarySession === "europe" : signalDirection === "SHORT" ? true : false : null;
18501
+ const q4DerivativesApproval = q4DerivativesPocket && q4DerivativesDirectionSessionOk === true && !q4DerivativesBadCmcPocket;
18361
18502
  const softBlockReasons = [
18362
18503
  ...legacyShapeCandidate && sessionWindowPhase !== "active" ? ["inactive_session_window"] : [],
18363
18504
  ...legacyShapeCandidate && (executionScore == null || executionScore < MIN_EXECUTION_SCORE_FOR_AI_GATE) ? ["low_or_missing_execution_score"] : [],
@@ -18369,12 +18510,15 @@ var buildDoubleTapAiContext = (payload) => {
18369
18510
  ...legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && cmcBtcDominanceChange24hPct == null ? ["missing_cmc_btc_dominance_change"] : [],
18370
18511
  ...legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && cmcBtcDominanceChange24hPct != null && (cmcBtcDominanceChange24hPct <= Q4_CMC_BTC_DOMINANCE_CHANGE_MIN || cmcBtcDominanceChange24hPct > Q4_CMC_BTC_DOMINANCE_CHANGE_MAX) ? ["cmc_btc_dominance_change_outside_band"] : [],
18371
18512
  ...legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && cmcBtcDominanceChange24hPct != null && cmcBtcDominanceChange24hPct > Q4_CMC_BTC_DOMINANCE_CHANGE_MIN && cmcBtcDominanceChange24hPct <= Q4_CMC_BTC_DOMINANCE_CHANGE_MAX && altDispersion24h == null ? ["missing_alt_dispersion_24h_for_q4"] : [],
18372
- ...legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && altDispersion24h != null && altDispersion24h >= Q4_ALT_DISPERSION_24H_MAX ? ["alt_dispersion_24h_too_high_for_q4"] : []
18513
+ ...legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && altDispersion24h != null && altDispersion24h >= Q4_ALT_DISPERSION_24H_MAX ? ["alt_dispersion_24h_too_high_for_q4"] : [],
18514
+ ...q4CmcApproval ? ["legacy_q4_structural_observation_only"] : [],
18515
+ ...q4DerivativesPocket && signalDirection === "LONG" && q4DerivativesDirectionSessionOk === false ? ["long_q4_derivatives_outside_europe_session"] : [],
18516
+ ...q4DerivativesPocket && signalDirection == null ? ["missing_signal_direction_for_q4_derivatives"] : []
18373
18517
  ];
18374
18518
  const highPrecisionApprovalBlocked = legacyHighPrecisionShapeCandidate && !highPrecisionCmcApproval && !q4DerivativesApproval;
18375
- const q4DerivativesApprovalBlocked = q4DerivativesPocket && !q4DerivativesApproval && !highPrecisionCmcApproval && !q4CmcApproval;
18376
- const q4ApprovalBlocked = legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && !q4CmcApproval && !q4DerivativesApproval;
18377
- const approvalSourceAllowed = highPrecisionCmcApproval || q4CmcApproval || q4DerivativesApproval;
18519
+ const q4DerivativesApprovalBlocked = q4DerivativesPocket && !q4DerivativesApproval && !highPrecisionCmcApproval;
18520
+ const q4ApprovalBlocked = legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && !q4DerivativesApproval;
18521
+ const approvalSourceAllowed = highPrecisionCmcApproval || q4DerivativesApproval;
18378
18522
  const approvalBlocked = !approvalSourceAllowed && (highPrecisionApprovalBlocked || q4ApprovalBlocked || q4DerivativesApprovalBlocked);
18379
18523
  const defaultApprovalAllowed = structuralHardBlockReasons.length === 0 && approvalSourceAllowed && !approvalBlocked;
18380
18524
  const strictMomentumRoc1dOk = roc1d == null ? null : roc1d >= STRICT_MOMENTUM_ROC1D_MIN;
@@ -18405,10 +18549,11 @@ var buildDoubleTapAiContext = (payload) => {
18405
18549
  defaultApprovalAllowed,
18406
18550
  q4AltDispersionOk: altDispersion24h == null ? null : altDispersion24h < Q4_ALT_DISPERSION_24H_MAX,
18407
18551
  q4DerivativesCmcRiskOk: btcVsAltReturn24h == null || cmc20ToCmc100RatioChange24hPct == null ? null : !q4DerivativesBadCmcPocket,
18552
+ q4DerivativesDirectionSessionOk,
18408
18553
  strictMomentumApproved: strictMomentumApprovalAllowedNow,
18409
18554
  strictMomentumRoc1dOk
18410
18555
  });
18411
- const deterministicQuality = structuralHardBlockReasons.length > 0 ? Math.min(geometryQuality, 2) : highPrecisionCmcApproval ? 5 : q4CmcApproval || q4DerivativesApproval ? 4 : Math.min(geometryQuality, 3);
18556
+ const deterministicQuality = structuralHardBlockReasons.length > 0 ? Math.min(geometryQuality, 2) : highPrecisionCmcApproval ? 5 : q4DerivativesApproval ? 4 : Math.min(geometryQuality, 3);
18412
18557
  return {
18413
18558
  ...context,
18414
18559
  baseContextAvailable,
@@ -18438,6 +18583,7 @@ var buildDoubleTapAiContext = (payload) => {
18438
18583
  ethCrowdingPersistenceBars,
18439
18584
  solFundingZScore15m,
18440
18585
  altDispersion24h,
18586
+ q4DerivativesDirectionSessionOk,
18441
18587
  doubleTapGateFeatures,
18442
18588
  structuralHardBlockReasons,
18443
18589
  softBlockReasons,
@@ -18542,6 +18688,7 @@ Additional DoubleTap context:
18542
18688
  - doubleTapGateQ4AltDispersionOk=${String(context.doubleTapGateFeatures.q4AltDispersionOk ?? "n/a")}
18543
18689
  - doubleTapGateQ4DerivativesPocket=${String(context.doubleTapGateFeatures.q4DerivativesPocket)}
18544
18690
  - doubleTapGateQ4DerivativesCmcRiskOk=${String(context.doubleTapGateFeatures.q4DerivativesCmcRiskOk ?? "n/a")}
18691
+ - doubleTapGateQ4DerivativesDirectionSessionOk=${String(context.doubleTapGateFeatures.q4DerivativesDirectionSessionOk ?? "n/a")}
18545
18692
  - doubleTapGateStrictMomentumApproved=${String(context.doubleTapGateFeatures.strictMomentumApproved)}
18546
18693
  - doubleTapGateStrictMomentumRoc1dOk=${String(context.doubleTapGateFeatures.strictMomentumRoc1dOk ?? "n/a")}
18547
18694
  - deterministicQuality=${String(context.deterministicQuality)}
@@ -18558,9 +18705,9 @@ Interpretation rules for DoubleTap:
18558
18705
  - Extremely tiny breaks can still be early noise; live approval needs support from baseContext.
18559
18706
  - Treat deterministicQuality and approvalAllowedNow as the normalized local gate result.
18560
18707
  - Local q5 approval needs the high-precision pocket plus active session window, execution score >= 35, lowTouchCount20 >= 1, aligned volume structure, no benchmark conflict, and CMC alt volume change <= 0.5.
18561
- - Local q4 approval can come from the structural approval pocket plus active session window, execution score >= 35, lowTouchCount20 >= 1, -0.3 < CMC BTC dominance change <= -0.05, and BTC/alt dispersion 24h < 0.06.
18562
- - Local q4 approval can also come 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.
18563
- - Main local approval additionally needs strict momentum confirmation with ROC1D >= -5.25 for structural q4/q5 approvals; the derivatives reference q4 pocket is already momentum/positioning filtered and does not require that ROC gate.
18708
+ - The legacy structural q4 CMC pocket is retained only as observation context and should not be treated as local approval.
18709
+ - Local q4 approval comes from the derivatives reference pocket: BTC underperforms alts by at least 0.9%, ETH crowding persistence >= 140, SOL 15m funding z-score <= 0.2, unless BTC underperforms alts by at least 1.4% while CMC20/CMC100 ratio change <= -0.0007; LONG q4 derivatives approval additionally requires the Europe session, while SHORT q4 derivatives approval has no session-side restriction.
18710
+ - Main local approval additionally needs strict momentum confirmation with ROC1D >= -5.25 for q5 approval; the derivatives reference q4 pocket is already momentum/positioning filtered and does not require that ROC gate.
18564
18711
  - A good long has two comparable lows and a clean close above the neckline.
18565
18712
  - A good short has two comparable highs and a clean close below the neckline.
18566
18713
  - Venue spread, trend bias, body strength, and reward-to-volatility are diagnostics for this gate, not strict local blockers.
@@ -18630,6 +18777,7 @@ var asFiniteNumber2 = (value) => {
18630
18777
  const parsed = Number(value);
18631
18778
  return Number.isFinite(parsed) ? parsed : null;
18632
18779
  };
18780
+ var asNullableFiniteNumber = (value) => value == null ? null : asFiniteNumber2(value);
18633
18781
  var asStringArray2 = (value) => Array.isArray(value) ? value.filter(
18634
18782
  (entry) => typeof entry === "string" && entry.trim().length > 0
18635
18783
  ) : [];
@@ -18638,8 +18786,12 @@ var MIN_Q3_UPGRADE_REACTION_CLOSE_DISTANCE_PCT = 1.5;
18638
18786
  var MIN_Q3_UPGRADE_BODY_STRENGTH = 0.65;
18639
18787
  var MIN_Q3_UPGRADE_VOLUME_REL20 = 1;
18640
18788
  var MAX_APPROVAL_CMC_FEAR_GREED_VALUE = 39;
18789
+ var MAX_APPROVAL_PRICE_DISTANCE_TO_MA_SLOW_ATR = 1.2;
18790
+ var MIN_APPROVAL_ACTIVE_LIQUIDITY_ZONES = 1;
18641
18791
  var MAX_DERIVATIVES_RISK_OFF_ALT_BASKET_RETURN_24H = -0.035;
18642
18792
  var MAX_DERIVATIVES_RISK_OFF_TRX_OI_CHANGE_PCT_4H = -1.8;
18793
+ var MIN_BENCHMARK_FLOW_BUY_PRESSURE_PCT = 0.61;
18794
+ var MIN_BENCHMARK_OI_ACCELERATION = 0.55;
18643
18795
  var Q4_APPROVAL_ATR_RANK_BUCKETS = /* @__PURE__ */ new Set(["high", "extreme"]);
18644
18796
  var buildLiquidityTailsGateFeatures = ({
18645
18797
  signalContext,
@@ -18701,6 +18853,12 @@ var buildLiquidityTailsGuardrailContext = ({
18701
18853
  const roc1h = asFiniteNumber2(baseContext?.regime?.momentum?.roc1h);
18702
18854
  const roc4h = asFiniteNumber2(baseContext?.regime?.momentum?.roc4h);
18703
18855
  const benchmarkTrendAlignment = baseContext?.relative?.benchmark?.trendAlignment ?? null;
18856
+ const priceDistanceToMaSlowAtr = asNullableFiniteNumber(
18857
+ baseContext?.regime?.trend?.priceDistanceToMaSlowAtr
18858
+ );
18859
+ const liquidityZonesActiveCount = asNullableFiniteNumber(
18860
+ baseContext?.structure?.liquidityZones?.activeCount
18861
+ );
18704
18862
  const atrPctRankBucket = typeof baseContext?.gateFeatures?.volatility?.atrPctRankBucket === "string" ? baseContext.gateFeatures.volatility.atrPctRankBucket : null;
18705
18863
  const q4AtrRankEligible = atrPctRankBucket != null && Q4_APPROVAL_ATR_RANK_BUCKETS.has(atrPctRankBucket);
18706
18864
  const liquidityRisk = typeof baseContext?.gateFeatures?.risk?.liquidityRisk === "string" ? baseContext.gateFeatures.risk.liquidityRisk : null;
@@ -18738,10 +18896,17 @@ var buildLiquidityTailsGuardrailContext = ({
18738
18896
  const flushSupport = direction === "LONG" ? derivativesRiskFlags.includes("short_liquidation_spike") || derivativesPressure === "short_flush" : direction === "SHORT" ? derivativesRiskFlags.includes("long_liquidation_spike") || derivativesPressure === "long_flush" : false;
18739
18897
  const directionalCrowding = direction === "LONG" ? derivativesRiskFlags.includes("crowded_long") : direction === "SHORT" ? derivativesRiskFlags.includes("crowded_short") : false;
18740
18898
  const derivativesRiskOffLongRecoveryPocket = direction === "LONG" && cmcFearGreedValue != null && cmcFearGreedValue <= MAX_APPROVAL_CMC_FEAR_GREED_VALUE && altBasketReturn24h != null && altBasketReturn24h <= MAX_DERIVATIVES_RISK_OFF_ALT_BASKET_RETURN_24H && referenceTrx1hStale === false && referenceTrx1hOiChangePct4h != null && referenceTrx1hOiChangePct4h <= MAX_DERIVATIVES_RISK_OFF_TRX_OI_CHANGE_PCT_4H;
18741
- if (derivativesDirectionAligned === true && !flushSupport && !derivativesRiskOffLongRecoveryPocket) {
18899
+ const referenceTradeFlowBuyPressurePct = asFiniteNumber2(
18900
+ baseContext?.gateFeatures?.participation?.referenceTradeFlowBuyPressurePct
18901
+ );
18902
+ const benchmarkOiAcceleration = asFiniteNumber2(
18903
+ derivativesSummary?.oiAcceleration
18904
+ );
18905
+ const benchmarkFlowOiExpansionRecoveryPocket = (direction === "LONG" || direction === "SHORT") && q4AtrRankEligible && referenceTradeFlowBuyPressurePct != null && referenceTradeFlowBuyPressurePct >= MIN_BENCHMARK_FLOW_BUY_PRESSURE_PCT && benchmarkOiAcceleration != null && benchmarkOiAcceleration >= MIN_BENCHMARK_OI_ACCELERATION;
18906
+ if (derivativesDirectionAligned === true && !flushSupport && !derivativesRiskOffLongRecoveryPocket && !benchmarkFlowOiExpansionRecoveryPocket) {
18742
18907
  hardBlockReasons.push("derivatives_reversal_aligned");
18743
18908
  }
18744
- if (derivativesDirectionAligned === false && !flushSupport && !derivativesRiskOffLongRecoveryPocket) {
18909
+ if (derivativesDirectionAligned === false && !flushSupport && !derivativesRiskOffLongRecoveryPocket && !benchmarkFlowOiExpansionRecoveryPocket) {
18745
18910
  hardBlockReasons.push("derivatives_reversal_conflict");
18746
18911
  }
18747
18912
  if (volumeRel20 != null && volumeRel20 < 0.75) {
@@ -18816,6 +18981,24 @@ var buildLiquidityTailsGuardrailContext = ({
18816
18981
  if (deterministicQuality === 3 && hardBlockReasons.length === 0 && derivativesRiskOffLongRecoveryPocket) {
18817
18982
  deterministicQuality = 4;
18818
18983
  }
18984
+ if (deterministicQuality >= 4) {
18985
+ const approvalContextReasons = [];
18986
+ if (priceDistanceToMaSlowAtr == null) {
18987
+ approvalContextReasons.push("price_distance_to_ma_slow_unavailable");
18988
+ } else if (priceDistanceToMaSlowAtr > MAX_APPROVAL_PRICE_DISTANCE_TO_MA_SLOW_ATR) {
18989
+ approvalContextReasons.push("price_overextended_from_ma_slow");
18990
+ }
18991
+ if (liquidityZonesActiveCount == null || liquidityZonesActiveCount < MIN_APPROVAL_ACTIVE_LIQUIDITY_ZONES) {
18992
+ approvalContextReasons.push("liquidity_zone_confirmation_missing");
18993
+ }
18994
+ if (approvalContextReasons.length > 0) {
18995
+ deterministicQuality = 3;
18996
+ softBlockReasons.push(...approvalContextReasons);
18997
+ }
18998
+ }
18999
+ if (deterministicQuality < 4 && hardBlockReasons.length === 0 && benchmarkFlowOiExpansionRecoveryPocket) {
19000
+ deterministicQuality = 4;
19001
+ }
18819
19002
  return {
18820
19003
  ...signalContext,
18821
19004
  baseContextAvailable: Boolean(baseContext),
@@ -18830,6 +19013,8 @@ var buildLiquidityTailsGuardrailContext = ({
18830
19013
  roc1h,
18831
19014
  roc4h,
18832
19015
  benchmarkTrendAlignment,
19016
+ priceDistanceToMaSlowAtr,
19017
+ liquidityZonesActiveCount,
18833
19018
  atrPctRankBucket,
18834
19019
  q4AtrRankEligible,
18835
19020
  liquidityRisk,
@@ -18844,6 +19029,7 @@ var buildLiquidityTailsGuardrailContext = ({
18844
19029
  derivativesRiskFlags,
18845
19030
  cadenceUpgradePocket,
18846
19031
  derivativesRiskOffLongRecoveryPocket,
19032
+ benchmarkFlowOiExpansionRecoveryPocket,
18847
19033
  liquidityTailsGateFeatures,
18848
19034
  hardBlockReasons,
18849
19035
  softBlockReasons,
@@ -18938,6 +19124,8 @@ Additional Liquidity Tails context:
18938
19124
  - roc1h=${String(context.roc1h ?? "n/a")}
18939
19125
  - roc4h=${String(context.roc4h ?? "n/a")}
18940
19126
  - benchmarkTrendAlignment=${context.benchmarkTrendAlignment ?? "n/a"}
19127
+ - priceDistanceToMaSlowAtr=${String(context.priceDistanceToMaSlowAtr ?? "n/a")}
19128
+ - liquidityZonesActiveCount=${String(context.liquidityZonesActiveCount ?? "n/a")}
18941
19129
  - atrPctRankBucket=${context.atrPctRankBucket ?? "n/a"}
18942
19130
  - q4AtrRankEligible=${String(context.q4AtrRankEligible)}
18943
19131
  - liquidityRisk=${context.liquidityRisk ?? "n/a"}
@@ -19012,6 +19200,9 @@ var isDirectionalPriceAboveLevel = ({
19012
19200
  price,
19013
19201
  level
19014
19202
  }) => direction === "LONG" ? price != null && level != null && price > level : direction === "SHORT" ? price != null && level != null && price < level : null;
19203
+ var TRANSITION_LOW_TOUCH_COUNT_MAX = 2;
19204
+ var ETH_REFERENCE_WEAK_NON_STRESS_OI_CHANGE_PCT_24H_MAX = -2.5;
19205
+ var LONG_DIRECT_INDICATOR_SUPPORT_MIN = 2;
19015
19206
  var buildLiquidityZonesGuardrailContext = ({
19016
19207
  signalContext,
19017
19208
  baseContext
@@ -19065,8 +19256,15 @@ var buildLiquidityZonesGuardrailContext = ({
19065
19256
  const lowTouchCount20 = asPresentFiniteNumber(
19066
19257
  baseContext?.structure?.levels?.lowTouchCount20
19067
19258
  );
19259
+ const ethReferenceDerivatives15m = baseContext?.derivatives?.referenceContexts?.ETHUSDT?.intervals?.["15m"];
19068
19260
  const ethReferenceOiChangePct4h = asPresentFiniteNumber(
19069
- baseContext?.derivatives?.referenceContexts?.ETHUSDT?.intervals?.["15m"]?.oiChangePct4h
19261
+ ethReferenceDerivatives15m?.oiChangePct4h
19262
+ );
19263
+ const ethReferenceOiChangePct24h = asPresentFiniteNumber(
19264
+ ethReferenceDerivatives15m?.oiChangePct24h
19265
+ );
19266
+ const ethReferenceFundingZScore = asPresentFiniteNumber(
19267
+ ethReferenceDerivatives15m?.fundingZScore
19070
19268
  );
19071
19269
  const solReferenceOiChangePct24h = asPresentFiniteNumber(
19072
19270
  baseContext?.derivatives?.referenceContexts?.SOLUSDT?.intervals?.["15m"]?.oiChangePct24h
@@ -19165,11 +19363,15 @@ var buildLiquidityZonesGuardrailContext = ({
19165
19363
  const isContinuationBreakoutRetest = direction === "LONG" ? breakoutState === "above_high_level" || entryLocation === "breakout" : direction === "SHORT" ? breakoutState === "below_low_level" || entryLocation === "breakdown" : false;
19166
19364
  const hasBaseRetestConfirmation = filterMetric >= 3 && hitCount >= 2 && reactionCloseDistancePct >= 0.08 && retestPenetrationPct <= 90;
19167
19365
  const ethReferenceOiWeakPocket = ethReferenceOiChangePct4h != null && ethReferenceOiChangePct4h <= -0.8;
19168
- const transitionStructureExpansionPocket = hasBaseRetestConfirmation && structureZoneState === "transition" && structureScore != null && structureScore >= 17 && adaptiveChannelFlipDown === false && !directionalCrowding && !ethReferenceOiWeakPocket;
19366
+ const ethReferenceStressPocket = hasBaseRetestConfirmation && lowTouchCount20 != null && lowTouchCount20 <= 3 && ethReferenceOiChangePct24h != null && ethReferenceOiChangePct24h <= -5.8 && ethReferenceFundingZScore != null && ethReferenceFundingZScore <= -1.05;
19367
+ const transitionStructureExpansionPocket = hasBaseRetestConfirmation && lowTouchCount20 != null && lowTouchCount20 <= TRANSITION_LOW_TOUCH_COUNT_MAX && structureZoneState === "transition" && structureScore != null && structureScore >= 17 && adaptiveChannelFlipDown === false && !directionalCrowding && !ethReferenceOiWeakPocket;
19169
19368
  const solReferenceStressPocket = hasBaseRetestConfirmation && lowTouchCount20 != null && lowTouchCount20 <= 3 && solReferenceOiChangePct24h != null && solReferenceOiChangePct24h <= -4.2 && solReferenceFundingZScore != null && solReferenceFundingZScore <= -1.2;
19170
- const calibratedExpansionPocket = transitionStructureExpansionPocket || solReferenceStressPocket;
19369
+ const calibratedExpansionPocket = transitionStructureExpansionPocket || ethReferenceStressPocket || solReferenceStressPocket;
19370
+ const ethReferenceWeakNonStressPocket = ethReferenceOiChangePct24h != null && ethReferenceOiChangePct24h <= ETH_REFERENCE_WEAK_NON_STRESS_OI_CHANGE_PCT_24H_MAX && !ethReferenceStressPocket;
19371
+ const longDirectIndicatorSupportConfirmed = direction === "LONG" ? directIndicatorSupportCount != null && directIndicatorSupportCount >= LONG_DIRECT_INDICATOR_SUPPORT_MIN : null;
19171
19372
  const longRequiresCalibratedExpansion = direction === "LONG" && !calibratedExpansionPocket;
19172
- const approvalDisqualifiedByCalibration = !calibratedExpansionPocket && (longRequiresCalibratedExpansion || isContinuationBreakoutRetest || hasOverextendedVolumeConfirmation || hasIsolatedIndicatorSupport);
19373
+ const longDirectIndicatorSupportMissing = longDirectIndicatorSupportConfirmed === false;
19374
+ const approvalDisqualifiedByCalibration = !calibratedExpansionPocket && (longRequiresCalibratedExpansion || isContinuationBreakoutRetest || hasOverextendedVolumeConfirmation || hasIsolatedIndicatorSupport) || ethReferenceWeakNonStressPocket || longDirectIndicatorSupportMissing;
19173
19375
  if (longRequiresCalibratedExpansion) {
19174
19376
  softBlockReasons.push("long_liquidity_retest_requires_recalibration");
19175
19377
  }
@@ -19182,6 +19384,12 @@ var buildLiquidityZonesGuardrailContext = ({
19182
19384
  if (hasIsolatedIndicatorSupport) {
19183
19385
  softBlockReasons.push("isolated_indicator_support");
19184
19386
  }
19387
+ if (ethReferenceWeakNonStressPocket) {
19388
+ softBlockReasons.push("eth_reference_oi_weak_without_stress");
19389
+ }
19390
+ if (longDirectIndicatorSupportMissing) {
19391
+ softBlockReasons.push("long_direct_indicator_support_missing");
19392
+ }
19185
19393
  const hasLongBreakoutConfirmation = direction === "LONG" && (breakoutState === "below_low_level" || breakoutState === "above_high_level") && reactionCloseDistancePct >= 1 && volumeRel20 != null && volumeRel20 >= 2 && venueSpreadZScore != null && venueSpreadZScore >= 0;
19186
19394
  const hasShortContinuationConfirmation = direction === "SHORT" && hasVolumeConfirmation;
19187
19395
  let deterministicQuality = 3;
@@ -19241,10 +19449,15 @@ var buildLiquidityZonesGuardrailContext = ({
19241
19449
  adaptiveChannelFlipDown,
19242
19450
  lowTouchCount20,
19243
19451
  ethReferenceOiChangePct4h,
19452
+ ethReferenceOiChangePct24h,
19453
+ ethReferenceFundingZScore,
19244
19454
  solReferenceOiChangePct24h,
19245
19455
  solReferenceFundingZScore,
19246
19456
  transitionStructureExpansionPocket,
19457
+ ethReferenceStressPocket,
19247
19458
  solReferenceStressPocket,
19459
+ ethReferenceWeakNonStressPocket,
19460
+ longDirectIndicatorSupportConfirmed,
19248
19461
  hardBlockReasons,
19249
19462
  softBlockReasons,
19250
19463
  deterministicQuality,
@@ -19338,6 +19551,7 @@ Additional Liquidity Zones context:
19338
19551
  - obvLevelAligned=${String(context.obvLevelAligned ?? "n/a")}
19339
19552
  - obvSlopeAligned=${String(context.obvSlopeAligned ?? "n/a")}
19340
19553
  - directIndicatorSupportCount=${String(context.directIndicatorSupportCount ?? "n/a")}
19554
+ - longDirectIndicatorSupportConfirmed=${String(context.longDirectIndicatorSupportConfirmed ?? "n/a")}
19341
19555
  - venueSpreadZScore=${String(context.venueSpreadZScore ?? "n/a")}
19342
19556
  - benchmarkTrendAlignment=${context.benchmarkTrendAlignment ?? "n/a"}
19343
19557
  - btcCorrelation=${String(context.btcCorrelation ?? "n/a")}
@@ -19349,10 +19563,14 @@ Additional Liquidity Zones context:
19349
19563
  - adaptiveChannelFlipDown=${String(context.adaptiveChannelFlipDown ?? "n/a")}
19350
19564
  - lowTouchCount20=${String(context.lowTouchCount20 ?? "n/a")}
19351
19565
  - ethReferenceOiChangePct4h=${String(context.ethReferenceOiChangePct4h ?? "n/a")}
19566
+ - ethReferenceOiChangePct24h=${String(context.ethReferenceOiChangePct24h ?? "n/a")}
19567
+ - ethReferenceFundingZScore=${String(context.ethReferenceFundingZScore ?? "n/a")}
19352
19568
  - solReferenceOiChangePct24h=${String(context.solReferenceOiChangePct24h ?? "n/a")}
19353
19569
  - solReferenceFundingZScore=${String(context.solReferenceFundingZScore ?? "n/a")}
19354
19570
  - transitionStructureExpansionPocket=${String(context.transitionStructureExpansionPocket)}
19571
+ - ethReferenceStressPocket=${String(context.ethReferenceStressPocket)}
19355
19572
  - solReferenceStressPocket=${String(context.solReferenceStressPocket)}
19573
+ - ethReferenceWeakNonStressPocket=${String(context.ethReferenceWeakNonStressPocket)}
19356
19574
  - deterministicQuality=${context.deterministicQuality}
19357
19575
  - approvalAllowedNow=${String(context.approvalAllowedNow)}
19358
19576
  - hardBlockReasons=${JSON.stringify(context.hardBlockReasons)}
@@ -19367,7 +19585,9 @@ Interpretation rules for Liquidity Zones:
19367
19585
  - A close fully through the level marks the zone crossed; crossed zones are not live-entry candidates.
19368
19586
  - Top-level derivatives context is BTC benchmark evidence; target-symbol derivatives require targetContext/targetDerived.
19369
19587
  - Do not treat derivatives points, rows, or loaded-history size as approval evidence.
19370
- - A calibrated transition-structure pocket or SOL reference stress pocket can approve a structurally valid retest.
19588
+ - A calibrated transition-structure pocket, ETH reference stress pocket, or SOL reference stress pocket can approve a structurally valid retest.
19589
+ - LONG approvals need at least two direct MA/MACD/OBV alignments after calibration.
19590
+ - Moderate ETH reference OI weakness blocks approval unless the deeper ETH reference stress pocket is active.
19371
19591
  - Treat deterministicQuality and approvalAllowedNow as the local normalized gate result.
19372
19592
  `.trim();
19373
19593
  },
@@ -19833,6 +20053,16 @@ var getNestedString2 = (value, path) => {
19833
20053
  }
19834
20054
  return typeof current === "string" ? current : null;
19835
20055
  };
20056
+ var getNestedBoolean2 = (value, path) => {
20057
+ let current = value;
20058
+ for (const segment of path) {
20059
+ if (!isRecord2(current)) {
20060
+ return null;
20061
+ }
20062
+ current = current[segment];
20063
+ }
20064
+ return typeof current === "boolean" ? current : null;
20065
+ };
19836
20066
  var isShortBtcOnlyRecoveryLane = (context, baseContext) => {
19837
20067
  const riskFlags = getNestedRecord2(baseContext, [
19838
20068
  "derivatives",
@@ -19857,23 +20087,59 @@ var isShortBtcOnlyRecoveryLane = (context, baseContext) => {
19857
20087
  const biasConflictState = getReverseTrendlineBiasConflictState(context);
19858
20088
  return context.signalDirection === "SHORT" && context.entryTiming === "ready_rejection" && biasConflictState === "btc_only" && context.deterministicRejectionScore != null && context.deterministicRejectionScore >= 6 && context.distance != null && context.distance >= 61 && !hasMissingDerivatives && (derivativesPressure === "long_flush" || derivativesPressure === "short_flush" || derivativesPressure === "crowded_long") && volumeRel20 != null && volumeRel20 >= 1.5 && rangePosition20 != null && rangePosition20 >= 0.2 && rangePosition20 <= 0.7;
19859
20089
  };
20090
+ var hasMissingDerivativesRisk = (baseContext) => {
20091
+ const riskFlags = getNestedRecord2(baseContext, [
20092
+ "derivatives",
20093
+ "summary"
20094
+ ])?.riskFlags;
20095
+ return Array.isArray(riskFlags) && riskFlags.includes("missing_derivatives");
20096
+ };
20097
+ var isExtremeVolatilityRecoveryLane = (context, baseContext) => {
20098
+ if (context.hardBlockReasons.length > 0) {
20099
+ return false;
20100
+ }
20101
+ const primaryIssue = getNestedString2(baseContext, [
20102
+ "gateFeatures",
20103
+ "decisionHints",
20104
+ "primaryIssue"
20105
+ ]);
20106
+ const approveBias = getNestedString2(baseContext, [
20107
+ "gateFeatures",
20108
+ "decisionHints",
20109
+ "approveBias"
20110
+ ]);
20111
+ const upCloseStreak = getNestedNumber2(baseContext, [
20112
+ "regime",
20113
+ "momentum",
20114
+ "upCloseStreak"
20115
+ ]);
20116
+ const adaptiveChannelFlipUp = getNestedBoolean2(baseContext, [
20117
+ "regime",
20118
+ "trend",
20119
+ "adaptiveChannel",
20120
+ "flipUp"
20121
+ ]);
20122
+ const atrPctRank100 = getNestedNumber2(baseContext, [
20123
+ "regime",
20124
+ "volatility",
20125
+ "percentiles",
20126
+ "atrPctRank100"
20127
+ ]);
20128
+ return primaryIssue === "extreme_volatility" && approveBias === "reject" && upCloseStreak != null && upCloseStreak <= 2 && adaptiveChannelFlipUp === false && atrPctRank100 != null && atrPctRank100 <= 99 && !hasMissingDerivativesRisk(baseContext);
20129
+ };
19860
20130
  var getBaseContextQualityPromotion = (context, signal) => {
19861
20131
  const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
19862
20132
  if (!baseContext) {
19863
20133
  return null;
19864
20134
  }
19865
- return isShortBtcOnlyRecoveryLane(context, baseContext) ? 4 : null;
20135
+ return isShortBtcOnlyRecoveryLane(context, baseContext) || isExtremeVolatilityRecoveryLane(context, baseContext) ? 4 : null;
19866
20136
  };
19867
20137
  var getBaseContextApprovalBlockReasons = (context, signal) => {
19868
20138
  const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
19869
20139
  if (!baseContext) {
19870
20140
  return [];
19871
20141
  }
19872
- const riskFlags = getNestedRecord2(baseContext, [
19873
- "derivatives",
19874
- "summary"
19875
- ])?.riskFlags;
19876
- const hasMissingDerivatives = Array.isArray(riskFlags) && riskFlags.includes("missing_derivatives");
20142
+ const hasMissingDerivatives = hasMissingDerivativesRisk(baseContext);
19877
20143
  const volumeRel20 = getNestedNumber2(baseContext, [
19878
20144
  "participation",
19879
20145
  "volume",
@@ -19909,6 +20175,10 @@ var getBaseContextApprovalBlockReasons = (context, signal) => {
19909
20175
  context,
19910
20176
  baseContext
19911
20177
  );
20178
+ const extremeVolatilityRecoveryLane = isExtremeVolatilityRecoveryLane(
20179
+ context,
20180
+ baseContext
20181
+ );
19912
20182
  const reasons = [];
19913
20183
  if (hasMissingDerivatives) {
19914
20184
  reasons.push("missing_derivatives");
@@ -19928,7 +20198,7 @@ var getBaseContextApprovalBlockReasons = (context, signal) => {
19928
20198
  if (context.signalDirection === "SHORT" && biasConflictState === "btc_only" && context.distance != null && context.distance <= 60) {
19929
20199
  reasons.push("short_btc_conflict_too_shallow");
19930
20200
  }
19931
- if (context.signalDirection === "SHORT" && atrPctZScore != null && atrPctZScore >= 2 && !shortBtcOnlyRecoveryLane) {
20201
+ if (context.signalDirection === "SHORT" && atrPctZScore != null && atrPctZScore >= 2 && !shortBtcOnlyRecoveryLane && !extremeVolatilityRecoveryLane) {
19932
20202
  reasons.push("short_extreme_volatility");
19933
20203
  }
19934
20204
  if (context.signalDirection === "SHORT" && rangePosition20 != null && rangePosition20 < 0.2) {
@@ -19949,7 +20219,9 @@ var buildReverseTrendLineGateFeatures = ({
19949
20219
  context,
19950
20220
  signal,
19951
20221
  approvalBlockReasons,
19952
- deterministicRejectionScore
20222
+ deterministicRejectionScore,
20223
+ approvalLane,
20224
+ extremeVolatilityRecoveryPocket
19953
20225
  }) => {
19954
20226
  const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
19955
20227
  const volumeRel20 = getNestedNumber2(baseContext, [
@@ -19983,6 +20255,8 @@ var buildReverseTrendLineGateFeatures = ({
19983
20255
  volatilityState,
19984
20256
  rangePositionState,
19985
20257
  highQualityBouncePocket: context.deterministicQuality >= 4 && approvalBlockReasons.length === 0 && (bounceAcceptance === "rejection" || bounceAcceptance === "follow_through"),
20258
+ extremeVolatilityRecoveryPocket,
20259
+ approvalLane,
19986
20260
  deterministicRejectionScore
19987
20261
  };
19988
20262
  };
@@ -20107,7 +20381,14 @@ var buildReverseTrendlineAiContext = (signal) => {
20107
20381
  },
20108
20382
  signal
20109
20383
  );
20110
- const reverseTrendLineGateFeatures = buildReverseTrendLineGateFeatures({
20384
+ const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
20385
+ const extremeVolatilityRecoveryPocket = baseContext != null ? isExtremeVolatilityRecoveryLane(
20386
+ {
20387
+ hardBlockReasons
20388
+ },
20389
+ baseContext
20390
+ ) : false;
20391
+ const baseReverseTrendLineGateFeatures = buildReverseTrendLineGateFeatures({
20111
20392
  context: {
20112
20393
  ...structural,
20113
20394
  ...timing,
@@ -20116,17 +20397,28 @@ var buildReverseTrendlineAiContext = (signal) => {
20116
20397
  },
20117
20398
  signal,
20118
20399
  approvalBlockReasons,
20119
- deterministicRejectionScore
20400
+ deterministicRejectionScore,
20401
+ approvalLane: "watch",
20402
+ extremeVolatilityRecoveryPocket
20120
20403
  });
20404
+ const highScoreBouncePocket = baseReverseTrendLineGateFeatures.highQualityBouncePocket && deterministicRejectionScore != null && deterministicRejectionScore >= 7;
20405
+ const approvalLane = highScoreBouncePocket ? "high_score_bounce" : extremeVolatilityRecoveryPocket ? "extreme_volatility_recovery" : "watch";
20406
+ const approvalAllowedNow = approvalLane !== "watch";
20407
+ const finalApprovalBlockReasons = !approvalAllowedNow && promotedDeterministicQuality >= 4 && approvalBlockReasons.length === 0 ? [...approvalBlockReasons, "rejection_score_below_gate"] : approvalBlockReasons;
20408
+ const finalDeterministicQuality = approvalAllowedNow ? Math.max(promotedDeterministicQuality, 4) : promotedDeterministicQuality;
20409
+ const reverseTrendLineGateFeatures = {
20410
+ ...baseReverseTrendLineGateFeatures,
20411
+ approvalLane
20412
+ };
20121
20413
  return {
20122
20414
  ...structural,
20123
20415
  ...timing,
20124
20416
  reverseTrendLineGateFeatures,
20125
- deterministicQuality: promotedDeterministicQuality,
20417
+ deterministicQuality: finalDeterministicQuality,
20126
20418
  deterministicRejectionScore,
20127
- approvalAllowedNow: promotedDeterministicQuality >= 4 && approvalBlockReasons.length === 0,
20419
+ approvalAllowedNow,
20128
20420
  hardBlockReasons,
20129
- approvalBlockReasons
20421
+ approvalBlockReasons: finalApprovalBlockReasons
20130
20422
  };
20131
20423
  };
20132
20424
  var withReverseTrendLineGateFeatures = ({
@@ -20171,6 +20463,8 @@ var getHardBlockReasonText2 = (reason) => {
20171
20463
  return "LONG bounce distance sits in a weak mid-distance pocket";
20172
20464
  case "short_follow_through_overrated":
20173
20465
  return "SHORT follow-through bounce is not reliable enough for quality 5";
20466
+ case "rejection_score_below_gate":
20467
+ return "deterministic rejection score is below the current strict gate";
20174
20468
  default:
20175
20469
  return reason;
20176
20470
  }
@@ -20255,6 +20549,8 @@ Additional ReverseTrendLine context:
20255
20549
  - reverseTrendLineGateVolatilityState=${context.reverseTrendLineGateFeatures.volatilityState}
20256
20550
  - reverseTrendLineGateRangePositionState=${context.reverseTrendLineGateFeatures.rangePositionState}
20257
20551
  - reverseTrendLineGateHighQualityBouncePocket=${String(context.reverseTrendLineGateFeatures.highQualityBouncePocket)}
20552
+ - reverseTrendLineGateExtremeVolatilityRecoveryPocket=${String(context.reverseTrendLineGateFeatures.extremeVolatilityRecoveryPocket)}
20553
+ - reverseTrendLineGateApprovalLane=${context.reverseTrendLineGateFeatures.approvalLane}
20258
20554
  - approvalAllowedNow=${context.approvalAllowedNow}
20259
20555
  - hardBlockReasons=${context.hardBlockReasons.join(", ") || "none"}
20260
20556
  - approvalBlockReasons=${context.approvalBlockReasons.join(", ") || "none"}
@@ -20508,6 +20804,7 @@ var TREND_FOLLOW_OPENING_SESSION_MAX_MINUTES_FROM_OPEN = 75;
20508
20804
  var TREND_FOLLOW_OPENING_REF_XRP_OI_MAX = 324e6;
20509
20805
  var TREND_FOLLOW_OPENING_REF_XRP_OI_CHANGE_1H_MIN = 0.4;
20510
20806
  var TREND_FOLLOW_OPENING_REF_BNB_OI_MIN = 56e4;
20807
+ var TREND_FOLLOW_ALLOWED_VOLATILITY_STATE = "normal";
20511
20808
  var asFiniteNumber5 = (value) => {
20512
20809
  const parsed = Number(value);
20513
20810
  return Number.isFinite(parsed) ? parsed : null;
@@ -20619,6 +20916,7 @@ var buildTrendFollowGateFeatures = ({
20619
20916
  );
20620
20917
  const marketBreadthAligned = marketBreadthReturn == null || marketBreadth?.stale ? null : direction === "LONG" ? marketBreadthReturn >= 0 : direction === "SHORT" ? marketBreadthReturn <= 0 : null;
20621
20918
  const marketBreadthContinuation = marketBreadth?.stale === true ? "stale" : marketBreadthAligned === true ? "aligned" : marketBreadthAligned === false ? "against" : "unknown";
20919
+ const marketVolatilityState = typeof baseContext?.regime?.volatility?.state === "string" ? baseContext.regime.volatility.state : null;
20622
20920
  const targetVsBtcBeta20 = asFiniteNumber5(
20623
20921
  baseContext?.relative?.targetVsBtc?.betaToBtc20
20624
20922
  );
@@ -20670,6 +20968,8 @@ var buildTrendFollowGateFeatures = ({
20670
20968
  const referenceDerivativesLossBlock = direction === "SHORT" && referenceXrp15mOpenInterest != null && referenceXrp15mOpenInterest >= TREND_FOLLOW_REF_LOSS_XRP_OI_MIN && referenceEthCrowdingPersistenceBars != null && referenceEthCrowdingPersistenceBars >= TREND_FOLLOW_REF_LOSS_ETH_CROWDING_MIN && referenceSol15mFundingZScore != null && referenceSol15mFundingZScore <= TREND_FOLLOW_REF_LOSS_SOL_FUNDING_Z_MAX;
20671
20969
  const referenceDerivativesCadencePocket = !referenceDerivativesLossBlock && (legacyCadencePocket || referenceDerivativesOiCompressionPocket || referenceDerivativesXrpFundingPocket || referenceDerivativesSolFlushPocket);
20672
20970
  const referenceDerivativesOpeningPocket = direction === "SHORT" && minutesFromSessionOpen != null && minutesFromSessionOpen <= TREND_FOLLOW_OPENING_SESSION_MAX_MINUTES_FROM_OPEN && referenceXrp15mOpenInterest != null && referenceXrp15mOpenInterest <= TREND_FOLLOW_OPENING_REF_XRP_OI_MAX && referenceXrp1hOiChangePct1h != null && referenceXrp1hOiChangePct1h >= TREND_FOLLOW_OPENING_REF_XRP_OI_CHANGE_1H_MIN && referenceBnb15mOpenInterest != null && referenceBnb15mOpenInterest >= TREND_FOLLOW_OPENING_REF_BNB_OI_MIN;
20971
+ const referenceDerivativesCleanCadencePocket = referenceDerivativesCadencePocket && !derivativesShortFlushOiPocket;
20972
+ const normalVolatilityCadencePocket = marketVolatilityState === TREND_FOLLOW_ALLOWED_VOLATILITY_STATE;
20673
20973
  return {
20674
20974
  setupStopDistanceAtr,
20675
20975
  setupTpDistanceAtr,
@@ -20684,6 +20984,7 @@ var buildTrendFollowGateFeatures = ({
20684
20984
  relativeContinuation,
20685
20985
  marketBreadthContinuation,
20686
20986
  marketBreadthDispersion: asFiniteNumber5(marketBreadth?.dispersion),
20987
+ marketVolatilityState,
20687
20988
  targetVsBtcBeta20,
20688
20989
  btcAltRegimeBtcTurnoverShare24h,
20689
20990
  btcAltRegimeAltBasketReturn24h,
@@ -20710,8 +21011,10 @@ var buildTrendFollowGateFeatures = ({
20710
21011
  referenceDerivativesSolFlushPocket,
20711
21012
  referenceDerivativesLossBlock,
20712
21013
  referenceDerivativesCadencePocket,
21014
+ referenceDerivativesCleanCadencePocket,
20713
21015
  referenceDerivativesOpeningPocket,
20714
- highQualityCadencePocket: referenceDerivativesCadencePocket || referenceDerivativesOpeningPocket
21016
+ normalVolatilityCadencePocket,
21017
+ highQualityCadencePocket: normalVolatilityCadencePocket && referenceDerivativesCleanCadencePocket
20715
21018
  };
20716
21019
  };
20717
21020
  var buildTrendFollowGuardrailContext = ({
@@ -20944,6 +21247,7 @@ Additional TrendFollow context:
20944
21247
  - trendFollowGateRelativeContinuation=${context.trendFollowGateFeatures.relativeContinuation}
20945
21248
  - trendFollowGateMarketBreadthContinuation=${context.trendFollowGateFeatures.marketBreadthContinuation}
20946
21249
  - trendFollowGateMarketBreadthDispersion=${String(context.trendFollowGateFeatures.marketBreadthDispersion ?? "n/a")}
21250
+ - trendFollowGateMarketVolatilityState=${String(context.trendFollowGateFeatures.marketVolatilityState ?? "n/a")}
20947
21251
  - trendFollowGateTargetVsBtcBeta20=${String(context.trendFollowGateFeatures.targetVsBtcBeta20 ?? "n/a")}
20948
21252
  - trendFollowGateBtcAltRegimeBtcTurnoverShare24h=${String(context.trendFollowGateFeatures.btcAltRegimeBtcTurnoverShare24h ?? "n/a")}
20949
21253
  - trendFollowGateBtcAltRegimeAltBasketReturn24h=${String(context.trendFollowGateFeatures.btcAltRegimeAltBasketReturn24h ?? "n/a")}
@@ -20970,7 +21274,9 @@ Additional TrendFollow context:
20970
21274
  - trendFollowGateReferenceDerivativesSolFlushPocket=${String(context.trendFollowGateFeatures.referenceDerivativesSolFlushPocket)}
20971
21275
  - trendFollowGateReferenceDerivativesLossBlock=${String(context.trendFollowGateFeatures.referenceDerivativesLossBlock)}
20972
21276
  - trendFollowGateReferenceDerivativesCadencePocket=${String(context.trendFollowGateFeatures.referenceDerivativesCadencePocket)}
21277
+ - trendFollowGateReferenceDerivativesCleanCadencePocket=${String(context.trendFollowGateFeatures.referenceDerivativesCleanCadencePocket)}
20973
21278
  - trendFollowGateReferenceDerivativesOpeningPocket=${String(context.trendFollowGateFeatures.referenceDerivativesOpeningPocket)}
21279
+ - trendFollowGateNormalVolatilityCadencePocket=${String(context.trendFollowGateFeatures.normalVolatilityCadencePocket)}
20974
21280
  - trendFollowGateHighQualityCadencePocket=${String(context.trendFollowGateFeatures.highQualityCadencePocket)}
20975
21281
  - benchmarkTrendAlignment=${context.benchmarkTrendAlignment ?? "n/a"}
20976
21282
  - derivativesPressure=${context.derivativesPressure ?? "n/a"}
@@ -20988,7 +21294,7 @@ Interpretation rules for TrendFollow:
20988
21294
  - The ATR trailing stop is the structural invalidation line and also updates while a position is open.
20989
21295
  - Prefer breakouts aligned with shared market context and backed by participation.
20990
21296
  - Late, thin, crowded, inside-range, adverse-delta, weak-momentum, or weak-volume-structure breakouts should be downgraded even if the pivot cross is valid.
20991
- - Live approval is reserved for calibrated SHORT derivatives pockets: the legacy BTC benchmark long-liquidation flush, guarded extra-reference XRP/SOL/BNB/TRX continuation pockets, or the narrow opening-session XRP/BNB reference pocket; other structurally valid breakouts remain watch mode.
21297
+ - Live approval is reserved for calibrated SHORT extra-reference derivatives pockets in normal volatility when the BTC benchmark short-flush/OI pocket is not active; legacy BTC benchmark flush and opening-session recovery remain watch mode.
20992
21298
  - Treat deterministicQuality and approvalAllowedNow as the local normalized gate result.
20993
21299
  `.trim();
20994
21300
  },
@@ -21020,6 +21326,13 @@ var SHORT_BREADTH_SHOCK_1H_LIQ_SHORT_MAX = 0.208;
21020
21326
  var LONG_ALT_LEADERSHIP_BTC_VS_ALT_RETURN_24H_MAX = -503054e-8;
21021
21327
  var LONG_ALT_LEADERSHIP_BTC_VS_ALT_RETURN_1H_MAX = -581403e-8;
21022
21328
  var LONG_ALT_LEADERSHIP_FEAR_GREED_CHANGE_24H_MIN = -1;
21329
+ var LONG_BROAD_MARKET_SHORT_FLUSH_ADVANCERS_MIN = 27;
21330
+ var LONG_BROAD_MARKET_SHORT_FLUSH_PCT_ABOVE_MA20_MIN = 0.95;
21331
+ var LONG_BROAD_MARKET_SHORT_FLUSH_BTC_VS_ALT_RETURN_24H_MIN = 0;
21332
+ var SHORT_ASIA_LONG_FLUSH_LOW_CMC_FEAR_GREED_MAX = 18;
21333
+ var SHORT_ASIA_LONG_FLUSH_ADVANCERS_MAX = 2;
21334
+ var BNB_REFERENCE_OI_CHANGE_PCT_4H_RISK_MIN = 0;
21335
+ var DERIVATIVES_DATA_UNAVAILABLE_STRESS_CMC_FEAR_GREED_MAX = 25;
21023
21336
  var toMtfAlignmentForTrendShift = ({
21024
21337
  direction,
21025
21338
  mtfAlignment
@@ -21268,19 +21581,33 @@ var buildTrendShiftGuardrailContext = ({
21268
21581
  );
21269
21582
  const gateVolatility = baseContext?.gateFeatures?.volatility;
21270
21583
  const gateRelative = baseContext?.gateFeatures?.relative;
21584
+ const baseMarketBreadth = baseContext?.relative?.marketBreadth;
21271
21585
  const baseBtcAltRegime = baseContext?.relative?.btcAltRegime;
21272
21586
  const baseCmcFearGreed = baseContext?.relative?.cmcFearGreed;
21273
21587
  const bbWidthPct = asFiniteNumber6(volatility?.bbWidthPct);
21274
21588
  const marketBreadthReturn = asFiniteNumber6(gateRelative?.marketBreadthReturn);
21589
+ const marketBreadthAdvancers = asFiniteNumber6(baseMarketBreadth?.advancers);
21590
+ const marketBreadthPctAboveMa20 = asFiniteNumber6(
21591
+ baseMarketBreadth?.pctAboveMa20
21592
+ );
21593
+ const marketBreadthStale = gateRelative?.marketBreadthStale === true || baseMarketBreadth?.stale === true;
21275
21594
  const btcVsAltReturn24h = asFiniteNumber6(gateRelative?.btcVsAltReturn24h);
21276
21595
  const btcVsAltReturn1h = asFiniteNumber6(baseBtcAltRegime?.btcVsAltReturn1h);
21596
+ const cmcFearGreedValue = asFiniteNumber6(
21597
+ gateRelative?.cmcFearGreedValue ?? baseCmcFearGreed?.value
21598
+ );
21277
21599
  const cmcFearGreedValueChange24h = asFiniteNumber6(
21278
21600
  gateRelative?.cmcFearGreedValueChange24h ?? baseCmcFearGreed?.valueChange24h
21279
21601
  );
21280
21602
  const cmcFearGreedStale = gateRelative?.cmcFearGreedStale === true || baseCmcFearGreed?.stale === true;
21603
+ const derivativesDataUnavailable = derivativesRiskFlags.includes("missing_derivatives") || derivativesRiskFlags.includes("stale_derivatives");
21604
+ const derivativesDataUnavailableStressRisk = derivativesDataUnavailable && cmcFearGreedStale !== true && cmcFearGreedValue != null && cmcFearGreedValue <= DERIVATIVES_DATA_UNAVAILABLE_STRESS_CMC_FEAR_GREED_MAX;
21281
21605
  const derivatives1hLiqShort = asFiniteNumber6(
21282
21606
  baseContext?.derivatives?.intervals?.["1h"]?.liqShort
21283
21607
  );
21608
+ const bnbReferenceOiChangePct4h = asFiniteNumber6(
21609
+ baseContext?.derivatives?.referenceContexts?.BNBUSDT?.intervals?.["1h"]?.oiChangePct4h
21610
+ );
21284
21611
  const btcAltRegime = typeof gateRelative?.btcAltRegime === "string" ? gateRelative.btcAltRegime : null;
21285
21612
  const btcAltRegimeStale = gateRelative?.btcAltRegimeStale === true;
21286
21613
  const cmcExchangeLiquidityVolumeChange24hPct = asFiniteNumber6(
@@ -21305,8 +21632,8 @@ var buildTrendShiftGuardrailContext = ({
21305
21632
  const q4LongBreakoutCandidate = signalContext.signalDirection === "LONG" && breakoutState === "above_high_level" && volumeRel20 != null && volumeRel20 >= 1.2 && atrPctZScore != null && atrPctZScore >= 0 && relativeStrength1h != null && relativeStrength1h > -1 && derivativesPressure === "short_flush";
21306
21633
  const q4ShortBreakoutCandidate = signalContext.signalDirection === "SHORT" && breakoutState === "below_low_level" && volumeRel20 != null && volumeRel20 >= 1.2 && atrPctZScore != null && atrPctZScore >= 0 && relativeStrength1h != null && relativeStrength1h < 1 && derivativesPressure === "long_flush";
21307
21634
  const q4ShortAsiaFlushCandidate = signalContext.signalDirection === "SHORT" && derivativesPressure === "neutral" && derivativesFlushSupport && sessionPrimary === "asia" && !sessionIsOverlap && distanceAtrRatio < 0.7 && slopeAbs >= 0.08 && closeVsAvgPctAbs >= 0.12;
21308
- 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");
21309
- const shortNeutralBearChannelBreakdownCandidate = signalContext.signalDirection === "SHORT" && breakoutState === "below_low_level" && derivativesPressure === "neutral" && atrPctZScore != null && atrPctZScore >= 0 && atrPctZScore < 1 && adaptiveChannelDirection === "bear";
21635
+ const selectiveNeutralQ4Candidate = hasDerivativesSummary && derivativesPressure === "neutral" && !derivativesDataUnavailableStressRisk && !sessionIsOverlap && (signalContext.signalDirection === "LONG" && sessionPrimary === "europe" && (breakoutState === "above_high_level" || breakoutState === "failed_high_breakout") || signalContext.signalDirection === "SHORT" && (sessionPrimary === "off_hours" || sessionPrimary === "asia") && breakoutState === "below_low_level");
21636
+ const shortNeutralBearChannelBreakdownCandidate = signalContext.signalDirection === "SHORT" && breakoutState === "below_low_level" && derivativesPressure === "neutral" && !derivativesDataUnavailableStressRisk && atrPctZScore != null && atrPctZScore >= 0 && atrPctZScore < 1 && adaptiveChannelDirection === "bear";
21310
21637
  let deterministicQuality = 3;
21311
21638
  if (hardBlockReasons.length > 0) {
21312
21639
  deterministicQuality = signalContext.confirmedFlip ? 2 : 1;
@@ -21374,6 +21701,10 @@ var buildTrendShiftGuardrailContext = ({
21374
21701
  hardBlockReasons.push("us_short_oi_not_expanding");
21375
21702
  }
21376
21703
  }
21704
+ if (deterministicQuality >= 5 && derivativesDataUnavailableStressRisk) {
21705
+ deterministicQuality = 4;
21706
+ hardBlockReasons.push("derivatives_data_unavailable_stress");
21707
+ }
21377
21708
  if (deterministicQuality >= 5 && hasDerivativesSummary && !selectiveNeutralQ4Candidate && !shortNeutralBearChannelBreakdownCandidate && derivativesPressure === "neutral" && !derivativesFlushSupport) {
21378
21709
  deterministicQuality = 4;
21379
21710
  hardBlockReasons.push("neutral_derivatives_pressure");
@@ -21393,9 +21724,12 @@ var buildTrendShiftGuardrailContext = ({
21393
21724
  const shortExtremeAtrHighBbRisk = signalContext.signalDirection === "SHORT" && gateVolatility?.state === "normal" && gateVolatility.atrPctRankBucket === "extreme" && gateVolatility.bbWidthRankBucket === "high";
21394
21725
  const shortBullSwingStructureRisk = signalContext.signalDirection === "SHORT" && swingBias === "bull";
21395
21726
  const shortLowBollingerWidthRisk = signalContext.signalDirection === "SHORT" && bbWidthPct != null && bbWidthPct <= SHORT_LOW_BB_WIDTH_PCT_MAX;
21727
+ const shortAsiaLongFlushLowCmcBreadthRisk = signalContext.signalDirection === "SHORT" && sessionPrimary === "asia" && derivativesPressure === "long_flush" && cmcFearGreedStale !== true && marketBreadthStale !== true && cmcFearGreedValue != null && cmcFearGreedValue <= SHORT_ASIA_LONG_FLUSH_LOW_CMC_FEAR_GREED_MAX && marketBreadthAdvancers != null && marketBreadthAdvancers <= SHORT_ASIA_LONG_FLUSH_ADVANCERS_MAX;
21396
21728
  const lowRewardToVolatilityRisk = rewardToVolatility != null && rewardToVolatility < 0.25;
21397
21729
  const defensiveRewardToVolatilityRisk = rewardToVolatility != null && rewardToVolatility >= 0.25 && rewardToVolatility < 8;
21730
+ const bnbReferenceOiExpansionRisk = bnbReferenceOiChangePct4h != null && bnbReferenceOiChangePct4h >= BNB_REFERENCE_OI_CHANGE_PCT_4H_RISK_MIN;
21398
21731
  const longBtcAltRegimeRisk = signalContext.signalDirection === "LONG" && btcAltRegimeStale !== true && (btcAltRegime === "btc_lead" || btcAltRegime === "risk_off");
21732
+ const longBroadMarketShortFlushRisk = signalContext.signalDirection === "LONG" && derivativesPressure === "short_flush" && marketBreadthAdvancers != null && marketBreadthAdvancers >= LONG_BROAD_MARKET_SHORT_FLUSH_ADVANCERS_MIN && marketBreadthPctAboveMa20 != null && marketBreadthPctAboveMa20 >= LONG_BROAD_MARKET_SHORT_FLUSH_PCT_ABOVE_MA20_MIN && btcVsAltReturn24h != null && btcVsAltReturn24h >= LONG_BROAD_MARKET_SHORT_FLUSH_BTC_VS_ALT_RETURN_24H_MIN;
21399
21733
  const cmcExchangeLiquidityVolumeChangeRisk = cmcExchangeLiquidityStale !== true && cmcExchangeLiquidityVolumeChange24hPct != null && (cmcExchangeLiquidityVolumeChange24hPct > -0.1 && cmcExchangeLiquidityVolumeChange24hPct < 0 || cmcExchangeLiquidityVolumeChange24hPct >= 0.1 && cmcExchangeLiquidityVolumeChange24hPct < 0.3);
21400
21734
  if (deterministicQuality >= 5 && longRelativeStrengthOverextended) {
21401
21735
  deterministicQuality = 4;
@@ -21433,6 +21767,10 @@ var buildTrendShiftGuardrailContext = ({
21433
21767
  deterministicQuality = 4;
21434
21768
  hardBlockReasons.push("short_bull_swing_structure");
21435
21769
  }
21770
+ if (deterministicQuality >= 5 && shortAsiaLongFlushLowCmcBreadthRisk) {
21771
+ deterministicQuality = 4;
21772
+ hardBlockReasons.push("short_asia_long_flush_low_cmc_breadth");
21773
+ }
21436
21774
  if (deterministicQuality >= 4 && lowRewardToVolatilityRisk) {
21437
21775
  deterministicQuality = 4;
21438
21776
  hardBlockReasons.push("low_reward_to_volatility");
@@ -21441,10 +21779,18 @@ var buildTrendShiftGuardrailContext = ({
21441
21779
  deterministicQuality = 4;
21442
21780
  hardBlockReasons.push("reward_to_volatility_below_defensive_threshold");
21443
21781
  }
21782
+ if (deterministicQuality >= 5 && bnbReferenceOiExpansionRisk) {
21783
+ deterministicQuality = 4;
21784
+ hardBlockReasons.push("bnb_reference_1h_oi4h_expansion_risk");
21785
+ }
21444
21786
  if (deterministicQuality >= 4 && longBtcAltRegimeRisk) {
21445
21787
  deterministicQuality = 4;
21446
21788
  hardBlockReasons.push("long_btc_alt_regime_risk");
21447
21789
  }
21790
+ if (deterministicQuality >= 5 && longBroadMarketShortFlushRisk) {
21791
+ deterministicQuality = 4;
21792
+ hardBlockReasons.push("long_broad_market_short_flush_risk");
21793
+ }
21448
21794
  if (deterministicQuality >= 4 && cmcExchangeLiquidityVolumeChangeRisk) {
21449
21795
  deterministicQuality = 4;
21450
21796
  hardBlockReasons.push("cmc_exchange_liquidity_volume_change_risk");
@@ -21463,7 +21809,7 @@ var buildTrendShiftGuardrailContext = ({
21463
21809
  const q4UsClosingOiConfirmationRecoveryCandidate = deterministicQuality === 4 && signalContext.confirmedFlip === true && signalContext.flipDistanceOk === true && sessionPrimary === "us" && sessionWindowPhase === "closing" && hardBlockReasons.length > 0 && hardBlockReasons.every(
21464
21810
  (reason) => q4UsClosingOiConfirmationRecoveryAllowedReasons.includes(reason)
21465
21811
  );
21466
- const q4ShortBreadthShockLiquidationRecoveryCandidate = deterministicQuality === 4 && signalContext.signalDirection === "SHORT" && signalContext.confirmedFlip === true && signalContext.flipDistanceOk === true && marketBreadthReturn != null && marketBreadthReturn <= SHORT_BREADTH_SHOCK_MARKET_BREADTH_RETURN_MAX2 && derivatives1hLiqShort != null && derivatives1hLiqShort <= SHORT_BREADTH_SHOCK_1H_LIQ_SHORT_MAX;
21812
+ const q4ShortBreadthShockLiquidationRecoveryCandidate = deterministicQuality === 4 && signalContext.signalDirection === "SHORT" && signalContext.confirmedFlip === true && signalContext.flipDistanceOk === true && hardBlockReasons.length === 0 && !derivativesDataUnavailableStressRisk && marketBreadthReturn != null && marketBreadthReturn <= SHORT_BREADTH_SHOCK_MARKET_BREADTH_RETURN_MAX2 && derivatives1hLiqShort != null && derivatives1hLiqShort <= SHORT_BREADTH_SHOCK_1H_LIQ_SHORT_MAX;
21467
21813
  const q4LongAltLeadershipRecoveryAllowedReasons = [
21468
21814
  "flat_or_mixed_oi",
21469
21815
  "neutral_derivatives_pressure",
@@ -21510,9 +21856,13 @@ var buildTrendShiftGuardrailContext = ({
21510
21856
  shortExtremeAtrHighBbRisk,
21511
21857
  shortBullSwingStructureRisk,
21512
21858
  shortLowBollingerWidthRisk,
21859
+ shortAsiaLongFlushLowCmcBreadthRisk,
21860
+ derivativesDataUnavailableStressRisk,
21513
21861
  lowRewardToVolatilityRisk,
21514
21862
  defensiveRewardToVolatilityRisk,
21863
+ bnbReferenceOiExpansionRisk,
21515
21864
  longBtcAltRegimeRisk,
21865
+ longBroadMarketShortFlushRisk,
21516
21866
  cmcExchangeLiquidityVolumeChangeRisk,
21517
21867
  q4TrendShiftGateFeaturesRecoveryCandidate,
21518
21868
  q4UsClosingOiConfirmationRecoveryCandidate,
@@ -21528,10 +21878,14 @@ var buildTrendShiftGuardrailContext = ({
21528
21878
  nearPointOfControl,
21529
21879
  relativeStrength1h,
21530
21880
  marketBreadthReturn,
21881
+ marketBreadthAdvancers,
21882
+ marketBreadthPctAboveMa20,
21531
21883
  btcVsAltReturn24h,
21532
21884
  btcVsAltReturn1h,
21885
+ cmcFearGreedValue,
21533
21886
  cmcFearGreedValueChange24h,
21534
21887
  derivatives1hLiqShort,
21888
+ bnbReferenceOiChangePct4h,
21535
21889
  btcAltRegime,
21536
21890
  cmcExchangeLiquidityVolumeChange24hPct,
21537
21891
  trendShiftGateFeatures,
@@ -21597,12 +21951,20 @@ var getTrendShiftGuardrailReasonText = (reason) => {
21597
21951
  return "the SHORT flip is still fighting a bullish swing structure, so keep it in watch mode";
21598
21952
  case "short_low_bollinger_width":
21599
21953
  return "the SHORT flip is in a narrow Bollinger-width compression pocket that has been less reliable, so keep it in watch mode";
21954
+ case "short_asia_long_flush_low_cmc_breadth":
21955
+ return "the SHORT flip is selling an Asia-session long flush while CMC fear/greed and market breadth are already in capitulation, so keep it in watch mode";
21956
+ case "derivatives_data_unavailable_stress":
21957
+ return "benchmark derivatives data is missing or stale during CMC stress, so keep the flip in watch mode instead of treating neutral derivatives as confirmation";
21600
21958
  case "low_reward_to_volatility":
21601
21959
  return "the expected reward is too small relative to current volatility after costs, so keep the flip in watch mode";
21602
21960
  case "reward_to_volatility_below_defensive_threshold":
21603
21961
  return "the expected reward is not large enough relative to current volatility for the defensive TrendShift gate after costs";
21962
+ case "bnb_reference_1h_oi4h_expansion_risk":
21963
+ return "BNB reference 1h open interest is expanding over 4h, a historically fragile cross-market state for TrendShift approvals";
21604
21964
  case "long_btc_alt_regime_risk":
21605
21965
  return "the LONG flip is fighting a BTC-led or risk-off alt regime, so keep it in watch mode";
21966
+ case "long_broad_market_short_flush_risk":
21967
+ return "the LONG flip is chasing a broad-market squeeze while BTC is leading alts and benchmark derivatives show a short flush, so keep it in watch mode";
21606
21968
  case "cmc_exchange_liquidity_volume_change_risk":
21607
21969
  return "major-exchange liquidity change is in a historically choppy CMC band, so keep the flip in watch mode";
21608
21970
  default:
@@ -21717,8 +22079,11 @@ Additional TrendShift context:
21717
22079
  - nearPointOfControl=${String(context.nearPointOfControl ?? "n/a")}
21718
22080
  - relativeStrength1h=${String(context.relativeStrength1h ?? "n/a")}
21719
22081
  - marketBreadthReturn=${String(context.marketBreadthReturn ?? "n/a")}
22082
+ - marketBreadthAdvancers=${String(context.marketBreadthAdvancers ?? "n/a")}
22083
+ - marketBreadthPctAboveMa20=${String(context.marketBreadthPctAboveMa20 ?? "n/a")}
21720
22084
  - btcVsAltReturn24h=${String(context.btcVsAltReturn24h ?? "n/a")}
21721
22085
  - btcVsAltReturn1h=${String(context.btcVsAltReturn1h ?? "n/a")}
22086
+ - cmcFearGreedValue=${String(context.cmcFearGreedValue ?? "n/a")}
21722
22087
  - cmcFearGreedValueChange24h=${String(context.cmcFearGreedValueChange24h ?? "n/a")}
21723
22088
  - derivatives1hLiqShort=${String(context.derivatives1hLiqShort ?? "n/a")}
21724
22089
  - btcAltRegime=${context.btcAltRegime ?? "n/a"}
@@ -21747,7 +22112,12 @@ Additional TrendShift context:
21747
22112
  - shortLowBollingerWidthRisk=${String(context.shortLowBollingerWidthRisk)}
21748
22113
  - defensiveRewardToVolatilityRisk=${String(context.defensiveRewardToVolatilityRisk)}
21749
22114
  - shortBullSwingStructureRisk=${String(context.shortBullSwingStructureRisk)}
22115
+ - shortAsiaLongFlushLowCmcBreadthRisk=${String(context.shortAsiaLongFlushLowCmcBreadthRisk)}
22116
+ - derivativesDataUnavailableStressRisk=${String(context.derivativesDataUnavailableStressRisk)}
21750
22117
  - longBtcAltRegimeRisk=${String(context.longBtcAltRegimeRisk)}
22118
+ - longBroadMarketShortFlushRisk=${String(context.longBroadMarketShortFlushRisk)}
22119
+ - bnbReferenceOiChangePct4h=${String(context.bnbReferenceOiChangePct4h ?? "n/a")}
22120
+ - bnbReferenceOiExpansionRisk=${String(context.bnbReferenceOiExpansionRisk)}
21751
22121
  - cmcExchangeLiquidityVolumeChangeRisk=${String(context.cmcExchangeLiquidityVolumeChangeRisk)}
21752
22122
  - q4TrendShiftGateFeaturesRecoveryCandidate=${String(context.q4TrendShiftGateFeaturesRecoveryCandidate)}
21753
22123
  - q4UsClosingOiConfirmationRecoveryCandidate=${String(context.q4UsClosingOiConfirmationRecoveryCandidate)}
@@ -21784,11 +22154,15 @@ Interpretation rules for TrendShift:
21784
22154
  - For SHORT, being near the price-volume point of control is a watch-only warning; LONG near-POC flips are not blocked by this rule.
21785
22155
  - For SHORT, a bullish swing structure is a watch-only warning even when the immediate flip geometry looks q5-strong.
21786
22156
  - For SHORT, a narrow Bollinger-width compression pocket is watch-only even if another q4 recovery condition is present.
22157
+ - For SHORT, Asia-session long-flush setups are watch-only when CMC fear/greed and market breadth are already in capitulation.
22158
+ - If benchmark derivatives data is missing or stale while CMC fear/greed is in stress mode, keep the flip in watch mode; neutral/unknown derivatives are not confirmation in that state.
21787
22159
  - The defensive live gate requires rewardToVolatility >= 8 when that field is available.
22160
+ - If BNB reference 1h open interest is expanding over the last 4h, keep TrendShift flips in watch mode; this is a defensive cross-market risk cut, not target-symbol evidence.
21788
22161
  - For LONG, BTC-led or risk-off BTC/alt regime is watch-only even when flip geometry is q5-strong.
22162
+ - For LONG, broad-market squeeze clusters are watch-only when breadth is already extreme, BTC is leading alts, and benchmark derivatives show a short flush.
21789
22163
  - If CMC major-exchange liquidity 24h change is in the historically choppy bands (-0.1, 0) or [0.1, 0.3), keep the flip in watch mode.
21790
22164
  - A narrow q4 recovery is allowed during the US closing window only when the sole blocker is missing OI expansion on an otherwise liquidation-supported US-session flush.
21791
- - A narrow SHORT q4 recovery may pass during a market breadth shock only when marketBreadthReturn <= -0.0112952 and 1h liqShort <= 0.208; this does not override the low-Bollinger-width defensive cut.
22165
+ - A narrow SHORT q4 recovery may pass during a market breadth shock only when marketBreadthReturn <= -0.0112952 and 1h liqShort <= 0.208; this does not override existing hard blockers or the low-Bollinger-width defensive cut.
21792
22166
  - A narrow LONG q4 recovery may pass only when alt leadership is clear (btcVsAltReturn24h <= -0.00503054 and btcVsAltReturn1h <= -0.00581403), fear/greed is not falling hard, and the only blockers are the tested OI/benchmark-derivatives or defensive reward-to-volatility blockers.
21793
22167
  - If hardBlockReasons is not empty, explain exactly what is still missing for confirmation.
21794
22168
  `.trim();
@@ -22104,6 +22478,9 @@ var TRENDLINE_PAYLOAD_PROMPT = `
22104
22478
  - It also includes 'atrPct / breakVsAtrRatio / coinMaSpreadPct / btcMaSpreadPct / aggressivePreBreakPressure / strongNearBreakPressure / weakCleanBreak / compressedCleanBreak / weakBtcLedBreak / weakLongFarBreak'.
22105
22479
  - If 'payload.additionalIndicators.baseContext.derivatives' exists, it contains Coinalyze-derived open interest, funding, and liquidation fields for the signal moment; do not treat 'stale' or 'missing_derivatives' as confirmation or conflict.
22106
22480
  `;
22481
+ var MARKET_CONTEXT_PRIMARY_ISSUE = "market_context_against";
22482
+ var MARKET_CONTEXT_TOTAL_MARKET_CAP_USD_MIN = 233e10;
22483
+ var MARKET_CONTEXT_TREND_PERSISTENCE_MAX = 0.77;
22107
22484
  var getRecord2 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
22108
22485
  var getNestedRecord3 = (source, path) => {
22109
22486
  let current = source;
@@ -22179,6 +22556,22 @@ var buildTrendlineContext = (signal) => {
22179
22556
  const volumeStructurePocIndex = toFiniteNumberOrNull5(
22180
22557
  participationVolumeStructure?.pocIndex
22181
22558
  );
22559
+ const gateDecisionHints = getNestedRecord3(baseContext, [
22560
+ "gateFeatures",
22561
+ "decisionHints"
22562
+ ]);
22563
+ const gatePrimaryIssue = typeof gateDecisionHints?.primaryIssue === "string" ? gateDecisionHints.primaryIssue : null;
22564
+ const cmcGlobalContext = getNestedRecord3(baseContext, [
22565
+ "relative",
22566
+ "cmcGlobal"
22567
+ ]);
22568
+ const cmcTotalMarketCapUsd = toFiniteNumberOrNull5(
22569
+ cmcGlobalContext?.totalMarketCapUsd
22570
+ );
22571
+ const trendRegimeContext = getNestedRecord3(baseContext, ["regime", "trend"]);
22572
+ const trendPersistence = toFiniteNumberOrNull5(
22573
+ trendRegimeContext?.persistence
22574
+ );
22182
22575
  const benchmarkTrendAlignment = typeof benchmarkContext?.trendAlignment === "string" ? benchmarkContext.trendAlignment : null;
22183
22576
  const executionContext = getNestedRecord3(baseContext, [
22184
22577
  "relative",
@@ -22230,7 +22623,7 @@ var buildTrendlineContext = (signal) => {
22230
22623
  if (structural.signalDirection === "SHORT" && (entryTiming === "ready_follow_through" || entryTiming === "ready_retest") && (sessionPrimary === "off_hours" || sessionIsOverlap) && !hardBlockReasons.includes("short_session_risk")) {
22231
22624
  hardBlockReasons.push("short_session_risk");
22232
22625
  }
22233
- const deterministicQuality = getDeterministicTrendlineQuality({
22626
+ const baseDeterministicQuality = getDeterministicTrendlineQuality({
22234
22627
  signalDirection: structural.signalDirection,
22235
22628
  clearBreak: structural.clearBreak,
22236
22629
  nearLineNoise: structural.nearLineNoise,
@@ -22245,16 +22638,18 @@ var buildTrendlineContext = (signal) => {
22245
22638
  entryTiming,
22246
22639
  coinMaSpreadPct
22247
22640
  });
22641
+ const marketContextApprovalPocket = gatePrimaryIssue === MARKET_CONTEXT_PRIMARY_ISSUE && cmcTotalMarketCapUsd != null && cmcTotalMarketCapUsd >= MARKET_CONTEXT_TOTAL_MARKET_CAP_USD_MIN && trendPersistence != null && trendPersistence <= MARKET_CONTEXT_TREND_PERSISTENCE_MAX;
22642
+ const deterministicQuality = marketContextApprovalPocket ? 4 : baseDeterministicQuality;
22248
22643
  const maxAllowedQuality = deterministicQuality;
22249
22644
  const longUsLowVolumeCrowdedShortSqueeze = structural.signalDirection === "LONG" && sessionPrimary === "us" && volumeRel20 != null && volumeRel20 < 0.8 && derivativesRiskFlags.includes("crowded_short") && benchmarkTrendAlignment !== "against_benchmark";
22250
22645
  const longHistoricalApprovalPocket = venueSpreadZScore != null && venueSpreadZScore <= -1 || longUsLowVolumeCrowdedShortSqueeze || sessionPrimary !== "europe" && !derivativesRiskFlags.includes("missing_derivatives") && !(structural.breakVsAtrRatio != null && structural.breakVsAtrRatio >= 0.8 && structural.breakVsAtrRatio < 1.2) && volumeRel20 != null && volumeRel20 >= 0.8 && benchmarkTrendAlignment !== "against_benchmark";
22251
- const longHighQualitySessionApproval = deterministicQuality >= 5 && sessionPrimary !== "asia";
22646
+ const longHighQualitySessionApproval = baseDeterministicQuality >= 5 && sessionPrimary !== "asia";
22252
22647
  const longStrongDerivativesAlignedApproval = volumeRel20 != null && volumeRel20 >= 1.5 && derivativesDirectionAligned === true;
22253
- const longModerateRetestLiquidSessionApproval = structural.signalDirection === "LONG" && deterministicQuality === 4 && entryTiming === "ready_retest" && (sessionPrimary === "us" || sessionPrimary === "europe") && volumeRel20 != null && volumeRel20 >= 0.8 && volumeRel20 < 1.5 && benchmarkTrendAlignment !== "against_benchmark" && derivativesDirectionAligned == null && derivativesRiskFlags.length > 0 && !oiNotConfirming;
22648
+ const longModerateRetestLiquidSessionApproval = structural.signalDirection === "LONG" && baseDeterministicQuality === 4 && entryTiming === "ready_retest" && (sessionPrimary === "us" || sessionPrimary === "europe") && volumeRel20 != null && volumeRel20 >= 0.8 && volumeRel20 < 1.5 && benchmarkTrendAlignment !== "against_benchmark" && derivativesDirectionAligned == null && derivativesRiskFlags.length > 0 && !oiNotConfirming;
22254
22649
  const longBaseContextApprovalPocket = structural.signalDirection !== "LONG" || longModerateRetestLiquidSessionApproval || longHistoricalApprovalPocket && (longHighQualitySessionApproval || longStrongDerivativesAlignedApproval);
22255
22650
  const shortThinNeutralBenchmarkRisk = structural.signalDirection === "SHORT" && volumeRel20 != null && volumeRel20 < 0.8 && benchmarkTrendAlignment === "neutral";
22256
- const q4ReferenceOiPocApproval = deterministicQuality === 4 && volumeStructurePocIndex != null && volumeStructurePocIndex >= 5 && ethReferenceOiAcceleration != null && ethReferenceOiAcceleration <= -0.5906;
22257
- const approvalAllowedNow = deterministicQuality >= 4 && longBaseContextApprovalPocket && !shortThinNeutralBenchmarkRisk && (deterministicQuality >= 5 || q4ReferenceOiPocApproval);
22651
+ const q4ReferenceOiPocApproval = baseDeterministicQuality === 4 && volumeStructurePocIndex != null && volumeStructurePocIndex >= 5 && ethReferenceOiAcceleration != null && ethReferenceOiAcceleration <= -0.5906;
22652
+ const approvalAllowedNow = marketContextApprovalPocket;
22258
22653
  const trendLineGateFeatures = buildTrendLineGateFeatures({
22259
22654
  structural,
22260
22655
  entryTiming,
@@ -22290,6 +22685,11 @@ var buildTrendlineContext = (signal) => {
22290
22685
  derivativesRiskFlags,
22291
22686
  ethReferenceOiAcceleration,
22292
22687
  oiNotConfirming,
22688
+ gatePrimaryIssue,
22689
+ cmcTotalMarketCapUsd,
22690
+ trendPersistence,
22691
+ marketContextApprovalPocket,
22692
+ baseDeterministicQuality,
22293
22693
  longUsLowVolumeCrowdedShortSqueeze,
22294
22694
  longHighQualitySessionApproval,
22295
22695
  longStrongDerivativesAlignedApproval,
@@ -22539,6 +22939,11 @@ Additional TrendLine context:
22539
22939
  - trendline.volumeStructurePocIndex=${formatPromptNumber(trendlineContext.volumeStructurePocIndex, 0)}
22540
22940
  - trendline.ethReferenceOiAcceleration=${formatPromptNumber(trendlineContext.ethReferenceOiAcceleration, 3)}
22541
22941
  - trendline.q4ReferenceOiPocApproval=${String(trendlineContext.q4ReferenceOiPocApproval)}
22942
+ - trendline.gatePrimaryIssue=${trendlineContext.gatePrimaryIssue ?? "n/a"}
22943
+ - trendline.cmcTotalMarketCapUsd=${formatPromptNumber(trendlineContext.cmcTotalMarketCapUsd, 0)}
22944
+ - trendline.trendPersistence=${formatPromptNumber(trendlineContext.trendPersistence, 3)}
22945
+ - trendline.marketContextApprovalPocket=${String(trendlineContext.marketContextApprovalPocket)}
22946
+ - trendline.baseDeterministicQuality=${String(trendlineContext.baseDeterministicQuality)}
22542
22947
  - trendline.weakCleanBreak=${String(trendlineContext.weakCleanBreak)}
22543
22948
  - trendline.compressedCleanBreak=${String(trendlineContext.compressedCleanBreak)}
22544
22949
  - trendline.weakBtcLedBreak=${String(trendlineContext.weakBtcLedBreak)}
@@ -22817,10 +23222,13 @@ VolumeDivergence addon:
22817
23222
  `;
22818
23223
  var VOLUME_DIVERGENCE_PAYLOAD_PROMPT = `
22819
23224
  - \`payload.additionalIndicators.volumeDivergenceContext\` contains a compact divergence-strength summary:
22820
- divergenceKind / confirmationPrice / confirmationReady / structureAdvanced / reboundFromPivotPct / confirmationDistancePct / priceDisplacementPct / divergenceAmplitudeAtrRatio / reclaimPct / confirmationCandleQuality / volumeDivergenceStrength / deltaAligned / coinBiasAligned / btcBiasAligned / derivativesDirectionAligned / derivativesRiskFlags / derivativesLiqSpikeRatio / venueSpreadZScore / volumeRel20 / rangePosition20 / deterministicQuality / approvalAllowedNow / structuralHardBlockReasons / maxAllowedQuality.
23225
+ divergenceKind / confirmationPrice / confirmationReady / structureAdvanced / reboundFromPivotPct / confirmationDistancePct / priceDisplacementPct / divergenceAmplitudeAtrRatio / reclaimPct / confirmationCandleQuality / volumeDivergenceStrength / deltaAligned / coinBiasAligned / btcBiasAligned / derivativesDirectionAligned / derivativesRiskFlags / derivativesLiqSpikeRatio / venueSpreadZScore / volumeRel20 / rangePosition20 / btcOiChangePct1h15m / solOpenInterest15m / xrpFundingZScore15m / derivativesRegimePocket / deterministicQuality / approvalAllowedNow / structuralHardBlockReasons / maxAllowedQuality.
22821
23226
  - Use this context as the explicit strategy-specific summary instead of trying to derive the same conclusion again only from generic candles.
22822
23227
  - If \`payload.additionalIndicators.baseContext.derivatives\` exists, it is a Coinalyze-derived summary of derivatives state at signal time; \`stale\` or \`missing_derivatives\` means that Coinalyze context must not be used.
22823
23228
  `;
23229
+ var BTC_OI_CHANGE_PCT_1H_15M_MAX = -0.32;
23230
+ var SOL_OPEN_INTEREST_15M_MIN = 101e5;
23231
+ var XRP_FUNDING_Z_SCORE_15M_MAX = -1.2;
22824
23232
  var toFiniteNumberOrNull6 = (value) => {
22825
23233
  if (typeof value === "number" && Number.isFinite(value)) {
22826
23234
  return value;
@@ -23187,6 +23595,23 @@ var getVolumeDivergenceContext = (signal) => {
23187
23595
  const derivativesRiskFlags = getStringArray3(derivativesSummary?.riskFlags);
23188
23596
  const derivativesFundingZScore = toFiniteNumberOrNull6(derivatives15m?.fundingZScore) ?? toFiniteNumberOrNull6(derivatives1h?.fundingZScore);
23189
23597
  const derivativesLiqSpikeRatio = toFiniteNumberOrNull6(derivatives15m?.liqSpikeRatio) ?? toFiniteNumberOrNull6(derivatives1h?.liqSpikeRatio);
23598
+ const btcOiChangePct1h15m = toFiniteNumberOrNull6(
23599
+ derivatives15m?.oiChangePct1h
23600
+ );
23601
+ const solOpenInterest15m = getNestedNumber3(derivativesContext, [
23602
+ "referenceContexts",
23603
+ "SOLUSDT",
23604
+ "intervals",
23605
+ "15m",
23606
+ "openInterest"
23607
+ ]);
23608
+ const xrpFundingZScore15m = getNestedNumber3(derivativesContext, [
23609
+ "referenceContexts",
23610
+ "XRPUSDT",
23611
+ "intervals",
23612
+ "15m",
23613
+ "fundingZScore"
23614
+ ]);
23190
23615
  const marketContext = getRecord3(additional?.marketContext);
23191
23616
  const venueSpreadZScore = getNestedNumber3(marketContext, [
23192
23617
  "execution",
@@ -23286,9 +23711,9 @@ var getVolumeDivergenceContext = (signal) => {
23286
23711
  entryThresholds,
23287
23712
  aiThresholds
23288
23713
  }) : hardBlockReasons.length > 0 ? 2 : 3;
23289
- const longApprovalPocket = signalDirection !== "LONG" || isAtLeast2(confirmationDistancePct, 2) && isAtLeast2(volumeRel20, 1) && isAtLeast2(venueSpreadZScore, 1.5365);
23290
- const shortApprovalPocket = signalDirection !== "SHORT" || isAtMost(venueSpreadZScore, 0) && rangePosition20 != null && rangePosition20 < 0.2;
23291
- const approvalAllowedNow = hardBlockReasons.length === 0 && deterministicQuality >= 4 && confirmationReady && longApprovalPocket && shortApprovalPocket;
23714
+ const derivativesRegimePocket = isAtMost(btcOiChangePct1h15m, BTC_OI_CHANGE_PCT_1H_15M_MAX) && isAtLeast2(solOpenInterest15m, SOL_OPEN_INTEREST_15M_MIN) && isAtMost(xrpFundingZScore15m, XRP_FUNDING_Z_SCORE_15M_MAX);
23715
+ const maxAllowedQuality = derivativesRegimePocket ? Math.max(deterministicQuality, 4) : deterministicQuality;
23716
+ const approvalAllowedNow = hardBlockReasons.length === 0 && confirmationReady && derivativesRegimePocket && maxAllowedQuality >= 4;
23292
23717
  return {
23293
23718
  signalDirection,
23294
23719
  divergenceKind,
@@ -23321,12 +23746,16 @@ var getVolumeDivergenceContext = (signal) => {
23321
23746
  venueSpreadZScore,
23322
23747
  volumeRel20,
23323
23748
  rangePosition20,
23749
+ btcOiChangePct1h15m,
23750
+ solOpenInterest15m,
23751
+ xrpFundingZScore15m,
23752
+ derivativesRegimePocket,
23324
23753
  sessionPhase,
23325
23754
  hardBlockReasons,
23326
23755
  structuralHardBlockReasons: [...hardBlockReasons],
23327
23756
  deterministicQuality,
23328
23757
  approvalAllowedNow,
23329
- maxAllowedQuality: deterministicQuality
23758
+ maxAllowedQuality
23330
23759
  };
23331
23760
  };
23332
23761
  var getVolumeDivergenceContextFromPayload = (payload, signal) => {
@@ -23377,6 +23806,7 @@ var postProcessAnalysis2 = ({
23377
23806
  );
23378
23807
  const needRetest = finalDirection == null;
23379
23808
  const retestPrice = needRetest ? context.confirmationPrice : null;
23809
+ const approvedQuality = finalDirection != null && context.maxAllowedQuality >= 4 ? Math.max(finalQuality, 4) : finalQuality;
23380
23810
  if (finalDirection == null) {
23381
23811
  return {
23382
23812
  ...analysis,
@@ -23394,7 +23824,7 @@ var postProcessAnalysis2 = ({
23394
23824
  return {
23395
23825
  ...analysis,
23396
23826
  direction: finalDirection,
23397
- quality: finalQuality,
23827
+ quality: approvedQuality,
23398
23828
  needRetest,
23399
23829
  retestPrice,
23400
23830
  takeProfitPrice: signal.prices?.takeProfitPrice ?? null,
@@ -23440,6 +23870,10 @@ Additional VolumeDivergence context:
23440
23870
  - venueSpreadZScore=${context.venueSpreadZScore?.toFixed?.(3) ?? "n/a"}
23441
23871
  - volumeRel20=${context.volumeRel20?.toFixed?.(3) ?? "n/a"}
23442
23872
  - rangePosition20=${context.rangePosition20?.toFixed?.(3) ?? "n/a"}
23873
+ - btcOiChangePct1h15m=${context.btcOiChangePct1h15m?.toFixed?.(3) ?? "n/a"}
23874
+ - solOpenInterest15m=${context.solOpenInterest15m?.toFixed?.(0) ?? "n/a"}
23875
+ - xrpFundingZScore15m=${context.xrpFundingZScore15m?.toFixed?.(3) ?? "n/a"}
23876
+ - derivativesRegimePocket=${context.derivativesRegimePocket}
23443
23877
  - barsSincePivot=${context.barsSincePivot ?? "n/a"}
23444
23878
  - barsBetweenPivotConfirmations=${context.barsBetweenPivotConfirmations ?? "n/a"}
23445
23879
  - entryTiming=${context.entryTiming ?? "n/a"}