@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.mjs CHANGED
@@ -16481,9 +16481,10 @@ AdaptiveMomentumRibbon addon:
16481
16481
  - \`quality=4\` additionally allows two narrower continuation pockets: oscillatorStrength >= 1.2 with coin bias conflict, structuralRewardRiskRatio >= 2.2 and volumeRel20 <= 1.2, or Europe-session oscillatorStrength >= 1.5 with effortVsResult <= 120.
16482
16482
  - If signal candle range is available, \`signalRangeAtrRatio\` must be >= 1.05 for live approval; weaker signal candles stay in watch mode.
16483
16483
  - The local deterministic gate approves LONG by default. SHORT stays in watch mode except for separately calibrated market-breadth shock pockets.
16484
- - SHORT breadth-shock approvals use two calibrated pockets: BTC-favored breadth shock, or a neutral shared-context breadth exhaustion pocket with marketBreadth.advancers <= 0 and effortVsResult <= 800.
16484
+ - SHORT watch-mode approvals use three calibrated pockets: BTC-favored breadth shock, neutral shared-context breadth exhaustion with marketBreadth.advancers <= 0 and effortVsResult <= 800, or low-CMC benchmark OI contraction with BTC net flow <= 0.
16485
16485
  - A reference-derivatives rotation pocket can approve q4 when XRP 15m OI 4h change >= 1.6 and TRX 15m OI 4h change <= -0.2. It may override weak signal range and the default SHORT watch mode, but never hard signal invalidation.
16486
16486
  - Non-derivatives approvals are demoted when stopDistanceAtr > 4.5 and breakoutBodyAtr > 2.25, because that combination behaves like a chase entry.
16487
+ - All live approvals require a calibrated market-regime floor: tpDistanceAtr >= 2.9, trendAdx >= 15, and benchmarkRelativeStrength1d <= 4 when available.
16487
16488
  - LONG approvals require cmcAltLiquidityRegime to be anything except \`btc_favored\` when that CMC field is available.
16488
16489
  - Non-q5 LONG approvals require targetVsBtcAlpha1h <= 2.4 when that field is available, to avoid chase entries after target already outran BTC.
16489
16490
  - \`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.
@@ -16492,16 +16493,22 @@ AdaptiveMomentumRibbon addon:
16492
16493
  `;
16493
16494
  var ADAPTIVE_MOMENTUM_RIBBON_PAYLOAD_PROMPT = `
16494
16495
  - \`payload.additionalIndicators.adaptiveMomentumRibbonContext\` contains a compact signal summary:
16495
- 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.
16496
+ signalOsc / oscillatorStrength / signalRangeAtrRatio / stopDistanceAtr / tpDistanceAtr / breakoutBodyAtr / trendAdx / benchmarkRelativeStrength1d / chaseRiskBlocked / approvalRegimeAllowed / approvalRegimeBlockReasons / channelState / channelExtensionPct / invalidationDistancePct / structuralRewardRiskRatio / coinBiasAligned / btcBiasAligned / targetVsBtcAlpha1h / targetVsBtcAlpha4h / spreadBps / cmcAltLiquidityRegime / cmcTotalMarketCapUsd / cmcFearGreedValueChange7d / cmcBtcDominanceChange24hPct / benchmarkOiChangePct24h1h / btcReferenceTradeFlowNetBaseDelta / baseDecisionApproveBias / marketBreadthAdvancers / marketBreadthAdvanceDeclineRatio / marketBreadthReturn / shortBreadthShockPocket / shortBreadthNeutralPocket / shortCmcBenchmarkContractionPocket / referenceDerivativesRotationPocket / referenceXrpOiChangePct4h15m / referenceTrxOiChangePct4h15m / q4TargetAlpha1Allowed / q4ContinuationAllowed / q4ContinuationBlockReasons / q4ContinuationRecoveryAllowed / derivativesDirectionAligned / derivativesRiskFlags / derivativesFundingZScore / deterministicQuality / approvalAllowedNow / approvalBlockReasons / riskAnnotations.
16496
16497
  - Use this context as the primary strategy-specific interpretation instead of re-deriving it only from generic series.
16497
16498
  `;
16498
16499
  var SHORT_BREADTH_SHOCK_MARKET_BREADTH_RETURN_MAX = -0.01;
16499
16500
  var SHORT_BREADTH_NEUTRAL_EFFORT_VS_RESULT_MAX = 800;
16501
+ var SHORT_CMC_TOTAL_MARKET_CAP_USD_MAX = 229e10;
16502
+ var SHORT_BENCHMARK_OI_CHANGE_PCT_24H_1H_MAX = -4;
16503
+ var SHORT_BTC_REFERENCE_TRADE_FLOW_NET_BASE_DELTA_MAX = 0;
16500
16504
  var Q4_TARGET_VS_BTC_ALPHA_1H_MAX = 2.4;
16501
16505
  var REFERENCE_XRP_OI_CHANGE_PCT_4H_15M_MIN = 1.6;
16502
16506
  var REFERENCE_TRX_OI_CHANGE_PCT_4H_15M_MAX = -0.2;
16503
16507
  var CHASE_STOP_DISTANCE_ATR_MAX = 4.5;
16504
16508
  var CHASE_BREAKOUT_BODY_ATR_MAX = 2.25;
16509
+ var MIN_APPROVAL_TP_DISTANCE_ATR = 2.9;
16510
+ var MIN_APPROVAL_TREND_ADX = 15;
16511
+ var MAX_APPROVAL_BENCHMARK_RELATIVE_STRENGTH_1D = 4;
16505
16512
  var toFiniteNumberOrNull = (value) => {
16506
16513
  if (typeof value === "number" && Number.isFinite(value)) {
16507
16514
  return value;
@@ -16676,6 +16683,19 @@ var getQ4ContinuationBlockReasons = (context) => {
16676
16683
  return reasons;
16677
16684
  };
16678
16685
  var getQ4ContinuationRecoveryAllowed = (context) => context.q4TargetAlpha1Allowed && !context.q4ContinuationAllowed && isInRange(context.effortVsResult, 0, 60) && context.cmcBtcDominanceChange24hPct != null && context.cmcBtcDominanceChange24hPct <= 0;
16686
+ var getApprovalRegimeBlockReasons = (context) => {
16687
+ const reasons = [];
16688
+ if (context.tpDistanceAtr == null || context.tpDistanceAtr < MIN_APPROVAL_TP_DISTANCE_ATR) {
16689
+ reasons.push("low_tp_distance_atr");
16690
+ }
16691
+ if (context.trendAdx == null || context.trendAdx < MIN_APPROVAL_TREND_ADX) {
16692
+ reasons.push("weak_trend_adx");
16693
+ }
16694
+ if (context.benchmarkRelativeStrength1d != null && context.benchmarkRelativeStrength1d > MAX_APPROVAL_BENCHMARK_RELATIVE_STRENGTH_1D) {
16695
+ reasons.push("benchmark_1d_chase_risk");
16696
+ }
16697
+ return reasons;
16698
+ };
16679
16699
  var getDeterministicAdaptiveMomentumRibbonQuality = (context) => {
16680
16700
  if (context.hardBlockReasons.length > 0) {
16681
16701
  return 2;
@@ -16689,8 +16709,11 @@ var getDeterministicAdaptiveMomentumRibbonQuality = (context) => {
16689
16709
  if (context.chaseRiskBlocked && !context.referenceDerivativesRotationPocket) {
16690
16710
  return 3;
16691
16711
  }
16712
+ if (!context.approvalRegimeAllowed) {
16713
+ return 3;
16714
+ }
16692
16715
  if (context.signalDirection === "SHORT") {
16693
- return context.shortBreadthShockPocket || context.shortBreadthNeutralPocket || context.referenceDerivativesRotationPocket ? 4 : 3;
16716
+ return context.shortBreadthShockPocket || context.shortBreadthNeutralPocket || context.shortCmcBenchmarkContractionPocket || context.referenceDerivativesRotationPocket ? 4 : 3;
16694
16717
  }
16695
16718
  if (context.signalDirection === "LONG" && context.cmcAltLiquidityRegime === "btc_favored") {
16696
16719
  return 3;
@@ -16701,12 +16724,12 @@ var getDeterministicAdaptiveMomentumRibbonQuality = (context) => {
16701
16724
  if (causalMomentumLowEffortPocket) {
16702
16725
  return 5;
16703
16726
  }
16727
+ if (context.signalDirection === "LONG" && !context.q4TargetAlpha1Allowed) {
16728
+ return 3;
16729
+ }
16704
16730
  if (context.referenceDerivativesRotationPocket) {
16705
16731
  return 4;
16706
16732
  }
16707
- if (!context.q4TargetAlpha1Allowed) {
16708
- return 3;
16709
- }
16710
16733
  if (context.q4ContinuationRecoveryAllowed) {
16711
16734
  return 4;
16712
16735
  }
@@ -16803,6 +16826,8 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16803
16826
  const candle = getRecord(baseContext?.candle);
16804
16827
  const raw = getRecord(baseContext?.raw);
16805
16828
  const regime = getRecord(baseContext?.regime);
16829
+ const regimeTrend = getRecord(regime?.trend);
16830
+ const regimeTrendAdx = getRecord(regimeTrend?.adx);
16806
16831
  const regimeSession = getRecord(regime?.session);
16807
16832
  const structure = getRecord(baseContext?.structure);
16808
16833
  const localRange = getRecord(structure?.localRange);
@@ -16814,6 +16839,8 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16814
16839
  const gateFeaturesRelative = getRecord(gateFeatures?.relative);
16815
16840
  const gateFeaturesDecisionHints = getRecord(gateFeatures?.decisionHints);
16816
16841
  const baseDerivativesContext = getRecord(baseContext?.derivatives);
16842
+ const baseDerivativesIntervals = getRecord(baseDerivativesContext?.intervals);
16843
+ const baseDerivatives1h = getRecord(baseDerivativesIntervals?.["1h"]);
16817
16844
  const referenceDerivativeContexts = getRecord(
16818
16845
  baseDerivativesContext?.referenceContexts
16819
16846
  );
@@ -16827,6 +16854,11 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16827
16854
  const targetVsBtc = getRecord(relative?.targetVsBtc);
16828
16855
  const cmcGlobal = getRecord(relative?.cmcGlobal);
16829
16856
  const cmcFearGreed = getRecord(relative?.cmcFearGreed);
16857
+ const referenceTradeFlow = getRecord(relative?.referenceTradeFlow);
16858
+ const referenceTradeFlowBySymbol = getRecord(
16859
+ referenceTradeFlow?.tradeFlowBySymbol
16860
+ );
16861
+ const btcReferenceTradeFlow = getRecord(referenceTradeFlowBySymbol?.BTCUSDT);
16830
16862
  const baseMarketBreadth = getRecord(relative?.marketBreadth);
16831
16863
  const structureAcceptance = getRecord(structure?.acceptance);
16832
16864
  const marketContext = getRecord(additional?.marketContext);
@@ -16842,6 +16874,9 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16842
16874
  const benchmarkRelativeStrength1h = toFiniteNumberOrNull(
16843
16875
  benchmark?.relativeStrength1h
16844
16876
  );
16877
+ const benchmarkRelativeStrength1d = toFiniteNumberOrNull(
16878
+ benchmark?.relativeStrength1d
16879
+ );
16845
16880
  const benchmarkTrendAlignment = typeof benchmark?.trendAlignment === "string" ? benchmark.trendAlignment : null;
16846
16881
  const targetVsBtcAlpha1h = toFiniteNumberOrNull(targetVsBtc?.alphaVsBtc1h);
16847
16882
  const targetVsBtcAlpha4h = toFiniteNumberOrNull(targetVsBtc?.alphaVsBtc4h);
@@ -16860,6 +16895,8 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16860
16895
  const stopDistanceAtr = toFiniteNumberOrNull(
16861
16896
  gateFeaturesSetup?.stopDistanceAtr
16862
16897
  );
16898
+ const tpDistanceAtr = toFiniteNumberOrNull(gateFeaturesSetup?.tpDistanceAtr);
16899
+ const trendAdx = toFiniteNumberOrNull(regimeTrendAdx?.adx);
16863
16900
  const breakoutBodyAtr = toFiniteNumberOrNull(
16864
16901
  structureAcceptance?.breakoutBodyAtr
16865
16902
  );
@@ -16872,12 +16909,21 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16872
16909
  );
16873
16910
  const referenceDerivativesRotationPocket = referenceXrpOiChangePct4h15m != null && referenceXrpOiChangePct4h15m >= REFERENCE_XRP_OI_CHANGE_PCT_4H_15M_MIN && referenceTrxOiChangePct4h15m != null && referenceTrxOiChangePct4h15m <= REFERENCE_TRX_OI_CHANGE_PCT_4H_15M_MAX;
16874
16911
  const cmcAltLiquidityRegime = typeof cmcGlobal?.altLiquidityRegime === "string" && cmcGlobal.altLiquidityRegime.trim().length > 0 ? cmcGlobal.altLiquidityRegime : null;
16912
+ const cmcTotalMarketCapUsd = toFiniteNumberOrNull(
16913
+ cmcGlobal?.totalMarketCapUsd
16914
+ );
16875
16915
  const cmcFearGreedValueChange7d = toFiniteNumberOrNull(
16876
16916
  cmcFearGreed?.valueChange7d
16877
16917
  );
16878
16918
  const cmcBtcDominanceChange24hPct = toFiniteNumberOrNull(
16879
16919
  cmcGlobal?.btcDominanceChange24hPct
16880
16920
  );
16921
+ const benchmarkOiChangePct24h1h = toFiniteNumberOrNull(
16922
+ baseDerivatives1h?.oiChangePct24h
16923
+ );
16924
+ const btcReferenceTradeFlowNetBaseDelta = toFiniteNumberOrNull(
16925
+ btcReferenceTradeFlow?.netBaseDelta
16926
+ );
16881
16927
  const baseDecisionApproveBias = gateFeaturesDecisionHints?.approveBias === "support" || gateFeaturesDecisionHints?.approveBias === "neutral" || gateFeaturesDecisionHints?.approveBias === "reject" ? gateFeaturesDecisionHints.approveBias : null;
16882
16928
  const marketBreadthAdvanceDeclineRatio = toFiniteNumberOrNull(
16883
16929
  marketBreadth?.advanceDeclineRatio
@@ -16886,6 +16932,7 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16886
16932
  const marketBreadthReturn = toFiniteNumberOrNull(gateFeaturesRelative?.marketBreadthReturn) ?? toFiniteNumberOrNull(marketBreadth?.equalWeightedReturn);
16887
16933
  const shortBreadthShockPocket = signalDirection === "SHORT" && cmcAltLiquidityRegime === "btc_favored" && marketBreadthAdvanceDeclineRatio != null && marketBreadthAdvanceDeclineRatio <= 0 && marketBreadthReturn != null && marketBreadthReturn <= SHORT_BREADTH_SHOCK_MARKET_BREADTH_RETURN_MAX;
16888
16934
  const shortBreadthNeutralPocket = signalDirection === "SHORT" && baseDecisionApproveBias === "neutral" && marketBreadthAdvancers != null && marketBreadthAdvancers <= 0 && marketBreadthReturn != null && marketBreadthReturn <= 0 && isInRange(effortVsResult, 0, SHORT_BREADTH_NEUTRAL_EFFORT_VS_RESULT_MAX);
16935
+ const shortCmcBenchmarkContractionPocket = signalDirection === "SHORT" && cmcTotalMarketCapUsd != null && cmcTotalMarketCapUsd <= SHORT_CMC_TOTAL_MARKET_CAP_USD_MAX && benchmarkOiChangePct24h1h != null && benchmarkOiChangePct24h1h <= SHORT_BENCHMARK_OI_CHANGE_PCT_24H_1H_MAX && btcReferenceTradeFlowNetBaseDelta != null && btcReferenceTradeFlowNetBaseDelta <= SHORT_BTC_REFERENCE_TRADE_FLOW_NET_BASE_DELTA_MAX;
16889
16936
  const q4TargetAlpha1Allowed = targetVsBtcAlpha1h == null || targetVsBtcAlpha1h <= Q4_TARGET_VS_BTC_ALPHA_1H_MAX;
16890
16937
  const q4ContinuationBlockReasons = getQ4ContinuationBlockReasons({
16891
16938
  targetVsBtcAlpha4h,
@@ -16899,6 +16946,12 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16899
16946
  effortVsResult,
16900
16947
  cmcBtcDominanceChange24hPct
16901
16948
  });
16949
+ const approvalRegimeBlockReasons = baseContextAvailable ? getApprovalRegimeBlockReasons({
16950
+ tpDistanceAtr,
16951
+ trendAdx,
16952
+ benchmarkRelativeStrength1d
16953
+ }) : [];
16954
+ const approvalRegimeAllowed = approvalRegimeBlockReasons.length === 0;
16902
16955
  const hardBlockReasons = [];
16903
16956
  if (invalidated) {
16904
16957
  hardBlockReasons.push("invalidated");
@@ -16938,6 +16991,7 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16938
16991
  if (chaseRiskBlocked && !referenceDerivativesRotationPocket) {
16939
16992
  approvalBlockReasons.push("chase_entry_risk");
16940
16993
  }
16994
+ approvalBlockReasons.push(...approvalRegimeBlockReasons);
16941
16995
  if (breakoutRetestQuality != null && breakoutRetestQuality < 0.25) {
16942
16996
  riskAnnotations.push("weak_retest_quality");
16943
16997
  }
@@ -16950,7 +17004,7 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16950
17004
  if (signalDirection === "LONG" && derivativesPressure === "crowded_long" || signalDirection === "SHORT" && derivativesPressure === "crowded_short") {
16951
17005
  riskAnnotations.push("derivatives_pressure_conflict");
16952
17006
  }
16953
- if (signalDirection === "SHORT" && !(shortBreadthShockPocket || shortBreadthNeutralPocket || referenceDerivativesRotationPocket)) {
17007
+ if (signalDirection === "SHORT" && !(shortBreadthShockPocket || shortBreadthNeutralPocket || shortCmcBenchmarkContractionPocket || referenceDerivativesRotationPocket)) {
16954
17008
  approvalBlockReasons.push("short_disabled");
16955
17009
  }
16956
17010
  if (signalDirection === "LONG" && cmcAltLiquidityRegime === "btc_favored") {
@@ -16969,8 +17023,13 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
16969
17023
  oscillatorStrength,
16970
17024
  signalRangeAtrRatio,
16971
17025
  stopDistanceAtr,
17026
+ tpDistanceAtr,
16972
17027
  breakoutBodyAtr,
17028
+ trendAdx,
17029
+ benchmarkRelativeStrength1d,
16973
17030
  chaseRiskBlocked,
17031
+ approvalRegimeAllowed,
17032
+ approvalRegimeBlockReasons,
16974
17033
  kcMidline,
16975
17034
  kcUpper,
16976
17035
  kcLower,
@@ -17007,14 +17066,18 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
17007
17066
  spreadBias,
17008
17067
  spreadSeverity,
17009
17068
  cmcAltLiquidityRegime,
17069
+ cmcTotalMarketCapUsd,
17010
17070
  cmcFearGreedValueChange7d,
17011
17071
  cmcBtcDominanceChange24hPct,
17072
+ benchmarkOiChangePct24h1h,
17073
+ btcReferenceTradeFlowNetBaseDelta,
17012
17074
  baseDecisionApproveBias,
17013
17075
  marketBreadthAdvancers,
17014
17076
  marketBreadthAdvanceDeclineRatio,
17015
17077
  marketBreadthReturn,
17016
17078
  shortBreadthShockPocket,
17017
17079
  shortBreadthNeutralPocket,
17080
+ shortCmcBenchmarkContractionPocket,
17018
17081
  referenceDerivativesRotationPocket,
17019
17082
  referenceXrpOiChangePct4h15m,
17020
17083
  referenceTrxOiChangePct4h15m,
@@ -17042,8 +17105,13 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
17042
17105
  oscillatorStrength,
17043
17106
  signalRangeAtrRatio,
17044
17107
  stopDistanceAtr,
17108
+ tpDistanceAtr,
17045
17109
  breakoutBodyAtr,
17110
+ trendAdx,
17111
+ benchmarkRelativeStrength1d,
17046
17112
  chaseRiskBlocked,
17113
+ approvalRegimeAllowed,
17114
+ approvalRegimeBlockReasons,
17047
17115
  kcMidline,
17048
17116
  kcUpper,
17049
17117
  kcLower,
@@ -17080,14 +17148,18 @@ var buildAdaptiveMomentumRibbonContext = (signal, additionalIndicators) => {
17080
17148
  spreadBias,
17081
17149
  spreadSeverity,
17082
17150
  cmcAltLiquidityRegime,
17151
+ cmcTotalMarketCapUsd,
17083
17152
  cmcFearGreedValueChange7d,
17084
17153
  cmcBtcDominanceChange24hPct,
17154
+ benchmarkOiChangePct24h1h,
17155
+ btcReferenceTradeFlowNetBaseDelta,
17085
17156
  baseDecisionApproveBias,
17086
17157
  marketBreadthAdvancers,
17087
17158
  marketBreadthAdvanceDeclineRatio,
17088
17159
  marketBreadthReturn,
17089
17160
  shortBreadthShockPocket,
17090
17161
  shortBreadthNeutralPocket,
17162
+ shortCmcBenchmarkContractionPocket,
17091
17163
  referenceDerivativesRotationPocket,
17092
17164
  referenceXrpOiChangePct4h15m,
17093
17165
  referenceTrxOiChangePct4h15m,
@@ -17190,8 +17262,13 @@ Additional AdaptiveMomentumRibbon context:
17190
17262
  - oscillatorStrength=${context.oscillatorStrength?.toFixed?.(3) ?? "n/a"}
17191
17263
  - signalRangeAtrRatio=${context.signalRangeAtrRatio?.toFixed?.(3) ?? "n/a"}
17192
17264
  - stopDistanceAtr=${context.stopDistanceAtr?.toFixed?.(3) ?? "n/a"}
17265
+ - tpDistanceAtr=${context.tpDistanceAtr?.toFixed?.(3) ?? "n/a"}
17193
17266
  - breakoutBodyAtr=${context.breakoutBodyAtr?.toFixed?.(3) ?? "n/a"}
17267
+ - trendAdx=${context.trendAdx?.toFixed?.(3) ?? "n/a"}
17268
+ - benchmarkRelativeStrength1d=${context.benchmarkRelativeStrength1d?.toFixed?.(3) ?? "n/a"}
17194
17269
  - chaseRiskBlocked=${context.chaseRiskBlocked}
17270
+ - approvalRegimeAllowed=${context.approvalRegimeAllowed}
17271
+ - approvalRegimeBlockReasons=${context.approvalRegimeBlockReasons.join(", ") || "none"}
17195
17272
  - channelState=${context.channelState}
17196
17273
  - channelBiasAligned=${context.channelBiasAligned}
17197
17274
  - channelExtensionPct=${context.channelExtensionPct?.toFixed?.(3) ?? "n/a"}%
@@ -17221,14 +17298,18 @@ Additional AdaptiveMomentumRibbon context:
17221
17298
  - spreadBias=${context.spreadBias ?? "n/a"}
17222
17299
  - spreadSeverity=${context.spreadSeverity ?? "n/a"}
17223
17300
  - cmcAltLiquidityRegime=${context.cmcAltLiquidityRegime ?? "n/a"}
17301
+ - cmcTotalMarketCapUsd=${context.cmcTotalMarketCapUsd?.toFixed?.(0) ?? "n/a"}
17224
17302
  - cmcFearGreedValueChange7d=${context.cmcFearGreedValueChange7d?.toFixed?.(3) ?? "n/a"}
17225
17303
  - cmcBtcDominanceChange24hPct=${context.cmcBtcDominanceChange24hPct?.toFixed?.(3) ?? "n/a"}
17304
+ - benchmarkOiChangePct24h1h=${context.benchmarkOiChangePct24h1h?.toFixed?.(3) ?? "n/a"}
17305
+ - btcReferenceTradeFlowNetBaseDelta=${context.btcReferenceTradeFlowNetBaseDelta?.toFixed?.(3) ?? "n/a"}
17226
17306
  - baseDecisionApproveBias=${context.baseDecisionApproveBias ?? "n/a"}
17227
17307
  - marketBreadthAdvancers=${context.marketBreadthAdvancers?.toFixed?.(0) ?? "n/a"}
17228
17308
  - marketBreadthAdvanceDeclineRatio=${context.marketBreadthAdvanceDeclineRatio?.toFixed?.(3) ?? "n/a"}
17229
17309
  - marketBreadthReturn=${context.marketBreadthReturn?.toFixed?.(5) ?? "n/a"}
17230
17310
  - shortBreadthShockPocket=${context.shortBreadthShockPocket}
17231
17311
  - shortBreadthNeutralPocket=${context.shortBreadthNeutralPocket}
17312
+ - shortCmcBenchmarkContractionPocket=${context.shortCmcBenchmarkContractionPocket}
17232
17313
  - referenceDerivativesRotationPocket=${context.referenceDerivativesRotationPocket}
17233
17314
  - referenceXrpOiChangePct4h15m=${context.referenceXrpOiChangePct4h15m?.toFixed?.(3) ?? "n/a"}
17234
17315
  - referenceTrxOiChangePct4h15m=${context.referenceTrxOiChangePct4h15m?.toFixed?.(3) ?? "n/a"}
@@ -17292,12 +17373,13 @@ var MIN_APPROVAL_CHANNEL_WIDTH_PCT = 2;
17292
17373
  var MIN_HIGH_CONFIDENCE_CHANNEL_WIDTH_PCT = 2;
17293
17374
  var MIN_APPROVAL_VOLUME_REL20 = 10;
17294
17375
  var MIN_SHORT_APPROVAL_VOLUME_REL20 = 7;
17295
- var MAX_SHORT_RECOVERY_TARGET_LIQ_IMBALANCE_1H = -0.97;
17296
- var MIN_SHORT_RECOVERY_TARGET_LIQ_SPIKE_RATIO_1H = 5.7;
17297
- var MAX_SHORT_RECOVERY_ETH_FUNDING_RATE_1H = 37e-4;
17376
+ var MAX_REFERENCE_SHORT_RECOVERY_ETH_LIQ_IMBALANCE_1H = -0.99;
17298
17377
  var MAX_XRP_SHORT_RECOVERY_BTC_VS_ALT_RETURN_24H = -0.03;
17299
17378
  var MAX_XRP_SHORT_RECOVERY_FUNDING_Z_SCORE_1H = -1.8;
17300
17379
  var MIN_XRP_OI_REJECT_BIAS_BLOCK_15M = 25e7;
17380
+ var MAX_XRP_OI_RECOVERY_BTC_DOMINANCE_PCT = 58.45;
17381
+ var MIN_XRP_OI_RECOVERY_MARKET_BREADTH_SYMBOLS = 27;
17382
+ var MIN_XRP_OI_RECOVERY_BNB_FUNDING_CHANGE_1H = 0;
17301
17383
  var MAX_APPROVAL_RSI = 75;
17302
17384
  var MIN_APPROVAL_BB_WIDTH_RANK_100 = 50;
17303
17385
  var buildAdaptiveTrendChannelGuardrailContext = ({
@@ -17306,6 +17388,7 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17306
17388
  }) => {
17307
17389
  const targetDerivatives1h = baseContext?.derivatives?.intervals?.["1h"];
17308
17390
  const ethDerivatives1h = baseContext?.derivatives?.referenceContexts?.["ETHUSDT"]?.intervals?.["1h"];
17391
+ const bnbDerivativesSummary = baseContext?.derivatives?.referenceContexts?.["BNBUSDT"]?.summary;
17309
17392
  const xrpDerivatives15m = baseContext?.derivatives?.referenceContexts?.["XRPUSDT"]?.intervals?.["15m"];
17310
17393
  const xrpDerivatives1h = baseContext?.derivatives?.referenceContexts?.["XRPUSDT"]?.intervals?.["1h"];
17311
17394
  const targetDerivatives1hStale = targetDerivatives1h?.stale === true;
@@ -17323,10 +17406,17 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17323
17406
  baseContext?.regime?.volatility?.percentiles?.bbWidthRank100
17324
17407
  );
17325
17408
  const trendFollowState = baseContext?.regime?.trend?.trendFollow?.state ?? null;
17409
+ const volatilityState = baseContext?.regime?.volatility?.state ?? null;
17326
17410
  const h4VolatilityState = baseContext?.mtf?.summary?.h4VolatilityState ?? null;
17327
17411
  const benchmarkTrendAlignment = baseContext?.relative?.benchmark?.trendAlignment ?? null;
17328
17412
  const cmcExchangeLiquidityAligned = typeof baseContext?.gateFeatures?.relative?.cmcExchangeLiquidityAligned === "boolean" ? baseContext.gateFeatures.relative.cmcExchangeLiquidityAligned : null;
17329
17413
  const cmcExchangeLiquidityStale = typeof baseContext?.gateFeatures?.relative?.cmcExchangeLiquidityStale === "boolean" ? baseContext.gateFeatures.relative.cmcExchangeLiquidityStale : null;
17414
+ const cmcBtcDominancePct = asFiniteNumber(
17415
+ baseContext?.relative?.cmcGlobal?.btcDominancePct
17416
+ );
17417
+ const marketBreadthSymbolsCount = asFiniteNumber(
17418
+ baseContext?.relative?.marketBreadth?.symbolsCount
17419
+ );
17330
17420
  const baseApproveBias = baseContext?.gateFeatures?.decisionHints?.approveBias ?? null;
17331
17421
  const targetLiqImbalance1h = asFiniteNumber(
17332
17422
  targetDerivatives1h?.liqImbalance
@@ -17335,7 +17425,11 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17335
17425
  targetDerivatives1h?.liqSpikeRatio
17336
17426
  );
17337
17427
  const targetLiqTotal1h = asFiniteNumber(targetDerivatives1h?.liqTotal);
17428
+ const ethLiqImbalance1h = asFiniteNumber(ethDerivatives1h?.liqImbalance);
17338
17429
  const ethFundingRate1h = asFiniteNumber(ethDerivatives1h?.fundingRate);
17430
+ const bnbFundingChange1h = asFiniteNumber(
17431
+ bnbDerivativesSummary?.fundingChange1h
17432
+ );
17339
17433
  const xrpOpenInterest15m = asFiniteNumber(xrpDerivatives15m?.openInterest);
17340
17434
  const xrpPriceOiDivergenceType = baseContext?.derivatives?.referenceContexts?.["XRPUSDT"]?.summary?.priceOiDivergenceType ?? null;
17341
17435
  const xrpFundingZScore1h = asFiniteNumber(xrpDerivatives1h?.fundingZScore);
@@ -17370,12 +17464,14 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17370
17464
  const cmcExchangeLiquiditySupportsApproval = direction === "LONG" && cmcExchangeLiquidityAligned === true && cmcExchangeLiquidityStale !== true;
17371
17465
  const trendFollowSupportsApproval = direction === "LONG" && trendFollowState === "bull";
17372
17466
  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;
17373
- 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;
17374
- 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;
17375
- if (xrpOpenInterest15m != null && xrpOpenInterest15m >= MIN_XRP_OI_REJECT_BIAS_BLOCK_15M && baseApproveBias === "reject" && !xrpShortRecoverySetup) {
17467
+ const xrpBtcShortRecoverySetup = direction === "SHORT" && xrpDerivatives1hStale !== true && xrpPriceOiDivergenceType === "price_down_oi_up" && btcVsAltReturn24h != null && btcVsAltReturn24h <= MAX_XRP_SHORT_RECOVERY_BTC_VS_ALT_RETURN_24H && xrpFundingZScore1h != null && xrpFundingZScore1h <= MAX_XRP_SHORT_RECOVERY_FUNDING_Z_SCORE_1H;
17468
+ const xrpEthShortRecoverySetup = direction === "SHORT" && xrpDerivatives1hStale !== true && ethDerivatives1hStale !== true && xrpPriceOiDivergenceType === "price_down_oi_up" && xrpFundingZScore1h != null && xrpFundingZScore1h <= MAX_XRP_SHORT_RECOVERY_FUNDING_Z_SCORE_1H && ethLiqImbalance1h != null && ethLiqImbalance1h <= MAX_REFERENCE_SHORT_RECOVERY_ETH_LIQ_IMBALANCE_1H;
17469
+ const xrpShortRecoverySetup = xrpBtcShortRecoverySetup || xrpEthShortRecoverySetup;
17470
+ const xrpOiReferenceRecoverySetup = xrpOpenInterest15m != null && xrpOpenInterest15m >= MIN_XRP_OI_REJECT_BIAS_BLOCK_15M && baseApproveBias === "reject" && volatilityState === "expanded" && cmcBtcDominancePct != null && cmcBtcDominancePct <= MAX_XRP_OI_RECOVERY_BTC_DOMINANCE_PCT && marketBreadthSymbolsCount != null && marketBreadthSymbolsCount >= MIN_XRP_OI_RECOVERY_MARKET_BREADTH_SYMBOLS && bnbFundingChange1h != null && bnbFundingChange1h >= MIN_XRP_OI_RECOVERY_BNB_FUNDING_CHANGE_1H;
17471
+ if (xrpOpenInterest15m != null && xrpOpenInterest15m >= MIN_XRP_OI_REJECT_BIAS_BLOCK_15M && baseApproveBias === "reject" && !xrpShortRecoverySetup && !xrpOiReferenceRecoverySetup) {
17376
17472
  hardBlockReasons.push("xrp_oi_reject_bias");
17377
17473
  }
17378
- const approvalSetup = longApprovalSetup || shortRecoverySetup || xrpShortRecoverySetup;
17474
+ const approvalSetup = longApprovalSetup || xrpShortRecoverySetup || xrpOiReferenceRecoverySetup;
17379
17475
  const highConfidenceSetup = longApprovalSetup && breakoutDistancePct >= MIN_HIGH_CONFIDENCE_BREAKOUT_DISTANCE_PCT && channelWidthPct >= MIN_HIGH_CONFIDENCE_CHANNEL_WIDTH_PCT;
17380
17476
  let deterministicQuality = 3;
17381
17477
  if (hardBlockReasons.length > 0) {
@@ -17433,14 +17529,19 @@ var buildAdaptiveTrendChannelGuardrailContext = ({
17433
17529
  rsi,
17434
17530
  bbWidthRank100,
17435
17531
  trendFollowState,
17532
+ volatilityState,
17436
17533
  h4VolatilityState,
17437
17534
  benchmarkTrendAlignment,
17438
17535
  cmcExchangeLiquidityAligned,
17439
17536
  cmcExchangeLiquidityStale,
17537
+ cmcBtcDominancePct,
17538
+ marketBreadthSymbolsCount,
17440
17539
  targetLiqImbalance1h,
17441
17540
  targetLiqSpikeRatio1h,
17442
17541
  targetLiqTotal1h,
17542
+ ethLiqImbalance1h,
17443
17543
  ethFundingRate1h,
17544
+ bnbFundingChange1h,
17444
17545
  xrpOpenInterest15m,
17445
17546
  xrpPriceOiDivergenceType,
17446
17547
  xrpFundingZScore1h,
@@ -17516,12 +17617,17 @@ Additional AdaptiveTrendChannel context:
17516
17617
  - rsi=${String(context.rsi ?? "n/a")}
17517
17618
  - bbWidthRank100=${String(context.bbWidthRank100 ?? "n/a")}
17518
17619
  - trendFollowState=${context.trendFollowState ?? "n/a"}
17620
+ - volatilityState=${context.volatilityState ?? "n/a"}
17519
17621
  - h4VolatilityState=${context.h4VolatilityState ?? "n/a"}
17520
17622
  - benchmarkTrendAlignment=${context.benchmarkTrendAlignment ?? "n/a"}
17623
+ - cmcBtcDominancePct=${String(context.cmcBtcDominancePct ?? "n/a")}
17624
+ - marketBreadthSymbolsCount=${String(context.marketBreadthSymbolsCount ?? "n/a")}
17521
17625
  - targetLiqImbalance1h=${String(context.targetLiqImbalance1h ?? "n/a")}
17522
17626
  - targetLiqSpikeRatio1h=${String(context.targetLiqSpikeRatio1h ?? "n/a")}
17523
17627
  - targetLiqTotal1h=${String(context.targetLiqTotal1h ?? "n/a")}
17628
+ - ethLiqImbalance1h=${String(context.ethLiqImbalance1h ?? "n/a")}
17524
17629
  - ethFundingRate1h=${String(context.ethFundingRate1h ?? "n/a")}
17630
+ - bnbFundingChange1h=${String(context.bnbFundingChange1h ?? "n/a")}
17525
17631
  - xrpOpenInterest15m=${String(context.xrpOpenInterest15m ?? "n/a")}
17526
17632
  - xrpPriceOiDivergenceType=${context.xrpPriceOiDivergenceType ?? "n/a"}
17527
17633
  - xrpFundingZScore1h=${String(context.xrpFundingZScore1h ?? "n/a")}
@@ -17539,7 +17645,7 @@ Interpretation rules for AdaptiveTrendChannel:
17539
17645
  - The centerline is the adaptive rail; floor/roof are volatility-scaled invalidation bands.
17540
17646
  - Prefer flips with reasonable distance from the centerline and confirmation from shared market context.
17541
17647
  - Thin participation, missing shared-context confirmation, or missing liquidation-shock recovery evidence should downgrade the setup.
17542
- - A high-XRP-OI reject bias should remain blocked unless a narrow XRP reference SHORT recovery setup is present.
17648
+ - A high-XRP-OI reject bias should remain blocked unless a narrow XRP reference SHORT recovery setup or expanded CMC/BNB/breadth recovery setup is present.
17543
17649
  - Treat deterministicQuality and approvalAllowedNow as the local normalized gate result.
17544
17650
  `.trim();
17545
17651
  },
@@ -17756,6 +17862,7 @@ var buildEntryStopTargetFigures = ({
17756
17862
  var MFR_CALIBRATED_LONG_TARGET_VS_BTC_RATIO_RETURN_24H_MAX = -3.3;
17757
17863
  var MFR_CALIBRATED_LONG_ETH_VS_BTC_VOLUME_RATIO_MIN = 0.54;
17758
17864
  var MFR_CALIBRATED_LONG_H1_RANGE_POSITION_MAX = 0.08;
17865
+ var MFR_AI_LONG_STOP_DISTANCE_ATR_MIN = 24;
17759
17866
  var getMarketFlushReversalLongReboundPocketFeatures = (baseContext) => ({
17760
17867
  targetVsBtcRatioReturn24h: toFiniteNumberOrNull2(
17761
17868
  baseContext?.relative?.targetVsBtc?.ratioReturn24h
@@ -17773,6 +17880,21 @@ var isMarketFlushReversalCalibratedLongReboundPocket = ({
17773
17880
  ethVsBtcVolumeRatio,
17774
17881
  h1RangePosition
17775
17882
  }) => direction === "LONG" && targetVsBtcRatioReturn24h != null && targetVsBtcRatioReturn24h <= MFR_CALIBRATED_LONG_TARGET_VS_BTC_RATIO_RETURN_24H_MAX && (ethVsBtcVolumeRatio != null && ethVsBtcVolumeRatio >= MFR_CALIBRATED_LONG_ETH_VS_BTC_VOLUME_RATIO_MIN || h1RangePosition != null && h1RangePosition <= MFR_CALIBRATED_LONG_H1_RANGE_POSITION_MAX);
17883
+ var getMarketFlushReversalAiLongPocketFeatures = (baseContext) => ({
17884
+ stopDistanceAtr: toFiniteNumberOrNull2(
17885
+ baseContext?.gateFeatures?.setup?.stopDistanceAtr
17886
+ ),
17887
+ cmcIndexRegime: baseContext?.relative?.cmcIndexes?.indexRegime ?? null,
17888
+ cmcIndexStale: typeof baseContext?.relative?.cmcIndexes?.stale === "boolean" ? baseContext.relative.cmcIndexes.stale : null,
17889
+ rsiState: baseContext?.regime?.momentum?.rsiState ?? null
17890
+ });
17891
+ var isMarketFlushReversalValidatedAiLongPocket = ({
17892
+ direction,
17893
+ stopDistanceAtr,
17894
+ cmcIndexRegime,
17895
+ cmcIndexStale,
17896
+ rsiState
17897
+ }) => direction === "LONG" && stopDistanceAtr != null && stopDistanceAtr >= MFR_AI_LONG_STOP_DISTANCE_ATR_MIN && cmcIndexRegime === "risk_off" && cmcIndexStale === false && rsiState === "oversold";
17776
17898
 
17777
17899
  // src/MarketFlushReversal/guardrails.ts
17778
17900
  var toFiniteNumberOrNull3 = (value) => {
@@ -17862,6 +17984,12 @@ var buildMarketFlushReversalGuardrailContext = ({
17862
17984
  direction
17863
17985
  });
17864
17986
  const { targetVsBtcRatioReturn24h, ethVsBtcVolumeRatio, h1RangePosition } = longReboundPocketFeatures;
17987
+ const aiLongPocketFeatures = getMarketFlushReversalAiLongPocketFeatures(baseContext);
17988
+ const validatedAiLongPocket = isMarketFlushReversalValidatedAiLongPocket({
17989
+ ...aiLongPocketFeatures,
17990
+ direction
17991
+ });
17992
+ const { stopDistanceAtr, cmcIndexRegime, cmcIndexStale, rsiState } = aiLongPocketFeatures;
17865
17993
  const approvalBlockReasons = [];
17866
17994
  const riskAnnotations = [];
17867
17995
  if (direction == null) approvalBlockReasons.push("missing_direction");
@@ -17872,22 +18000,22 @@ var buildMarketFlushReversalGuardrailContext = ({
17872
18000
  approvalBlockReasons.push("local_participation_not_confirmed");
17873
18001
  }
17874
18002
  if (!marketContextAvailable) {
17875
- approvalBlockReasons.push("missing_broad_market_derivatives");
18003
+ riskAnnotations.push("missing_broad_market_derivatives");
17876
18004
  }
17877
18005
  if (marketRiskFlags.includes("stale_derivatives")) {
17878
- approvalBlockReasons.push("stale_broad_market_derivatives");
18006
+ riskAnnotations.push("stale_broad_market_derivatives");
17879
18007
  }
17880
18008
  if (marketContextAvailable && broadMarketFlushDirection == null) {
17881
- approvalBlockReasons.push("no_broad_market_flush");
18009
+ riskAnnotations.push("no_broad_market_flush");
17882
18010
  }
17883
18011
  if (direction != null && broadMarketFlushDirection != null && broadMarketFlushDirection !== direction) {
17884
- approvalBlockReasons.push("broad_market_flush_direction_mismatch");
18012
+ riskAnnotations.push("broad_market_flush_direction_mismatch");
17885
18013
  }
17886
18014
  if (direction === "SHORT") {
17887
18015
  approvalBlockReasons.push("short_flush_rebound_pocket_not_validated");
17888
18016
  }
17889
- if (direction === "LONG" && !calibratedLongRebound) {
17890
- approvalBlockReasons.push("calibrated_long_rebound_missing");
18017
+ if (direction === "LONG" && !validatedAiLongPocket) {
18018
+ approvalBlockReasons.push("validated_long_ai_pocket_missing");
17891
18019
  }
17892
18020
  if (signalContext.marketFlushConfirmed !== true) {
17893
18021
  riskAnnotations.push("market_flush_not_available_at_core_time");
@@ -17911,7 +18039,12 @@ var buildMarketFlushReversalGuardrailContext = ({
17911
18039
  targetVsBtcRatioReturn24h,
17912
18040
  ethVsBtcVolumeRatio,
17913
18041
  h1RangePosition,
17914
- calibratedLongRebound
18042
+ calibratedLongRebound,
18043
+ stopDistanceAtr,
18044
+ cmcIndexRegime,
18045
+ cmcIndexStale,
18046
+ rsiState,
18047
+ validatedAiLongPocket
17915
18048
  };
17916
18049
  return {
17917
18050
  ...signalContext,
@@ -18010,6 +18143,11 @@ Additional Market Flush Reversal context:
18010
18143
  - ethVsBtcVolumeRatio=${String(context.marketFlushReversalGateFeatures.ethVsBtcVolumeRatio ?? "n/a")}
18011
18144
  - h1RangePosition=${String(context.marketFlushReversalGateFeatures.h1RangePosition ?? "n/a")}
18012
18145
  - calibratedLongRebound=${String(context.marketFlushReversalGateFeatures.calibratedLongRebound)}
18146
+ - stopDistanceAtr=${String(context.marketFlushReversalGateFeatures.stopDistanceAtr ?? "n/a")}
18147
+ - cmcIndexRegime=${context.marketFlushReversalGateFeatures.cmcIndexRegime ?? "n/a"}
18148
+ - cmcIndexStale=${String(context.marketFlushReversalGateFeatures.cmcIndexStale ?? "n/a")}
18149
+ - rsiState=${context.marketFlushReversalGateFeatures.rsiState ?? "n/a"}
18150
+ - validatedAiLongPocket=${String(context.marketFlushReversalGateFeatures.validatedAiLongPocket)}
18013
18151
  - approvalAllowedNow=${String(context.approvalAllowedNow)}
18014
18152
  - deterministicQuality=${String(context.deterministicQuality)}
18015
18153
  - approvalBlockReasons=${context.approvalBlockReasons.join(",") || "none"}
@@ -18122,6 +18260,7 @@ var buildDoubleTapGateFeatures = ({
18122
18260
  defaultApprovalAllowed,
18123
18261
  q4AltDispersionOk,
18124
18262
  q4DerivativesCmcRiskOk,
18263
+ q4DerivativesDirectionSessionOk,
18125
18264
  strictMomentumApproved,
18126
18265
  strictMomentumRoc1dOk
18127
18266
  }) => {
@@ -18144,6 +18283,7 @@ var buildDoubleTapGateFeatures = ({
18144
18283
  q4AltDispersionOk,
18145
18284
  q4DerivativesPocket,
18146
18285
  q4DerivativesCmcRiskOk,
18286
+ q4DerivativesDirectionSessionOk,
18147
18287
  strictMomentumApproved,
18148
18288
  strictMomentumRoc1dOk
18149
18289
  };
@@ -18322,7 +18462,8 @@ var buildDoubleTapAiContext = (payload) => {
18322
18462
  const q4CmcApproval = legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && baseIndicatorCandidate && cmcBtcDominanceChange24hPct != null && cmcBtcDominanceChange24hPct > Q4_CMC_BTC_DOMINANCE_CHANGE_MIN && cmcBtcDominanceChange24hPct <= Q4_CMC_BTC_DOMINANCE_CHANGE_MAX && altDispersion24h != null && altDispersion24h < Q4_ALT_DISPERSION_24H_MAX;
18323
18463
  const q4DerivativesBadCmcPocket = btcVsAltReturn24h != null && cmc20ToCmc100RatioChange24hPct != null && btcVsAltReturn24h <= Q4_DERIVATIVES_BAD_BTC_VS_ALT_RETURN_24H_MAX && cmc20ToCmc100RatioChange24hPct <= Q4_DERIVATIVES_BAD_CMC20_TO_CMC100_CHANGE_24H_MAX;
18324
18464
  const q4DerivativesPocket = baseContextAvailable && btcVsAltReturn24h != null && ethCrowdingPersistenceBars != null && solFundingZScore15m != null && btcVsAltReturn24h <= Q4_DERIVATIVES_BTC_VS_ALT_RETURN_24H_MAX && ethCrowdingPersistenceBars >= Q4_DERIVATIVES_ETH_CROWDING_PERSISTENCE_MIN && solFundingZScore15m <= Q4_DERIVATIVES_SOL_FUNDING_Z_SCORE_15M_MAX;
18325
- const q4DerivativesApproval = q4DerivativesPocket && !q4DerivativesBadCmcPocket;
18465
+ const q4DerivativesDirectionSessionOk = q4DerivativesPocket ? signalDirection === "LONG" ? primarySession === "europe" : signalDirection === "SHORT" ? true : false : null;
18466
+ const q4DerivativesApproval = q4DerivativesPocket && q4DerivativesDirectionSessionOk === true && !q4DerivativesBadCmcPocket;
18326
18467
  const softBlockReasons = [
18327
18468
  ...legacyShapeCandidate && sessionWindowPhase !== "active" ? ["inactive_session_window"] : [],
18328
18469
  ...legacyShapeCandidate && (executionScore == null || executionScore < MIN_EXECUTION_SCORE_FOR_AI_GATE) ? ["low_or_missing_execution_score"] : [],
@@ -18334,12 +18475,15 @@ var buildDoubleTapAiContext = (payload) => {
18334
18475
  ...legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && cmcBtcDominanceChange24hPct == null ? ["missing_cmc_btc_dominance_change"] : [],
18335
18476
  ...legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && cmcBtcDominanceChange24hPct != null && (cmcBtcDominanceChange24hPct <= Q4_CMC_BTC_DOMINANCE_CHANGE_MIN || cmcBtcDominanceChange24hPct > Q4_CMC_BTC_DOMINANCE_CHANGE_MAX) ? ["cmc_btc_dominance_change_outside_band"] : [],
18336
18477
  ...legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && cmcBtcDominanceChange24hPct != null && cmcBtcDominanceChange24hPct > Q4_CMC_BTC_DOMINANCE_CHANGE_MIN && cmcBtcDominanceChange24hPct <= Q4_CMC_BTC_DOMINANCE_CHANGE_MAX && altDispersion24h == null ? ["missing_alt_dispersion_24h_for_q4"] : [],
18337
- ...legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && altDispersion24h != null && altDispersion24h >= Q4_ALT_DISPERSION_24H_MAX ? ["alt_dispersion_24h_too_high_for_q4"] : []
18478
+ ...legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && altDispersion24h != null && altDispersion24h >= Q4_ALT_DISPERSION_24H_MAX ? ["alt_dispersion_24h_too_high_for_q4"] : [],
18479
+ ...q4CmcApproval ? ["legacy_q4_structural_observation_only"] : [],
18480
+ ...q4DerivativesPocket && signalDirection === "LONG" && q4DerivativesDirectionSessionOk === false ? ["long_q4_derivatives_outside_europe_session"] : [],
18481
+ ...q4DerivativesPocket && signalDirection == null ? ["missing_signal_direction_for_q4_derivatives"] : []
18338
18482
  ];
18339
18483
  const highPrecisionApprovalBlocked = legacyHighPrecisionShapeCandidate && !highPrecisionCmcApproval && !q4DerivativesApproval;
18340
- const q4DerivativesApprovalBlocked = q4DerivativesPocket && !q4DerivativesApproval && !highPrecisionCmcApproval && !q4CmcApproval;
18341
- const q4ApprovalBlocked = legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && !q4CmcApproval && !q4DerivativesApproval;
18342
- const approvalSourceAllowed = highPrecisionCmcApproval || q4CmcApproval || q4DerivativesApproval;
18484
+ const q4DerivativesApprovalBlocked = q4DerivativesPocket && !q4DerivativesApproval && !highPrecisionCmcApproval;
18485
+ const q4ApprovalBlocked = legacyShapeCandidate && !legacyHighPrecisionShapeCandidate && !q4DerivativesApproval;
18486
+ const approvalSourceAllowed = highPrecisionCmcApproval || q4DerivativesApproval;
18343
18487
  const approvalBlocked = !approvalSourceAllowed && (highPrecisionApprovalBlocked || q4ApprovalBlocked || q4DerivativesApprovalBlocked);
18344
18488
  const defaultApprovalAllowed = structuralHardBlockReasons.length === 0 && approvalSourceAllowed && !approvalBlocked;
18345
18489
  const strictMomentumRoc1dOk = roc1d == null ? null : roc1d >= STRICT_MOMENTUM_ROC1D_MIN;
@@ -18370,10 +18514,11 @@ var buildDoubleTapAiContext = (payload) => {
18370
18514
  defaultApprovalAllowed,
18371
18515
  q4AltDispersionOk: altDispersion24h == null ? null : altDispersion24h < Q4_ALT_DISPERSION_24H_MAX,
18372
18516
  q4DerivativesCmcRiskOk: btcVsAltReturn24h == null || cmc20ToCmc100RatioChange24hPct == null ? null : !q4DerivativesBadCmcPocket,
18517
+ q4DerivativesDirectionSessionOk,
18373
18518
  strictMomentumApproved: strictMomentumApprovalAllowedNow,
18374
18519
  strictMomentumRoc1dOk
18375
18520
  });
18376
- const deterministicQuality = structuralHardBlockReasons.length > 0 ? Math.min(geometryQuality, 2) : highPrecisionCmcApproval ? 5 : q4CmcApproval || q4DerivativesApproval ? 4 : Math.min(geometryQuality, 3);
18521
+ const deterministicQuality = structuralHardBlockReasons.length > 0 ? Math.min(geometryQuality, 2) : highPrecisionCmcApproval ? 5 : q4DerivativesApproval ? 4 : Math.min(geometryQuality, 3);
18377
18522
  return {
18378
18523
  ...context,
18379
18524
  baseContextAvailable,
@@ -18403,6 +18548,7 @@ var buildDoubleTapAiContext = (payload) => {
18403
18548
  ethCrowdingPersistenceBars,
18404
18549
  solFundingZScore15m,
18405
18550
  altDispersion24h,
18551
+ q4DerivativesDirectionSessionOk,
18406
18552
  doubleTapGateFeatures,
18407
18553
  structuralHardBlockReasons,
18408
18554
  softBlockReasons,
@@ -18507,6 +18653,7 @@ Additional DoubleTap context:
18507
18653
  - doubleTapGateQ4AltDispersionOk=${String(context.doubleTapGateFeatures.q4AltDispersionOk ?? "n/a")}
18508
18654
  - doubleTapGateQ4DerivativesPocket=${String(context.doubleTapGateFeatures.q4DerivativesPocket)}
18509
18655
  - doubleTapGateQ4DerivativesCmcRiskOk=${String(context.doubleTapGateFeatures.q4DerivativesCmcRiskOk ?? "n/a")}
18656
+ - doubleTapGateQ4DerivativesDirectionSessionOk=${String(context.doubleTapGateFeatures.q4DerivativesDirectionSessionOk ?? "n/a")}
18510
18657
  - doubleTapGateStrictMomentumApproved=${String(context.doubleTapGateFeatures.strictMomentumApproved)}
18511
18658
  - doubleTapGateStrictMomentumRoc1dOk=${String(context.doubleTapGateFeatures.strictMomentumRoc1dOk ?? "n/a")}
18512
18659
  - deterministicQuality=${String(context.deterministicQuality)}
@@ -18523,9 +18670,9 @@ Interpretation rules for DoubleTap:
18523
18670
  - Extremely tiny breaks can still be early noise; live approval needs support from baseContext.
18524
18671
  - Treat deterministicQuality and approvalAllowedNow as the normalized local gate result.
18525
18672
  - Local q5 approval needs the high-precision pocket plus active session window, execution score >= 35, lowTouchCount20 >= 1, aligned volume structure, no benchmark conflict, and CMC alt volume change <= 0.5.
18526
- - 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.
18527
- - 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.
18528
- - 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.
18673
+ - The legacy structural q4 CMC pocket is retained only as observation context and should not be treated as local approval.
18674
+ - Local q4 approval comes from the derivatives reference pocket: BTC underperforms alts by at least 0.9%, ETH crowding persistence >= 140, SOL 15m funding z-score <= 0.2, unless BTC underperforms alts by at least 1.4% while CMC20/CMC100 ratio change <= -0.0007; LONG q4 derivatives approval additionally requires the Europe session, while SHORT q4 derivatives approval has no session-side restriction.
18675
+ - Main local approval additionally needs strict momentum confirmation with ROC1D >= -5.25 for q5 approval; the derivatives reference q4 pocket is already momentum/positioning filtered and does not require that ROC gate.
18529
18676
  - A good long has two comparable lows and a clean close above the neckline.
18530
18677
  - A good short has two comparable highs and a clean close below the neckline.
18531
18678
  - Venue spread, trend bias, body strength, and reward-to-volatility are diagnostics for this gate, not strict local blockers.
@@ -18595,6 +18742,7 @@ var asFiniteNumber2 = (value) => {
18595
18742
  const parsed = Number(value);
18596
18743
  return Number.isFinite(parsed) ? parsed : null;
18597
18744
  };
18745
+ var asNullableFiniteNumber = (value) => value == null ? null : asFiniteNumber2(value);
18598
18746
  var asStringArray2 = (value) => Array.isArray(value) ? value.filter(
18599
18747
  (entry) => typeof entry === "string" && entry.trim().length > 0
18600
18748
  ) : [];
@@ -18603,8 +18751,12 @@ var MIN_Q3_UPGRADE_REACTION_CLOSE_DISTANCE_PCT = 1.5;
18603
18751
  var MIN_Q3_UPGRADE_BODY_STRENGTH = 0.65;
18604
18752
  var MIN_Q3_UPGRADE_VOLUME_REL20 = 1;
18605
18753
  var MAX_APPROVAL_CMC_FEAR_GREED_VALUE = 39;
18754
+ var MAX_APPROVAL_PRICE_DISTANCE_TO_MA_SLOW_ATR = 1.2;
18755
+ var MIN_APPROVAL_ACTIVE_LIQUIDITY_ZONES = 1;
18606
18756
  var MAX_DERIVATIVES_RISK_OFF_ALT_BASKET_RETURN_24H = -0.035;
18607
18757
  var MAX_DERIVATIVES_RISK_OFF_TRX_OI_CHANGE_PCT_4H = -1.8;
18758
+ var MIN_BENCHMARK_FLOW_BUY_PRESSURE_PCT = 0.61;
18759
+ var MIN_BENCHMARK_OI_ACCELERATION = 0.55;
18608
18760
  var Q4_APPROVAL_ATR_RANK_BUCKETS = /* @__PURE__ */ new Set(["high", "extreme"]);
18609
18761
  var buildLiquidityTailsGateFeatures = ({
18610
18762
  signalContext,
@@ -18666,6 +18818,12 @@ var buildLiquidityTailsGuardrailContext = ({
18666
18818
  const roc1h = asFiniteNumber2(baseContext?.regime?.momentum?.roc1h);
18667
18819
  const roc4h = asFiniteNumber2(baseContext?.regime?.momentum?.roc4h);
18668
18820
  const benchmarkTrendAlignment = baseContext?.relative?.benchmark?.trendAlignment ?? null;
18821
+ const priceDistanceToMaSlowAtr = asNullableFiniteNumber(
18822
+ baseContext?.regime?.trend?.priceDistanceToMaSlowAtr
18823
+ );
18824
+ const liquidityZonesActiveCount = asNullableFiniteNumber(
18825
+ baseContext?.structure?.liquidityZones?.activeCount
18826
+ );
18669
18827
  const atrPctRankBucket = typeof baseContext?.gateFeatures?.volatility?.atrPctRankBucket === "string" ? baseContext.gateFeatures.volatility.atrPctRankBucket : null;
18670
18828
  const q4AtrRankEligible = atrPctRankBucket != null && Q4_APPROVAL_ATR_RANK_BUCKETS.has(atrPctRankBucket);
18671
18829
  const liquidityRisk = typeof baseContext?.gateFeatures?.risk?.liquidityRisk === "string" ? baseContext.gateFeatures.risk.liquidityRisk : null;
@@ -18703,10 +18861,17 @@ var buildLiquidityTailsGuardrailContext = ({
18703
18861
  const flushSupport = direction === "LONG" ? derivativesRiskFlags.includes("short_liquidation_spike") || derivativesPressure === "short_flush" : direction === "SHORT" ? derivativesRiskFlags.includes("long_liquidation_spike") || derivativesPressure === "long_flush" : false;
18704
18862
  const directionalCrowding = direction === "LONG" ? derivativesRiskFlags.includes("crowded_long") : direction === "SHORT" ? derivativesRiskFlags.includes("crowded_short") : false;
18705
18863
  const derivativesRiskOffLongRecoveryPocket = direction === "LONG" && cmcFearGreedValue != null && cmcFearGreedValue <= MAX_APPROVAL_CMC_FEAR_GREED_VALUE && altBasketReturn24h != null && altBasketReturn24h <= MAX_DERIVATIVES_RISK_OFF_ALT_BASKET_RETURN_24H && referenceTrx1hStale === false && referenceTrx1hOiChangePct4h != null && referenceTrx1hOiChangePct4h <= MAX_DERIVATIVES_RISK_OFF_TRX_OI_CHANGE_PCT_4H;
18706
- if (derivativesDirectionAligned === true && !flushSupport && !derivativesRiskOffLongRecoveryPocket) {
18864
+ const referenceTradeFlowBuyPressurePct = asFiniteNumber2(
18865
+ baseContext?.gateFeatures?.participation?.referenceTradeFlowBuyPressurePct
18866
+ );
18867
+ const benchmarkOiAcceleration = asFiniteNumber2(
18868
+ derivativesSummary?.oiAcceleration
18869
+ );
18870
+ const benchmarkFlowOiExpansionRecoveryPocket = (direction === "LONG" || direction === "SHORT") && q4AtrRankEligible && referenceTradeFlowBuyPressurePct != null && referenceTradeFlowBuyPressurePct >= MIN_BENCHMARK_FLOW_BUY_PRESSURE_PCT && benchmarkOiAcceleration != null && benchmarkOiAcceleration >= MIN_BENCHMARK_OI_ACCELERATION;
18871
+ if (derivativesDirectionAligned === true && !flushSupport && !derivativesRiskOffLongRecoveryPocket && !benchmarkFlowOiExpansionRecoveryPocket) {
18707
18872
  hardBlockReasons.push("derivatives_reversal_aligned");
18708
18873
  }
18709
- if (derivativesDirectionAligned === false && !flushSupport && !derivativesRiskOffLongRecoveryPocket) {
18874
+ if (derivativesDirectionAligned === false && !flushSupport && !derivativesRiskOffLongRecoveryPocket && !benchmarkFlowOiExpansionRecoveryPocket) {
18710
18875
  hardBlockReasons.push("derivatives_reversal_conflict");
18711
18876
  }
18712
18877
  if (volumeRel20 != null && volumeRel20 < 0.75) {
@@ -18781,6 +18946,24 @@ var buildLiquidityTailsGuardrailContext = ({
18781
18946
  if (deterministicQuality === 3 && hardBlockReasons.length === 0 && derivativesRiskOffLongRecoveryPocket) {
18782
18947
  deterministicQuality = 4;
18783
18948
  }
18949
+ if (deterministicQuality >= 4) {
18950
+ const approvalContextReasons = [];
18951
+ if (priceDistanceToMaSlowAtr == null) {
18952
+ approvalContextReasons.push("price_distance_to_ma_slow_unavailable");
18953
+ } else if (priceDistanceToMaSlowAtr > MAX_APPROVAL_PRICE_DISTANCE_TO_MA_SLOW_ATR) {
18954
+ approvalContextReasons.push("price_overextended_from_ma_slow");
18955
+ }
18956
+ if (liquidityZonesActiveCount == null || liquidityZonesActiveCount < MIN_APPROVAL_ACTIVE_LIQUIDITY_ZONES) {
18957
+ approvalContextReasons.push("liquidity_zone_confirmation_missing");
18958
+ }
18959
+ if (approvalContextReasons.length > 0) {
18960
+ deterministicQuality = 3;
18961
+ softBlockReasons.push(...approvalContextReasons);
18962
+ }
18963
+ }
18964
+ if (deterministicQuality < 4 && hardBlockReasons.length === 0 && benchmarkFlowOiExpansionRecoveryPocket) {
18965
+ deterministicQuality = 4;
18966
+ }
18784
18967
  return {
18785
18968
  ...signalContext,
18786
18969
  baseContextAvailable: Boolean(baseContext),
@@ -18795,6 +18978,8 @@ var buildLiquidityTailsGuardrailContext = ({
18795
18978
  roc1h,
18796
18979
  roc4h,
18797
18980
  benchmarkTrendAlignment,
18981
+ priceDistanceToMaSlowAtr,
18982
+ liquidityZonesActiveCount,
18798
18983
  atrPctRankBucket,
18799
18984
  q4AtrRankEligible,
18800
18985
  liquidityRisk,
@@ -18809,6 +18994,7 @@ var buildLiquidityTailsGuardrailContext = ({
18809
18994
  derivativesRiskFlags,
18810
18995
  cadenceUpgradePocket,
18811
18996
  derivativesRiskOffLongRecoveryPocket,
18997
+ benchmarkFlowOiExpansionRecoveryPocket,
18812
18998
  liquidityTailsGateFeatures,
18813
18999
  hardBlockReasons,
18814
19000
  softBlockReasons,
@@ -18903,6 +19089,8 @@ Additional Liquidity Tails context:
18903
19089
  - roc1h=${String(context.roc1h ?? "n/a")}
18904
19090
  - roc4h=${String(context.roc4h ?? "n/a")}
18905
19091
  - benchmarkTrendAlignment=${context.benchmarkTrendAlignment ?? "n/a"}
19092
+ - priceDistanceToMaSlowAtr=${String(context.priceDistanceToMaSlowAtr ?? "n/a")}
19093
+ - liquidityZonesActiveCount=${String(context.liquidityZonesActiveCount ?? "n/a")}
18906
19094
  - atrPctRankBucket=${context.atrPctRankBucket ?? "n/a"}
18907
19095
  - q4AtrRankEligible=${String(context.q4AtrRankEligible)}
18908
19096
  - liquidityRisk=${context.liquidityRisk ?? "n/a"}
@@ -18977,6 +19165,9 @@ var isDirectionalPriceAboveLevel = ({
18977
19165
  price,
18978
19166
  level
18979
19167
  }) => direction === "LONG" ? price != null && level != null && price > level : direction === "SHORT" ? price != null && level != null && price < level : null;
19168
+ var TRANSITION_LOW_TOUCH_COUNT_MAX = 2;
19169
+ var ETH_REFERENCE_WEAK_NON_STRESS_OI_CHANGE_PCT_24H_MAX = -2.5;
19170
+ var LONG_DIRECT_INDICATOR_SUPPORT_MIN = 2;
18980
19171
  var buildLiquidityZonesGuardrailContext = ({
18981
19172
  signalContext,
18982
19173
  baseContext
@@ -19030,8 +19221,15 @@ var buildLiquidityZonesGuardrailContext = ({
19030
19221
  const lowTouchCount20 = asPresentFiniteNumber(
19031
19222
  baseContext?.structure?.levels?.lowTouchCount20
19032
19223
  );
19224
+ const ethReferenceDerivatives15m = baseContext?.derivatives?.referenceContexts?.ETHUSDT?.intervals?.["15m"];
19033
19225
  const ethReferenceOiChangePct4h = asPresentFiniteNumber(
19034
- baseContext?.derivatives?.referenceContexts?.ETHUSDT?.intervals?.["15m"]?.oiChangePct4h
19226
+ ethReferenceDerivatives15m?.oiChangePct4h
19227
+ );
19228
+ const ethReferenceOiChangePct24h = asPresentFiniteNumber(
19229
+ ethReferenceDerivatives15m?.oiChangePct24h
19230
+ );
19231
+ const ethReferenceFundingZScore = asPresentFiniteNumber(
19232
+ ethReferenceDerivatives15m?.fundingZScore
19035
19233
  );
19036
19234
  const solReferenceOiChangePct24h = asPresentFiniteNumber(
19037
19235
  baseContext?.derivatives?.referenceContexts?.SOLUSDT?.intervals?.["15m"]?.oiChangePct24h
@@ -19130,11 +19328,15 @@ var buildLiquidityZonesGuardrailContext = ({
19130
19328
  const isContinuationBreakoutRetest = direction === "LONG" ? breakoutState === "above_high_level" || entryLocation === "breakout" : direction === "SHORT" ? breakoutState === "below_low_level" || entryLocation === "breakdown" : false;
19131
19329
  const hasBaseRetestConfirmation = filterMetric >= 3 && hitCount >= 2 && reactionCloseDistancePct >= 0.08 && retestPenetrationPct <= 90;
19132
19330
  const ethReferenceOiWeakPocket = ethReferenceOiChangePct4h != null && ethReferenceOiChangePct4h <= -0.8;
19133
- const transitionStructureExpansionPocket = hasBaseRetestConfirmation && structureZoneState === "transition" && structureScore != null && structureScore >= 17 && adaptiveChannelFlipDown === false && !directionalCrowding && !ethReferenceOiWeakPocket;
19331
+ const ethReferenceStressPocket = hasBaseRetestConfirmation && lowTouchCount20 != null && lowTouchCount20 <= 3 && ethReferenceOiChangePct24h != null && ethReferenceOiChangePct24h <= -5.8 && ethReferenceFundingZScore != null && ethReferenceFundingZScore <= -1.05;
19332
+ const transitionStructureExpansionPocket = hasBaseRetestConfirmation && lowTouchCount20 != null && lowTouchCount20 <= TRANSITION_LOW_TOUCH_COUNT_MAX && structureZoneState === "transition" && structureScore != null && structureScore >= 17 && adaptiveChannelFlipDown === false && !directionalCrowding && !ethReferenceOiWeakPocket;
19134
19333
  const solReferenceStressPocket = hasBaseRetestConfirmation && lowTouchCount20 != null && lowTouchCount20 <= 3 && solReferenceOiChangePct24h != null && solReferenceOiChangePct24h <= -4.2 && solReferenceFundingZScore != null && solReferenceFundingZScore <= -1.2;
19135
- const calibratedExpansionPocket = transitionStructureExpansionPocket || solReferenceStressPocket;
19334
+ const calibratedExpansionPocket = transitionStructureExpansionPocket || ethReferenceStressPocket || solReferenceStressPocket;
19335
+ const ethReferenceWeakNonStressPocket = ethReferenceOiChangePct24h != null && ethReferenceOiChangePct24h <= ETH_REFERENCE_WEAK_NON_STRESS_OI_CHANGE_PCT_24H_MAX && !ethReferenceStressPocket;
19336
+ const longDirectIndicatorSupportConfirmed = direction === "LONG" ? directIndicatorSupportCount != null && directIndicatorSupportCount >= LONG_DIRECT_INDICATOR_SUPPORT_MIN : null;
19136
19337
  const longRequiresCalibratedExpansion = direction === "LONG" && !calibratedExpansionPocket;
19137
- const approvalDisqualifiedByCalibration = !calibratedExpansionPocket && (longRequiresCalibratedExpansion || isContinuationBreakoutRetest || hasOverextendedVolumeConfirmation || hasIsolatedIndicatorSupport);
19338
+ const longDirectIndicatorSupportMissing = longDirectIndicatorSupportConfirmed === false;
19339
+ const approvalDisqualifiedByCalibration = !calibratedExpansionPocket && (longRequiresCalibratedExpansion || isContinuationBreakoutRetest || hasOverextendedVolumeConfirmation || hasIsolatedIndicatorSupport) || ethReferenceWeakNonStressPocket || longDirectIndicatorSupportMissing;
19138
19340
  if (longRequiresCalibratedExpansion) {
19139
19341
  softBlockReasons.push("long_liquidity_retest_requires_recalibration");
19140
19342
  }
@@ -19147,6 +19349,12 @@ var buildLiquidityZonesGuardrailContext = ({
19147
19349
  if (hasIsolatedIndicatorSupport) {
19148
19350
  softBlockReasons.push("isolated_indicator_support");
19149
19351
  }
19352
+ if (ethReferenceWeakNonStressPocket) {
19353
+ softBlockReasons.push("eth_reference_oi_weak_without_stress");
19354
+ }
19355
+ if (longDirectIndicatorSupportMissing) {
19356
+ softBlockReasons.push("long_direct_indicator_support_missing");
19357
+ }
19150
19358
  const hasLongBreakoutConfirmation = direction === "LONG" && (breakoutState === "below_low_level" || breakoutState === "above_high_level") && reactionCloseDistancePct >= 1 && volumeRel20 != null && volumeRel20 >= 2 && venueSpreadZScore != null && venueSpreadZScore >= 0;
19151
19359
  const hasShortContinuationConfirmation = direction === "SHORT" && hasVolumeConfirmation;
19152
19360
  let deterministicQuality = 3;
@@ -19206,10 +19414,15 @@ var buildLiquidityZonesGuardrailContext = ({
19206
19414
  adaptiveChannelFlipDown,
19207
19415
  lowTouchCount20,
19208
19416
  ethReferenceOiChangePct4h,
19417
+ ethReferenceOiChangePct24h,
19418
+ ethReferenceFundingZScore,
19209
19419
  solReferenceOiChangePct24h,
19210
19420
  solReferenceFundingZScore,
19211
19421
  transitionStructureExpansionPocket,
19422
+ ethReferenceStressPocket,
19212
19423
  solReferenceStressPocket,
19424
+ ethReferenceWeakNonStressPocket,
19425
+ longDirectIndicatorSupportConfirmed,
19213
19426
  hardBlockReasons,
19214
19427
  softBlockReasons,
19215
19428
  deterministicQuality,
@@ -19303,6 +19516,7 @@ Additional Liquidity Zones context:
19303
19516
  - obvLevelAligned=${String(context.obvLevelAligned ?? "n/a")}
19304
19517
  - obvSlopeAligned=${String(context.obvSlopeAligned ?? "n/a")}
19305
19518
  - directIndicatorSupportCount=${String(context.directIndicatorSupportCount ?? "n/a")}
19519
+ - longDirectIndicatorSupportConfirmed=${String(context.longDirectIndicatorSupportConfirmed ?? "n/a")}
19306
19520
  - venueSpreadZScore=${String(context.venueSpreadZScore ?? "n/a")}
19307
19521
  - benchmarkTrendAlignment=${context.benchmarkTrendAlignment ?? "n/a"}
19308
19522
  - btcCorrelation=${String(context.btcCorrelation ?? "n/a")}
@@ -19314,10 +19528,14 @@ Additional Liquidity Zones context:
19314
19528
  - adaptiveChannelFlipDown=${String(context.adaptiveChannelFlipDown ?? "n/a")}
19315
19529
  - lowTouchCount20=${String(context.lowTouchCount20 ?? "n/a")}
19316
19530
  - ethReferenceOiChangePct4h=${String(context.ethReferenceOiChangePct4h ?? "n/a")}
19531
+ - ethReferenceOiChangePct24h=${String(context.ethReferenceOiChangePct24h ?? "n/a")}
19532
+ - ethReferenceFundingZScore=${String(context.ethReferenceFundingZScore ?? "n/a")}
19317
19533
  - solReferenceOiChangePct24h=${String(context.solReferenceOiChangePct24h ?? "n/a")}
19318
19534
  - solReferenceFundingZScore=${String(context.solReferenceFundingZScore ?? "n/a")}
19319
19535
  - transitionStructureExpansionPocket=${String(context.transitionStructureExpansionPocket)}
19536
+ - ethReferenceStressPocket=${String(context.ethReferenceStressPocket)}
19320
19537
  - solReferenceStressPocket=${String(context.solReferenceStressPocket)}
19538
+ - ethReferenceWeakNonStressPocket=${String(context.ethReferenceWeakNonStressPocket)}
19321
19539
  - deterministicQuality=${context.deterministicQuality}
19322
19540
  - approvalAllowedNow=${String(context.approvalAllowedNow)}
19323
19541
  - hardBlockReasons=${JSON.stringify(context.hardBlockReasons)}
@@ -19332,7 +19550,9 @@ Interpretation rules for Liquidity Zones:
19332
19550
  - A close fully through the level marks the zone crossed; crossed zones are not live-entry candidates.
19333
19551
  - Top-level derivatives context is BTC benchmark evidence; target-symbol derivatives require targetContext/targetDerived.
19334
19552
  - Do not treat derivatives points, rows, or loaded-history size as approval evidence.
19335
- - A calibrated transition-structure pocket or SOL reference stress pocket can approve a structurally valid retest.
19553
+ - A calibrated transition-structure pocket, ETH reference stress pocket, or SOL reference stress pocket can approve a structurally valid retest.
19554
+ - LONG approvals need at least two direct MA/MACD/OBV alignments after calibration.
19555
+ - Moderate ETH reference OI weakness blocks approval unless the deeper ETH reference stress pocket is active.
19336
19556
  - Treat deterministicQuality and approvalAllowedNow as the local normalized gate result.
19337
19557
  `.trim();
19338
19558
  },
@@ -19798,6 +20018,16 @@ var getNestedString2 = (value, path) => {
19798
20018
  }
19799
20019
  return typeof current === "string" ? current : null;
19800
20020
  };
20021
+ var getNestedBoolean2 = (value, path) => {
20022
+ let current = value;
20023
+ for (const segment of path) {
20024
+ if (!isRecord2(current)) {
20025
+ return null;
20026
+ }
20027
+ current = current[segment];
20028
+ }
20029
+ return typeof current === "boolean" ? current : null;
20030
+ };
19801
20031
  var isShortBtcOnlyRecoveryLane = (context, baseContext) => {
19802
20032
  const riskFlags = getNestedRecord2(baseContext, [
19803
20033
  "derivatives",
@@ -19822,23 +20052,59 @@ var isShortBtcOnlyRecoveryLane = (context, baseContext) => {
19822
20052
  const biasConflictState = getReverseTrendlineBiasConflictState(context);
19823
20053
  return context.signalDirection === "SHORT" && context.entryTiming === "ready_rejection" && biasConflictState === "btc_only" && context.deterministicRejectionScore != null && context.deterministicRejectionScore >= 6 && context.distance != null && context.distance >= 61 && !hasMissingDerivatives && (derivativesPressure === "long_flush" || derivativesPressure === "short_flush" || derivativesPressure === "crowded_long") && volumeRel20 != null && volumeRel20 >= 1.5 && rangePosition20 != null && rangePosition20 >= 0.2 && rangePosition20 <= 0.7;
19824
20054
  };
20055
+ var hasMissingDerivativesRisk = (baseContext) => {
20056
+ const riskFlags = getNestedRecord2(baseContext, [
20057
+ "derivatives",
20058
+ "summary"
20059
+ ])?.riskFlags;
20060
+ return Array.isArray(riskFlags) && riskFlags.includes("missing_derivatives");
20061
+ };
20062
+ var isExtremeVolatilityRecoveryLane = (context, baseContext) => {
20063
+ if (context.hardBlockReasons.length > 0) {
20064
+ return false;
20065
+ }
20066
+ const primaryIssue = getNestedString2(baseContext, [
20067
+ "gateFeatures",
20068
+ "decisionHints",
20069
+ "primaryIssue"
20070
+ ]);
20071
+ const approveBias = getNestedString2(baseContext, [
20072
+ "gateFeatures",
20073
+ "decisionHints",
20074
+ "approveBias"
20075
+ ]);
20076
+ const upCloseStreak = getNestedNumber2(baseContext, [
20077
+ "regime",
20078
+ "momentum",
20079
+ "upCloseStreak"
20080
+ ]);
20081
+ const adaptiveChannelFlipUp = getNestedBoolean2(baseContext, [
20082
+ "regime",
20083
+ "trend",
20084
+ "adaptiveChannel",
20085
+ "flipUp"
20086
+ ]);
20087
+ const atrPctRank100 = getNestedNumber2(baseContext, [
20088
+ "regime",
20089
+ "volatility",
20090
+ "percentiles",
20091
+ "atrPctRank100"
20092
+ ]);
20093
+ return primaryIssue === "extreme_volatility" && approveBias === "reject" && upCloseStreak != null && upCloseStreak <= 2 && adaptiveChannelFlipUp === false && atrPctRank100 != null && atrPctRank100 <= 99 && !hasMissingDerivativesRisk(baseContext);
20094
+ };
19825
20095
  var getBaseContextQualityPromotion = (context, signal) => {
19826
20096
  const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
19827
20097
  if (!baseContext) {
19828
20098
  return null;
19829
20099
  }
19830
- return isShortBtcOnlyRecoveryLane(context, baseContext) ? 4 : null;
20100
+ return isShortBtcOnlyRecoveryLane(context, baseContext) || isExtremeVolatilityRecoveryLane(context, baseContext) ? 4 : null;
19831
20101
  };
19832
20102
  var getBaseContextApprovalBlockReasons = (context, signal) => {
19833
20103
  const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
19834
20104
  if (!baseContext) {
19835
20105
  return [];
19836
20106
  }
19837
- const riskFlags = getNestedRecord2(baseContext, [
19838
- "derivatives",
19839
- "summary"
19840
- ])?.riskFlags;
19841
- const hasMissingDerivatives = Array.isArray(riskFlags) && riskFlags.includes("missing_derivatives");
20107
+ const hasMissingDerivatives = hasMissingDerivativesRisk(baseContext);
19842
20108
  const volumeRel20 = getNestedNumber2(baseContext, [
19843
20109
  "participation",
19844
20110
  "volume",
@@ -19874,6 +20140,10 @@ var getBaseContextApprovalBlockReasons = (context, signal) => {
19874
20140
  context,
19875
20141
  baseContext
19876
20142
  );
20143
+ const extremeVolatilityRecoveryLane = isExtremeVolatilityRecoveryLane(
20144
+ context,
20145
+ baseContext
20146
+ );
19877
20147
  const reasons = [];
19878
20148
  if (hasMissingDerivatives) {
19879
20149
  reasons.push("missing_derivatives");
@@ -19893,7 +20163,7 @@ var getBaseContextApprovalBlockReasons = (context, signal) => {
19893
20163
  if (context.signalDirection === "SHORT" && biasConflictState === "btc_only" && context.distance != null && context.distance <= 60) {
19894
20164
  reasons.push("short_btc_conflict_too_shallow");
19895
20165
  }
19896
- if (context.signalDirection === "SHORT" && atrPctZScore != null && atrPctZScore >= 2 && !shortBtcOnlyRecoveryLane) {
20166
+ if (context.signalDirection === "SHORT" && atrPctZScore != null && atrPctZScore >= 2 && !shortBtcOnlyRecoveryLane && !extremeVolatilityRecoveryLane) {
19897
20167
  reasons.push("short_extreme_volatility");
19898
20168
  }
19899
20169
  if (context.signalDirection === "SHORT" && rangePosition20 != null && rangePosition20 < 0.2) {
@@ -19914,7 +20184,9 @@ var buildReverseTrendLineGateFeatures = ({
19914
20184
  context,
19915
20185
  signal,
19916
20186
  approvalBlockReasons,
19917
- deterministicRejectionScore
20187
+ deterministicRejectionScore,
20188
+ approvalLane,
20189
+ extremeVolatilityRecoveryPocket
19918
20190
  }) => {
19919
20191
  const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
19920
20192
  const volumeRel20 = getNestedNumber2(baseContext, [
@@ -19948,6 +20220,8 @@ var buildReverseTrendLineGateFeatures = ({
19948
20220
  volatilityState,
19949
20221
  rangePositionState,
19950
20222
  highQualityBouncePocket: context.deterministicQuality >= 4 && approvalBlockReasons.length === 0 && (bounceAcceptance === "rejection" || bounceAcceptance === "follow_through"),
20223
+ extremeVolatilityRecoveryPocket,
20224
+ approvalLane,
19951
20225
  deterministicRejectionScore
19952
20226
  };
19953
20227
  };
@@ -20072,7 +20346,14 @@ var buildReverseTrendlineAiContext = (signal) => {
20072
20346
  },
20073
20347
  signal
20074
20348
  );
20075
- const reverseTrendLineGateFeatures = buildReverseTrendLineGateFeatures({
20349
+ const baseContext = isRecord2(signal.additionalIndicators?.baseContext) ? signal.additionalIndicators.baseContext : null;
20350
+ const extremeVolatilityRecoveryPocket = baseContext != null ? isExtremeVolatilityRecoveryLane(
20351
+ {
20352
+ hardBlockReasons
20353
+ },
20354
+ baseContext
20355
+ ) : false;
20356
+ const baseReverseTrendLineGateFeatures = buildReverseTrendLineGateFeatures({
20076
20357
  context: {
20077
20358
  ...structural,
20078
20359
  ...timing,
@@ -20081,17 +20362,28 @@ var buildReverseTrendlineAiContext = (signal) => {
20081
20362
  },
20082
20363
  signal,
20083
20364
  approvalBlockReasons,
20084
- deterministicRejectionScore
20365
+ deterministicRejectionScore,
20366
+ approvalLane: "watch",
20367
+ extremeVolatilityRecoveryPocket
20085
20368
  });
20369
+ const highScoreBouncePocket = baseReverseTrendLineGateFeatures.highQualityBouncePocket && deterministicRejectionScore != null && deterministicRejectionScore >= 7;
20370
+ const approvalLane = highScoreBouncePocket ? "high_score_bounce" : extremeVolatilityRecoveryPocket ? "extreme_volatility_recovery" : "watch";
20371
+ const approvalAllowedNow = approvalLane !== "watch";
20372
+ const finalApprovalBlockReasons = !approvalAllowedNow && promotedDeterministicQuality >= 4 && approvalBlockReasons.length === 0 ? [...approvalBlockReasons, "rejection_score_below_gate"] : approvalBlockReasons;
20373
+ const finalDeterministicQuality = approvalAllowedNow ? Math.max(promotedDeterministicQuality, 4) : promotedDeterministicQuality;
20374
+ const reverseTrendLineGateFeatures = {
20375
+ ...baseReverseTrendLineGateFeatures,
20376
+ approvalLane
20377
+ };
20086
20378
  return {
20087
20379
  ...structural,
20088
20380
  ...timing,
20089
20381
  reverseTrendLineGateFeatures,
20090
- deterministicQuality: promotedDeterministicQuality,
20382
+ deterministicQuality: finalDeterministicQuality,
20091
20383
  deterministicRejectionScore,
20092
- approvalAllowedNow: promotedDeterministicQuality >= 4 && approvalBlockReasons.length === 0,
20384
+ approvalAllowedNow,
20093
20385
  hardBlockReasons,
20094
- approvalBlockReasons
20386
+ approvalBlockReasons: finalApprovalBlockReasons
20095
20387
  };
20096
20388
  };
20097
20389
  var withReverseTrendLineGateFeatures = ({
@@ -20136,6 +20428,8 @@ var getHardBlockReasonText2 = (reason) => {
20136
20428
  return "LONG bounce distance sits in a weak mid-distance pocket";
20137
20429
  case "short_follow_through_overrated":
20138
20430
  return "SHORT follow-through bounce is not reliable enough for quality 5";
20431
+ case "rejection_score_below_gate":
20432
+ return "deterministic rejection score is below the current strict gate";
20139
20433
  default:
20140
20434
  return reason;
20141
20435
  }
@@ -20220,6 +20514,8 @@ Additional ReverseTrendLine context:
20220
20514
  - reverseTrendLineGateVolatilityState=${context.reverseTrendLineGateFeatures.volatilityState}
20221
20515
  - reverseTrendLineGateRangePositionState=${context.reverseTrendLineGateFeatures.rangePositionState}
20222
20516
  - reverseTrendLineGateHighQualityBouncePocket=${String(context.reverseTrendLineGateFeatures.highQualityBouncePocket)}
20517
+ - reverseTrendLineGateExtremeVolatilityRecoveryPocket=${String(context.reverseTrendLineGateFeatures.extremeVolatilityRecoveryPocket)}
20518
+ - reverseTrendLineGateApprovalLane=${context.reverseTrendLineGateFeatures.approvalLane}
20223
20519
  - approvalAllowedNow=${context.approvalAllowedNow}
20224
20520
  - hardBlockReasons=${context.hardBlockReasons.join(", ") || "none"}
20225
20521
  - approvalBlockReasons=${context.approvalBlockReasons.join(", ") || "none"}
@@ -20473,6 +20769,7 @@ var TREND_FOLLOW_OPENING_SESSION_MAX_MINUTES_FROM_OPEN = 75;
20473
20769
  var TREND_FOLLOW_OPENING_REF_XRP_OI_MAX = 324e6;
20474
20770
  var TREND_FOLLOW_OPENING_REF_XRP_OI_CHANGE_1H_MIN = 0.4;
20475
20771
  var TREND_FOLLOW_OPENING_REF_BNB_OI_MIN = 56e4;
20772
+ var TREND_FOLLOW_ALLOWED_VOLATILITY_STATE = "normal";
20476
20773
  var asFiniteNumber5 = (value) => {
20477
20774
  const parsed = Number(value);
20478
20775
  return Number.isFinite(parsed) ? parsed : null;
@@ -20584,6 +20881,7 @@ var buildTrendFollowGateFeatures = ({
20584
20881
  );
20585
20882
  const marketBreadthAligned = marketBreadthReturn == null || marketBreadth?.stale ? null : direction === "LONG" ? marketBreadthReturn >= 0 : direction === "SHORT" ? marketBreadthReturn <= 0 : null;
20586
20883
  const marketBreadthContinuation = marketBreadth?.stale === true ? "stale" : marketBreadthAligned === true ? "aligned" : marketBreadthAligned === false ? "against" : "unknown";
20884
+ const marketVolatilityState = typeof baseContext?.regime?.volatility?.state === "string" ? baseContext.regime.volatility.state : null;
20587
20885
  const targetVsBtcBeta20 = asFiniteNumber5(
20588
20886
  baseContext?.relative?.targetVsBtc?.betaToBtc20
20589
20887
  );
@@ -20635,6 +20933,8 @@ var buildTrendFollowGateFeatures = ({
20635
20933
  const referenceDerivativesLossBlock = direction === "SHORT" && referenceXrp15mOpenInterest != null && referenceXrp15mOpenInterest >= TREND_FOLLOW_REF_LOSS_XRP_OI_MIN && referenceEthCrowdingPersistenceBars != null && referenceEthCrowdingPersistenceBars >= TREND_FOLLOW_REF_LOSS_ETH_CROWDING_MIN && referenceSol15mFundingZScore != null && referenceSol15mFundingZScore <= TREND_FOLLOW_REF_LOSS_SOL_FUNDING_Z_MAX;
20636
20934
  const referenceDerivativesCadencePocket = !referenceDerivativesLossBlock && (legacyCadencePocket || referenceDerivativesOiCompressionPocket || referenceDerivativesXrpFundingPocket || referenceDerivativesSolFlushPocket);
20637
20935
  const referenceDerivativesOpeningPocket = direction === "SHORT" && minutesFromSessionOpen != null && minutesFromSessionOpen <= TREND_FOLLOW_OPENING_SESSION_MAX_MINUTES_FROM_OPEN && referenceXrp15mOpenInterest != null && referenceXrp15mOpenInterest <= TREND_FOLLOW_OPENING_REF_XRP_OI_MAX && referenceXrp1hOiChangePct1h != null && referenceXrp1hOiChangePct1h >= TREND_FOLLOW_OPENING_REF_XRP_OI_CHANGE_1H_MIN && referenceBnb15mOpenInterest != null && referenceBnb15mOpenInterest >= TREND_FOLLOW_OPENING_REF_BNB_OI_MIN;
20936
+ const referenceDerivativesCleanCadencePocket = referenceDerivativesCadencePocket && !derivativesShortFlushOiPocket;
20937
+ const normalVolatilityCadencePocket = marketVolatilityState === TREND_FOLLOW_ALLOWED_VOLATILITY_STATE;
20638
20938
  return {
20639
20939
  setupStopDistanceAtr,
20640
20940
  setupTpDistanceAtr,
@@ -20649,6 +20949,7 @@ var buildTrendFollowGateFeatures = ({
20649
20949
  relativeContinuation,
20650
20950
  marketBreadthContinuation,
20651
20951
  marketBreadthDispersion: asFiniteNumber5(marketBreadth?.dispersion),
20952
+ marketVolatilityState,
20652
20953
  targetVsBtcBeta20,
20653
20954
  btcAltRegimeBtcTurnoverShare24h,
20654
20955
  btcAltRegimeAltBasketReturn24h,
@@ -20675,8 +20976,10 @@ var buildTrendFollowGateFeatures = ({
20675
20976
  referenceDerivativesSolFlushPocket,
20676
20977
  referenceDerivativesLossBlock,
20677
20978
  referenceDerivativesCadencePocket,
20979
+ referenceDerivativesCleanCadencePocket,
20678
20980
  referenceDerivativesOpeningPocket,
20679
- highQualityCadencePocket: referenceDerivativesCadencePocket || referenceDerivativesOpeningPocket
20981
+ normalVolatilityCadencePocket,
20982
+ highQualityCadencePocket: normalVolatilityCadencePocket && referenceDerivativesCleanCadencePocket
20680
20983
  };
20681
20984
  };
20682
20985
  var buildTrendFollowGuardrailContext = ({
@@ -20909,6 +21212,7 @@ Additional TrendFollow context:
20909
21212
  - trendFollowGateRelativeContinuation=${context.trendFollowGateFeatures.relativeContinuation}
20910
21213
  - trendFollowGateMarketBreadthContinuation=${context.trendFollowGateFeatures.marketBreadthContinuation}
20911
21214
  - trendFollowGateMarketBreadthDispersion=${String(context.trendFollowGateFeatures.marketBreadthDispersion ?? "n/a")}
21215
+ - trendFollowGateMarketVolatilityState=${String(context.trendFollowGateFeatures.marketVolatilityState ?? "n/a")}
20912
21216
  - trendFollowGateTargetVsBtcBeta20=${String(context.trendFollowGateFeatures.targetVsBtcBeta20 ?? "n/a")}
20913
21217
  - trendFollowGateBtcAltRegimeBtcTurnoverShare24h=${String(context.trendFollowGateFeatures.btcAltRegimeBtcTurnoverShare24h ?? "n/a")}
20914
21218
  - trendFollowGateBtcAltRegimeAltBasketReturn24h=${String(context.trendFollowGateFeatures.btcAltRegimeAltBasketReturn24h ?? "n/a")}
@@ -20935,7 +21239,9 @@ Additional TrendFollow context:
20935
21239
  - trendFollowGateReferenceDerivativesSolFlushPocket=${String(context.trendFollowGateFeatures.referenceDerivativesSolFlushPocket)}
20936
21240
  - trendFollowGateReferenceDerivativesLossBlock=${String(context.trendFollowGateFeatures.referenceDerivativesLossBlock)}
20937
21241
  - trendFollowGateReferenceDerivativesCadencePocket=${String(context.trendFollowGateFeatures.referenceDerivativesCadencePocket)}
21242
+ - trendFollowGateReferenceDerivativesCleanCadencePocket=${String(context.trendFollowGateFeatures.referenceDerivativesCleanCadencePocket)}
20938
21243
  - trendFollowGateReferenceDerivativesOpeningPocket=${String(context.trendFollowGateFeatures.referenceDerivativesOpeningPocket)}
21244
+ - trendFollowGateNormalVolatilityCadencePocket=${String(context.trendFollowGateFeatures.normalVolatilityCadencePocket)}
20939
21245
  - trendFollowGateHighQualityCadencePocket=${String(context.trendFollowGateFeatures.highQualityCadencePocket)}
20940
21246
  - benchmarkTrendAlignment=${context.benchmarkTrendAlignment ?? "n/a"}
20941
21247
  - derivativesPressure=${context.derivativesPressure ?? "n/a"}
@@ -20953,7 +21259,7 @@ Interpretation rules for TrendFollow:
20953
21259
  - The ATR trailing stop is the structural invalidation line and also updates while a position is open.
20954
21260
  - Prefer breakouts aligned with shared market context and backed by participation.
20955
21261
  - Late, thin, crowded, inside-range, adverse-delta, weak-momentum, or weak-volume-structure breakouts should be downgraded even if the pivot cross is valid.
20956
- - 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.
21262
+ - Live approval is reserved for calibrated SHORT extra-reference derivatives pockets in normal volatility when the BTC benchmark short-flush/OI pocket is not active; legacy BTC benchmark flush and opening-session recovery remain watch mode.
20957
21263
  - Treat deterministicQuality and approvalAllowedNow as the local normalized gate result.
20958
21264
  `.trim();
20959
21265
  },
@@ -20985,6 +21291,13 @@ var SHORT_BREADTH_SHOCK_1H_LIQ_SHORT_MAX = 0.208;
20985
21291
  var LONG_ALT_LEADERSHIP_BTC_VS_ALT_RETURN_24H_MAX = -503054e-8;
20986
21292
  var LONG_ALT_LEADERSHIP_BTC_VS_ALT_RETURN_1H_MAX = -581403e-8;
20987
21293
  var LONG_ALT_LEADERSHIP_FEAR_GREED_CHANGE_24H_MIN = -1;
21294
+ var LONG_BROAD_MARKET_SHORT_FLUSH_ADVANCERS_MIN = 27;
21295
+ var LONG_BROAD_MARKET_SHORT_FLUSH_PCT_ABOVE_MA20_MIN = 0.95;
21296
+ var LONG_BROAD_MARKET_SHORT_FLUSH_BTC_VS_ALT_RETURN_24H_MIN = 0;
21297
+ var SHORT_ASIA_LONG_FLUSH_LOW_CMC_FEAR_GREED_MAX = 18;
21298
+ var SHORT_ASIA_LONG_FLUSH_ADVANCERS_MAX = 2;
21299
+ var BNB_REFERENCE_OI_CHANGE_PCT_4H_RISK_MIN = 0;
21300
+ var DERIVATIVES_DATA_UNAVAILABLE_STRESS_CMC_FEAR_GREED_MAX = 25;
20988
21301
  var toMtfAlignmentForTrendShift = ({
20989
21302
  direction,
20990
21303
  mtfAlignment
@@ -21233,19 +21546,33 @@ var buildTrendShiftGuardrailContext = ({
21233
21546
  );
21234
21547
  const gateVolatility = baseContext?.gateFeatures?.volatility;
21235
21548
  const gateRelative = baseContext?.gateFeatures?.relative;
21549
+ const baseMarketBreadth = baseContext?.relative?.marketBreadth;
21236
21550
  const baseBtcAltRegime = baseContext?.relative?.btcAltRegime;
21237
21551
  const baseCmcFearGreed = baseContext?.relative?.cmcFearGreed;
21238
21552
  const bbWidthPct = asFiniteNumber6(volatility?.bbWidthPct);
21239
21553
  const marketBreadthReturn = asFiniteNumber6(gateRelative?.marketBreadthReturn);
21554
+ const marketBreadthAdvancers = asFiniteNumber6(baseMarketBreadth?.advancers);
21555
+ const marketBreadthPctAboveMa20 = asFiniteNumber6(
21556
+ baseMarketBreadth?.pctAboveMa20
21557
+ );
21558
+ const marketBreadthStale = gateRelative?.marketBreadthStale === true || baseMarketBreadth?.stale === true;
21240
21559
  const btcVsAltReturn24h = asFiniteNumber6(gateRelative?.btcVsAltReturn24h);
21241
21560
  const btcVsAltReturn1h = asFiniteNumber6(baseBtcAltRegime?.btcVsAltReturn1h);
21561
+ const cmcFearGreedValue = asFiniteNumber6(
21562
+ gateRelative?.cmcFearGreedValue ?? baseCmcFearGreed?.value
21563
+ );
21242
21564
  const cmcFearGreedValueChange24h = asFiniteNumber6(
21243
21565
  gateRelative?.cmcFearGreedValueChange24h ?? baseCmcFearGreed?.valueChange24h
21244
21566
  );
21245
21567
  const cmcFearGreedStale = gateRelative?.cmcFearGreedStale === true || baseCmcFearGreed?.stale === true;
21568
+ const derivativesDataUnavailable = derivativesRiskFlags.includes("missing_derivatives") || derivativesRiskFlags.includes("stale_derivatives");
21569
+ const derivativesDataUnavailableStressRisk = derivativesDataUnavailable && cmcFearGreedStale !== true && cmcFearGreedValue != null && cmcFearGreedValue <= DERIVATIVES_DATA_UNAVAILABLE_STRESS_CMC_FEAR_GREED_MAX;
21246
21570
  const derivatives1hLiqShort = asFiniteNumber6(
21247
21571
  baseContext?.derivatives?.intervals?.["1h"]?.liqShort
21248
21572
  );
21573
+ const bnbReferenceOiChangePct4h = asFiniteNumber6(
21574
+ baseContext?.derivatives?.referenceContexts?.BNBUSDT?.intervals?.["1h"]?.oiChangePct4h
21575
+ );
21249
21576
  const btcAltRegime = typeof gateRelative?.btcAltRegime === "string" ? gateRelative.btcAltRegime : null;
21250
21577
  const btcAltRegimeStale = gateRelative?.btcAltRegimeStale === true;
21251
21578
  const cmcExchangeLiquidityVolumeChange24hPct = asFiniteNumber6(
@@ -21270,8 +21597,8 @@ var buildTrendShiftGuardrailContext = ({
21270
21597
  const q4LongBreakoutCandidate = signalContext.signalDirection === "LONG" && breakoutState === "above_high_level" && volumeRel20 != null && volumeRel20 >= 1.2 && atrPctZScore != null && atrPctZScore >= 0 && relativeStrength1h != null && relativeStrength1h > -1 && derivativesPressure === "short_flush";
21271
21598
  const q4ShortBreakoutCandidate = signalContext.signalDirection === "SHORT" && breakoutState === "below_low_level" && volumeRel20 != null && volumeRel20 >= 1.2 && atrPctZScore != null && atrPctZScore >= 0 && relativeStrength1h != null && relativeStrength1h < 1 && derivativesPressure === "long_flush";
21272
21599
  const q4ShortAsiaFlushCandidate = signalContext.signalDirection === "SHORT" && derivativesPressure === "neutral" && derivativesFlushSupport && sessionPrimary === "asia" && !sessionIsOverlap && distanceAtrRatio < 0.7 && slopeAbs >= 0.08 && closeVsAvgPctAbs >= 0.12;
21273
- 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");
21274
- const shortNeutralBearChannelBreakdownCandidate = signalContext.signalDirection === "SHORT" && breakoutState === "below_low_level" && derivativesPressure === "neutral" && atrPctZScore != null && atrPctZScore >= 0 && atrPctZScore < 1 && adaptiveChannelDirection === "bear";
21600
+ const selectiveNeutralQ4Candidate = hasDerivativesSummary && derivativesPressure === "neutral" && !derivativesDataUnavailableStressRisk && !sessionIsOverlap && (signalContext.signalDirection === "LONG" && sessionPrimary === "europe" && (breakoutState === "above_high_level" || breakoutState === "failed_high_breakout") || signalContext.signalDirection === "SHORT" && (sessionPrimary === "off_hours" || sessionPrimary === "asia") && breakoutState === "below_low_level");
21601
+ const shortNeutralBearChannelBreakdownCandidate = signalContext.signalDirection === "SHORT" && breakoutState === "below_low_level" && derivativesPressure === "neutral" && !derivativesDataUnavailableStressRisk && atrPctZScore != null && atrPctZScore >= 0 && atrPctZScore < 1 && adaptiveChannelDirection === "bear";
21275
21602
  let deterministicQuality = 3;
21276
21603
  if (hardBlockReasons.length > 0) {
21277
21604
  deterministicQuality = signalContext.confirmedFlip ? 2 : 1;
@@ -21339,6 +21666,10 @@ var buildTrendShiftGuardrailContext = ({
21339
21666
  hardBlockReasons.push("us_short_oi_not_expanding");
21340
21667
  }
21341
21668
  }
21669
+ if (deterministicQuality >= 5 && derivativesDataUnavailableStressRisk) {
21670
+ deterministicQuality = 4;
21671
+ hardBlockReasons.push("derivatives_data_unavailable_stress");
21672
+ }
21342
21673
  if (deterministicQuality >= 5 && hasDerivativesSummary && !selectiveNeutralQ4Candidate && !shortNeutralBearChannelBreakdownCandidate && derivativesPressure === "neutral" && !derivativesFlushSupport) {
21343
21674
  deterministicQuality = 4;
21344
21675
  hardBlockReasons.push("neutral_derivatives_pressure");
@@ -21358,9 +21689,12 @@ var buildTrendShiftGuardrailContext = ({
21358
21689
  const shortExtremeAtrHighBbRisk = signalContext.signalDirection === "SHORT" && gateVolatility?.state === "normal" && gateVolatility.atrPctRankBucket === "extreme" && gateVolatility.bbWidthRankBucket === "high";
21359
21690
  const shortBullSwingStructureRisk = signalContext.signalDirection === "SHORT" && swingBias === "bull";
21360
21691
  const shortLowBollingerWidthRisk = signalContext.signalDirection === "SHORT" && bbWidthPct != null && bbWidthPct <= SHORT_LOW_BB_WIDTH_PCT_MAX;
21692
+ const shortAsiaLongFlushLowCmcBreadthRisk = signalContext.signalDirection === "SHORT" && sessionPrimary === "asia" && derivativesPressure === "long_flush" && cmcFearGreedStale !== true && marketBreadthStale !== true && cmcFearGreedValue != null && cmcFearGreedValue <= SHORT_ASIA_LONG_FLUSH_LOW_CMC_FEAR_GREED_MAX && marketBreadthAdvancers != null && marketBreadthAdvancers <= SHORT_ASIA_LONG_FLUSH_ADVANCERS_MAX;
21361
21693
  const lowRewardToVolatilityRisk = rewardToVolatility != null && rewardToVolatility < 0.25;
21362
21694
  const defensiveRewardToVolatilityRisk = rewardToVolatility != null && rewardToVolatility >= 0.25 && rewardToVolatility < 8;
21695
+ const bnbReferenceOiExpansionRisk = bnbReferenceOiChangePct4h != null && bnbReferenceOiChangePct4h >= BNB_REFERENCE_OI_CHANGE_PCT_4H_RISK_MIN;
21363
21696
  const longBtcAltRegimeRisk = signalContext.signalDirection === "LONG" && btcAltRegimeStale !== true && (btcAltRegime === "btc_lead" || btcAltRegime === "risk_off");
21697
+ const longBroadMarketShortFlushRisk = signalContext.signalDirection === "LONG" && derivativesPressure === "short_flush" && marketBreadthAdvancers != null && marketBreadthAdvancers >= LONG_BROAD_MARKET_SHORT_FLUSH_ADVANCERS_MIN && marketBreadthPctAboveMa20 != null && marketBreadthPctAboveMa20 >= LONG_BROAD_MARKET_SHORT_FLUSH_PCT_ABOVE_MA20_MIN && btcVsAltReturn24h != null && btcVsAltReturn24h >= LONG_BROAD_MARKET_SHORT_FLUSH_BTC_VS_ALT_RETURN_24H_MIN;
21364
21698
  const cmcExchangeLiquidityVolumeChangeRisk = cmcExchangeLiquidityStale !== true && cmcExchangeLiquidityVolumeChange24hPct != null && (cmcExchangeLiquidityVolumeChange24hPct > -0.1 && cmcExchangeLiquidityVolumeChange24hPct < 0 || cmcExchangeLiquidityVolumeChange24hPct >= 0.1 && cmcExchangeLiquidityVolumeChange24hPct < 0.3);
21365
21699
  if (deterministicQuality >= 5 && longRelativeStrengthOverextended) {
21366
21700
  deterministicQuality = 4;
@@ -21398,6 +21732,10 @@ var buildTrendShiftGuardrailContext = ({
21398
21732
  deterministicQuality = 4;
21399
21733
  hardBlockReasons.push("short_bull_swing_structure");
21400
21734
  }
21735
+ if (deterministicQuality >= 5 && shortAsiaLongFlushLowCmcBreadthRisk) {
21736
+ deterministicQuality = 4;
21737
+ hardBlockReasons.push("short_asia_long_flush_low_cmc_breadth");
21738
+ }
21401
21739
  if (deterministicQuality >= 4 && lowRewardToVolatilityRisk) {
21402
21740
  deterministicQuality = 4;
21403
21741
  hardBlockReasons.push("low_reward_to_volatility");
@@ -21406,10 +21744,18 @@ var buildTrendShiftGuardrailContext = ({
21406
21744
  deterministicQuality = 4;
21407
21745
  hardBlockReasons.push("reward_to_volatility_below_defensive_threshold");
21408
21746
  }
21747
+ if (deterministicQuality >= 5 && bnbReferenceOiExpansionRisk) {
21748
+ deterministicQuality = 4;
21749
+ hardBlockReasons.push("bnb_reference_1h_oi4h_expansion_risk");
21750
+ }
21409
21751
  if (deterministicQuality >= 4 && longBtcAltRegimeRisk) {
21410
21752
  deterministicQuality = 4;
21411
21753
  hardBlockReasons.push("long_btc_alt_regime_risk");
21412
21754
  }
21755
+ if (deterministicQuality >= 5 && longBroadMarketShortFlushRisk) {
21756
+ deterministicQuality = 4;
21757
+ hardBlockReasons.push("long_broad_market_short_flush_risk");
21758
+ }
21413
21759
  if (deterministicQuality >= 4 && cmcExchangeLiquidityVolumeChangeRisk) {
21414
21760
  deterministicQuality = 4;
21415
21761
  hardBlockReasons.push("cmc_exchange_liquidity_volume_change_risk");
@@ -21428,7 +21774,7 @@ var buildTrendShiftGuardrailContext = ({
21428
21774
  const q4UsClosingOiConfirmationRecoveryCandidate = deterministicQuality === 4 && signalContext.confirmedFlip === true && signalContext.flipDistanceOk === true && sessionPrimary === "us" && sessionWindowPhase === "closing" && hardBlockReasons.length > 0 && hardBlockReasons.every(
21429
21775
  (reason) => q4UsClosingOiConfirmationRecoveryAllowedReasons.includes(reason)
21430
21776
  );
21431
- const q4ShortBreadthShockLiquidationRecoveryCandidate = deterministicQuality === 4 && signalContext.signalDirection === "SHORT" && signalContext.confirmedFlip === true && signalContext.flipDistanceOk === true && marketBreadthReturn != null && marketBreadthReturn <= SHORT_BREADTH_SHOCK_MARKET_BREADTH_RETURN_MAX2 && derivatives1hLiqShort != null && derivatives1hLiqShort <= SHORT_BREADTH_SHOCK_1H_LIQ_SHORT_MAX;
21777
+ const q4ShortBreadthShockLiquidationRecoveryCandidate = deterministicQuality === 4 && signalContext.signalDirection === "SHORT" && signalContext.confirmedFlip === true && signalContext.flipDistanceOk === true && hardBlockReasons.length === 0 && !derivativesDataUnavailableStressRisk && marketBreadthReturn != null && marketBreadthReturn <= SHORT_BREADTH_SHOCK_MARKET_BREADTH_RETURN_MAX2 && derivatives1hLiqShort != null && derivatives1hLiqShort <= SHORT_BREADTH_SHOCK_1H_LIQ_SHORT_MAX;
21432
21778
  const q4LongAltLeadershipRecoveryAllowedReasons = [
21433
21779
  "flat_or_mixed_oi",
21434
21780
  "neutral_derivatives_pressure",
@@ -21475,9 +21821,13 @@ var buildTrendShiftGuardrailContext = ({
21475
21821
  shortExtremeAtrHighBbRisk,
21476
21822
  shortBullSwingStructureRisk,
21477
21823
  shortLowBollingerWidthRisk,
21824
+ shortAsiaLongFlushLowCmcBreadthRisk,
21825
+ derivativesDataUnavailableStressRisk,
21478
21826
  lowRewardToVolatilityRisk,
21479
21827
  defensiveRewardToVolatilityRisk,
21828
+ bnbReferenceOiExpansionRisk,
21480
21829
  longBtcAltRegimeRisk,
21830
+ longBroadMarketShortFlushRisk,
21481
21831
  cmcExchangeLiquidityVolumeChangeRisk,
21482
21832
  q4TrendShiftGateFeaturesRecoveryCandidate,
21483
21833
  q4UsClosingOiConfirmationRecoveryCandidate,
@@ -21493,10 +21843,14 @@ var buildTrendShiftGuardrailContext = ({
21493
21843
  nearPointOfControl,
21494
21844
  relativeStrength1h,
21495
21845
  marketBreadthReturn,
21846
+ marketBreadthAdvancers,
21847
+ marketBreadthPctAboveMa20,
21496
21848
  btcVsAltReturn24h,
21497
21849
  btcVsAltReturn1h,
21850
+ cmcFearGreedValue,
21498
21851
  cmcFearGreedValueChange24h,
21499
21852
  derivatives1hLiqShort,
21853
+ bnbReferenceOiChangePct4h,
21500
21854
  btcAltRegime,
21501
21855
  cmcExchangeLiquidityVolumeChange24hPct,
21502
21856
  trendShiftGateFeatures,
@@ -21562,12 +21916,20 @@ var getTrendShiftGuardrailReasonText = (reason) => {
21562
21916
  return "the SHORT flip is still fighting a bullish swing structure, so keep it in watch mode";
21563
21917
  case "short_low_bollinger_width":
21564
21918
  return "the SHORT flip is in a narrow Bollinger-width compression pocket that has been less reliable, so keep it in watch mode";
21919
+ case "short_asia_long_flush_low_cmc_breadth":
21920
+ return "the SHORT flip is selling an Asia-session long flush while CMC fear/greed and market breadth are already in capitulation, so keep it in watch mode";
21921
+ case "derivatives_data_unavailable_stress":
21922
+ return "benchmark derivatives data is missing or stale during CMC stress, so keep the flip in watch mode instead of treating neutral derivatives as confirmation";
21565
21923
  case "low_reward_to_volatility":
21566
21924
  return "the expected reward is too small relative to current volatility after costs, so keep the flip in watch mode";
21567
21925
  case "reward_to_volatility_below_defensive_threshold":
21568
21926
  return "the expected reward is not large enough relative to current volatility for the defensive TrendShift gate after costs";
21927
+ case "bnb_reference_1h_oi4h_expansion_risk":
21928
+ return "BNB reference 1h open interest is expanding over 4h, a historically fragile cross-market state for TrendShift approvals";
21569
21929
  case "long_btc_alt_regime_risk":
21570
21930
  return "the LONG flip is fighting a BTC-led or risk-off alt regime, so keep it in watch mode";
21931
+ case "long_broad_market_short_flush_risk":
21932
+ 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";
21571
21933
  case "cmc_exchange_liquidity_volume_change_risk":
21572
21934
  return "major-exchange liquidity change is in a historically choppy CMC band, so keep the flip in watch mode";
21573
21935
  default:
@@ -21682,8 +22044,11 @@ Additional TrendShift context:
21682
22044
  - nearPointOfControl=${String(context.nearPointOfControl ?? "n/a")}
21683
22045
  - relativeStrength1h=${String(context.relativeStrength1h ?? "n/a")}
21684
22046
  - marketBreadthReturn=${String(context.marketBreadthReturn ?? "n/a")}
22047
+ - marketBreadthAdvancers=${String(context.marketBreadthAdvancers ?? "n/a")}
22048
+ - marketBreadthPctAboveMa20=${String(context.marketBreadthPctAboveMa20 ?? "n/a")}
21685
22049
  - btcVsAltReturn24h=${String(context.btcVsAltReturn24h ?? "n/a")}
21686
22050
  - btcVsAltReturn1h=${String(context.btcVsAltReturn1h ?? "n/a")}
22051
+ - cmcFearGreedValue=${String(context.cmcFearGreedValue ?? "n/a")}
21687
22052
  - cmcFearGreedValueChange24h=${String(context.cmcFearGreedValueChange24h ?? "n/a")}
21688
22053
  - derivatives1hLiqShort=${String(context.derivatives1hLiqShort ?? "n/a")}
21689
22054
  - btcAltRegime=${context.btcAltRegime ?? "n/a"}
@@ -21712,7 +22077,12 @@ Additional TrendShift context:
21712
22077
  - shortLowBollingerWidthRisk=${String(context.shortLowBollingerWidthRisk)}
21713
22078
  - defensiveRewardToVolatilityRisk=${String(context.defensiveRewardToVolatilityRisk)}
21714
22079
  - shortBullSwingStructureRisk=${String(context.shortBullSwingStructureRisk)}
22080
+ - shortAsiaLongFlushLowCmcBreadthRisk=${String(context.shortAsiaLongFlushLowCmcBreadthRisk)}
22081
+ - derivativesDataUnavailableStressRisk=${String(context.derivativesDataUnavailableStressRisk)}
21715
22082
  - longBtcAltRegimeRisk=${String(context.longBtcAltRegimeRisk)}
22083
+ - longBroadMarketShortFlushRisk=${String(context.longBroadMarketShortFlushRisk)}
22084
+ - bnbReferenceOiChangePct4h=${String(context.bnbReferenceOiChangePct4h ?? "n/a")}
22085
+ - bnbReferenceOiExpansionRisk=${String(context.bnbReferenceOiExpansionRisk)}
21716
22086
  - cmcExchangeLiquidityVolumeChangeRisk=${String(context.cmcExchangeLiquidityVolumeChangeRisk)}
21717
22087
  - q4TrendShiftGateFeaturesRecoveryCandidate=${String(context.q4TrendShiftGateFeaturesRecoveryCandidate)}
21718
22088
  - q4UsClosingOiConfirmationRecoveryCandidate=${String(context.q4UsClosingOiConfirmationRecoveryCandidate)}
@@ -21749,11 +22119,15 @@ Interpretation rules for TrendShift:
21749
22119
  - 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.
21750
22120
  - For SHORT, a bullish swing structure is a watch-only warning even when the immediate flip geometry looks q5-strong.
21751
22121
  - For SHORT, a narrow Bollinger-width compression pocket is watch-only even if another q4 recovery condition is present.
22122
+ - For SHORT, Asia-session long-flush setups are watch-only when CMC fear/greed and market breadth are already in capitulation.
22123
+ - If benchmark derivatives data is missing or stale while CMC fear/greed is in stress mode, keep the flip in watch mode; neutral/unknown derivatives are not confirmation in that state.
21752
22124
  - The defensive live gate requires rewardToVolatility >= 8 when that field is available.
22125
+ - If BNB reference 1h open interest is expanding over the last 4h, keep TrendShift flips in watch mode; this is a defensive cross-market risk cut, not target-symbol evidence.
21753
22126
  - For LONG, BTC-led or risk-off BTC/alt regime is watch-only even when flip geometry is q5-strong.
22127
+ - For LONG, broad-market squeeze clusters are watch-only when breadth is already extreme, BTC is leading alts, and benchmark derivatives show a short flush.
21754
22128
  - If CMC major-exchange liquidity 24h change is in the historically choppy bands (-0.1, 0) or [0.1, 0.3), keep the flip in watch mode.
21755
22129
  - A narrow q4 recovery is allowed during the US closing window only when the sole blocker is missing OI expansion on an otherwise liquidation-supported US-session flush.
21756
- - A narrow SHORT q4 recovery may pass during a market breadth shock only when marketBreadthReturn <= -0.0112952 and 1h liqShort <= 0.208; this does not override the low-Bollinger-width defensive cut.
22130
+ - A narrow SHORT q4 recovery may pass during a market breadth shock only when marketBreadthReturn <= -0.0112952 and 1h liqShort <= 0.208; this does not override existing hard blockers or the low-Bollinger-width defensive cut.
21757
22131
  - A narrow LONG q4 recovery may pass only when alt leadership is clear (btcVsAltReturn24h <= -0.00503054 and btcVsAltReturn1h <= -0.00581403), fear/greed is not falling hard, and the only blockers are the tested OI/benchmark-derivatives or defensive reward-to-volatility blockers.
21758
22132
  - If hardBlockReasons is not empty, explain exactly what is still missing for confirmation.
21759
22133
  `.trim();
@@ -22069,6 +22443,9 @@ var TRENDLINE_PAYLOAD_PROMPT = `
22069
22443
  - It also includes 'atrPct / breakVsAtrRatio / coinMaSpreadPct / btcMaSpreadPct / aggressivePreBreakPressure / strongNearBreakPressure / weakCleanBreak / compressedCleanBreak / weakBtcLedBreak / weakLongFarBreak'.
22070
22444
  - If 'payload.additionalIndicators.baseContext.derivatives' exists, it contains Coinalyze-derived open interest, funding, and liquidation fields for the signal moment; do not treat 'stale' or 'missing_derivatives' as confirmation or conflict.
22071
22445
  `;
22446
+ var MARKET_CONTEXT_PRIMARY_ISSUE = "market_context_against";
22447
+ var MARKET_CONTEXT_TOTAL_MARKET_CAP_USD_MIN = 233e10;
22448
+ var MARKET_CONTEXT_TREND_PERSISTENCE_MAX = 0.77;
22072
22449
  var getRecord2 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
22073
22450
  var getNestedRecord3 = (source, path) => {
22074
22451
  let current = source;
@@ -22144,6 +22521,22 @@ var buildTrendlineContext = (signal) => {
22144
22521
  const volumeStructurePocIndex = toFiniteNumberOrNull5(
22145
22522
  participationVolumeStructure?.pocIndex
22146
22523
  );
22524
+ const gateDecisionHints = getNestedRecord3(baseContext, [
22525
+ "gateFeatures",
22526
+ "decisionHints"
22527
+ ]);
22528
+ const gatePrimaryIssue = typeof gateDecisionHints?.primaryIssue === "string" ? gateDecisionHints.primaryIssue : null;
22529
+ const cmcGlobalContext = getNestedRecord3(baseContext, [
22530
+ "relative",
22531
+ "cmcGlobal"
22532
+ ]);
22533
+ const cmcTotalMarketCapUsd = toFiniteNumberOrNull5(
22534
+ cmcGlobalContext?.totalMarketCapUsd
22535
+ );
22536
+ const trendRegimeContext = getNestedRecord3(baseContext, ["regime", "trend"]);
22537
+ const trendPersistence = toFiniteNumberOrNull5(
22538
+ trendRegimeContext?.persistence
22539
+ );
22147
22540
  const benchmarkTrendAlignment = typeof benchmarkContext?.trendAlignment === "string" ? benchmarkContext.trendAlignment : null;
22148
22541
  const executionContext = getNestedRecord3(baseContext, [
22149
22542
  "relative",
@@ -22195,7 +22588,7 @@ var buildTrendlineContext = (signal) => {
22195
22588
  if (structural.signalDirection === "SHORT" && (entryTiming === "ready_follow_through" || entryTiming === "ready_retest") && (sessionPrimary === "off_hours" || sessionIsOverlap) && !hardBlockReasons.includes("short_session_risk")) {
22196
22589
  hardBlockReasons.push("short_session_risk");
22197
22590
  }
22198
- const deterministicQuality = getDeterministicTrendlineQuality({
22591
+ const baseDeterministicQuality = getDeterministicTrendlineQuality({
22199
22592
  signalDirection: structural.signalDirection,
22200
22593
  clearBreak: structural.clearBreak,
22201
22594
  nearLineNoise: structural.nearLineNoise,
@@ -22210,16 +22603,18 @@ var buildTrendlineContext = (signal) => {
22210
22603
  entryTiming,
22211
22604
  coinMaSpreadPct
22212
22605
  });
22606
+ const marketContextApprovalPocket = gatePrimaryIssue === MARKET_CONTEXT_PRIMARY_ISSUE && cmcTotalMarketCapUsd != null && cmcTotalMarketCapUsd >= MARKET_CONTEXT_TOTAL_MARKET_CAP_USD_MIN && trendPersistence != null && trendPersistence <= MARKET_CONTEXT_TREND_PERSISTENCE_MAX;
22607
+ const deterministicQuality = marketContextApprovalPocket ? 4 : baseDeterministicQuality;
22213
22608
  const maxAllowedQuality = deterministicQuality;
22214
22609
  const longUsLowVolumeCrowdedShortSqueeze = structural.signalDirection === "LONG" && sessionPrimary === "us" && volumeRel20 != null && volumeRel20 < 0.8 && derivativesRiskFlags.includes("crowded_short") && benchmarkTrendAlignment !== "against_benchmark";
22215
22610
  const longHistoricalApprovalPocket = venueSpreadZScore != null && venueSpreadZScore <= -1 || longUsLowVolumeCrowdedShortSqueeze || sessionPrimary !== "europe" && !derivativesRiskFlags.includes("missing_derivatives") && !(structural.breakVsAtrRatio != null && structural.breakVsAtrRatio >= 0.8 && structural.breakVsAtrRatio < 1.2) && volumeRel20 != null && volumeRel20 >= 0.8 && benchmarkTrendAlignment !== "against_benchmark";
22216
- const longHighQualitySessionApproval = deterministicQuality >= 5 && sessionPrimary !== "asia";
22611
+ const longHighQualitySessionApproval = baseDeterministicQuality >= 5 && sessionPrimary !== "asia";
22217
22612
  const longStrongDerivativesAlignedApproval = volumeRel20 != null && volumeRel20 >= 1.5 && derivativesDirectionAligned === true;
22218
- const longModerateRetestLiquidSessionApproval = structural.signalDirection === "LONG" && deterministicQuality === 4 && entryTiming === "ready_retest" && (sessionPrimary === "us" || sessionPrimary === "europe") && volumeRel20 != null && volumeRel20 >= 0.8 && volumeRel20 < 1.5 && benchmarkTrendAlignment !== "against_benchmark" && derivativesDirectionAligned == null && derivativesRiskFlags.length > 0 && !oiNotConfirming;
22613
+ const longModerateRetestLiquidSessionApproval = structural.signalDirection === "LONG" && baseDeterministicQuality === 4 && entryTiming === "ready_retest" && (sessionPrimary === "us" || sessionPrimary === "europe") && volumeRel20 != null && volumeRel20 >= 0.8 && volumeRel20 < 1.5 && benchmarkTrendAlignment !== "against_benchmark" && derivativesDirectionAligned == null && derivativesRiskFlags.length > 0 && !oiNotConfirming;
22219
22614
  const longBaseContextApprovalPocket = structural.signalDirection !== "LONG" || longModerateRetestLiquidSessionApproval || longHistoricalApprovalPocket && (longHighQualitySessionApproval || longStrongDerivativesAlignedApproval);
22220
22615
  const shortThinNeutralBenchmarkRisk = structural.signalDirection === "SHORT" && volumeRel20 != null && volumeRel20 < 0.8 && benchmarkTrendAlignment === "neutral";
22221
- const q4ReferenceOiPocApproval = deterministicQuality === 4 && volumeStructurePocIndex != null && volumeStructurePocIndex >= 5 && ethReferenceOiAcceleration != null && ethReferenceOiAcceleration <= -0.5906;
22222
- const approvalAllowedNow = deterministicQuality >= 4 && longBaseContextApprovalPocket && !shortThinNeutralBenchmarkRisk && (deterministicQuality >= 5 || q4ReferenceOiPocApproval);
22616
+ const q4ReferenceOiPocApproval = baseDeterministicQuality === 4 && volumeStructurePocIndex != null && volumeStructurePocIndex >= 5 && ethReferenceOiAcceleration != null && ethReferenceOiAcceleration <= -0.5906;
22617
+ const approvalAllowedNow = marketContextApprovalPocket;
22223
22618
  const trendLineGateFeatures = buildTrendLineGateFeatures({
22224
22619
  structural,
22225
22620
  entryTiming,
@@ -22255,6 +22650,11 @@ var buildTrendlineContext = (signal) => {
22255
22650
  derivativesRiskFlags,
22256
22651
  ethReferenceOiAcceleration,
22257
22652
  oiNotConfirming,
22653
+ gatePrimaryIssue,
22654
+ cmcTotalMarketCapUsd,
22655
+ trendPersistence,
22656
+ marketContextApprovalPocket,
22657
+ baseDeterministicQuality,
22258
22658
  longUsLowVolumeCrowdedShortSqueeze,
22259
22659
  longHighQualitySessionApproval,
22260
22660
  longStrongDerivativesAlignedApproval,
@@ -22504,6 +22904,11 @@ Additional TrendLine context:
22504
22904
  - trendline.volumeStructurePocIndex=${formatPromptNumber(trendlineContext.volumeStructurePocIndex, 0)}
22505
22905
  - trendline.ethReferenceOiAcceleration=${formatPromptNumber(trendlineContext.ethReferenceOiAcceleration, 3)}
22506
22906
  - trendline.q4ReferenceOiPocApproval=${String(trendlineContext.q4ReferenceOiPocApproval)}
22907
+ - trendline.gatePrimaryIssue=${trendlineContext.gatePrimaryIssue ?? "n/a"}
22908
+ - trendline.cmcTotalMarketCapUsd=${formatPromptNumber(trendlineContext.cmcTotalMarketCapUsd, 0)}
22909
+ - trendline.trendPersistence=${formatPromptNumber(trendlineContext.trendPersistence, 3)}
22910
+ - trendline.marketContextApprovalPocket=${String(trendlineContext.marketContextApprovalPocket)}
22911
+ - trendline.baseDeterministicQuality=${String(trendlineContext.baseDeterministicQuality)}
22507
22912
  - trendline.weakCleanBreak=${String(trendlineContext.weakCleanBreak)}
22508
22913
  - trendline.compressedCleanBreak=${String(trendlineContext.compressedCleanBreak)}
22509
22914
  - trendline.weakBtcLedBreak=${String(trendlineContext.weakBtcLedBreak)}
@@ -22782,10 +23187,13 @@ VolumeDivergence addon:
22782
23187
  `;
22783
23188
  var VOLUME_DIVERGENCE_PAYLOAD_PROMPT = `
22784
23189
  - \`payload.additionalIndicators.volumeDivergenceContext\` contains a compact divergence-strength summary:
22785
- divergenceKind / confirmationPrice / confirmationReady / structureAdvanced / reboundFromPivotPct / confirmationDistancePct / priceDisplacementPct / divergenceAmplitudeAtrRatio / reclaimPct / confirmationCandleQuality / volumeDivergenceStrength / deltaAligned / coinBiasAligned / btcBiasAligned / derivativesDirectionAligned / derivativesRiskFlags / derivativesLiqSpikeRatio / venueSpreadZScore / volumeRel20 / rangePosition20 / deterministicQuality / approvalAllowedNow / structuralHardBlockReasons / maxAllowedQuality.
23190
+ divergenceKind / confirmationPrice / confirmationReady / structureAdvanced / reboundFromPivotPct / confirmationDistancePct / priceDisplacementPct / divergenceAmplitudeAtrRatio / reclaimPct / confirmationCandleQuality / volumeDivergenceStrength / deltaAligned / coinBiasAligned / btcBiasAligned / derivativesDirectionAligned / derivativesRiskFlags / derivativesLiqSpikeRatio / venueSpreadZScore / volumeRel20 / rangePosition20 / btcOiChangePct1h15m / solOpenInterest15m / xrpFundingZScore15m / derivativesRegimePocket / deterministicQuality / approvalAllowedNow / structuralHardBlockReasons / maxAllowedQuality.
22786
23191
  - Use this context as the explicit strategy-specific summary instead of trying to derive the same conclusion again only from generic candles.
22787
23192
  - If \`payload.additionalIndicators.baseContext.derivatives\` exists, it is a Coinalyze-derived summary of derivatives state at signal time; \`stale\` or \`missing_derivatives\` means that Coinalyze context must not be used.
22788
23193
  `;
23194
+ var BTC_OI_CHANGE_PCT_1H_15M_MAX = -0.32;
23195
+ var SOL_OPEN_INTEREST_15M_MIN = 101e5;
23196
+ var XRP_FUNDING_Z_SCORE_15M_MAX = -1.2;
22789
23197
  var toFiniteNumberOrNull6 = (value) => {
22790
23198
  if (typeof value === "number" && Number.isFinite(value)) {
22791
23199
  return value;
@@ -23152,6 +23560,23 @@ var getVolumeDivergenceContext = (signal) => {
23152
23560
  const derivativesRiskFlags = getStringArray3(derivativesSummary?.riskFlags);
23153
23561
  const derivativesFundingZScore = toFiniteNumberOrNull6(derivatives15m?.fundingZScore) ?? toFiniteNumberOrNull6(derivatives1h?.fundingZScore);
23154
23562
  const derivativesLiqSpikeRatio = toFiniteNumberOrNull6(derivatives15m?.liqSpikeRatio) ?? toFiniteNumberOrNull6(derivatives1h?.liqSpikeRatio);
23563
+ const btcOiChangePct1h15m = toFiniteNumberOrNull6(
23564
+ derivatives15m?.oiChangePct1h
23565
+ );
23566
+ const solOpenInterest15m = getNestedNumber3(derivativesContext, [
23567
+ "referenceContexts",
23568
+ "SOLUSDT",
23569
+ "intervals",
23570
+ "15m",
23571
+ "openInterest"
23572
+ ]);
23573
+ const xrpFundingZScore15m = getNestedNumber3(derivativesContext, [
23574
+ "referenceContexts",
23575
+ "XRPUSDT",
23576
+ "intervals",
23577
+ "15m",
23578
+ "fundingZScore"
23579
+ ]);
23155
23580
  const marketContext = getRecord3(additional?.marketContext);
23156
23581
  const venueSpreadZScore = getNestedNumber3(marketContext, [
23157
23582
  "execution",
@@ -23251,9 +23676,9 @@ var getVolumeDivergenceContext = (signal) => {
23251
23676
  entryThresholds,
23252
23677
  aiThresholds
23253
23678
  }) : hardBlockReasons.length > 0 ? 2 : 3;
23254
- const longApprovalPocket = signalDirection !== "LONG" || isAtLeast2(confirmationDistancePct, 2) && isAtLeast2(volumeRel20, 1) && isAtLeast2(venueSpreadZScore, 1.5365);
23255
- const shortApprovalPocket = signalDirection !== "SHORT" || isAtMost(venueSpreadZScore, 0) && rangePosition20 != null && rangePosition20 < 0.2;
23256
- const approvalAllowedNow = hardBlockReasons.length === 0 && deterministicQuality >= 4 && confirmationReady && longApprovalPocket && shortApprovalPocket;
23679
+ const derivativesRegimePocket = isAtMost(btcOiChangePct1h15m, BTC_OI_CHANGE_PCT_1H_15M_MAX) && isAtLeast2(solOpenInterest15m, SOL_OPEN_INTEREST_15M_MIN) && isAtMost(xrpFundingZScore15m, XRP_FUNDING_Z_SCORE_15M_MAX);
23680
+ const maxAllowedQuality = derivativesRegimePocket ? Math.max(deterministicQuality, 4) : deterministicQuality;
23681
+ const approvalAllowedNow = hardBlockReasons.length === 0 && confirmationReady && derivativesRegimePocket && maxAllowedQuality >= 4;
23257
23682
  return {
23258
23683
  signalDirection,
23259
23684
  divergenceKind,
@@ -23286,12 +23711,16 @@ var getVolumeDivergenceContext = (signal) => {
23286
23711
  venueSpreadZScore,
23287
23712
  volumeRel20,
23288
23713
  rangePosition20,
23714
+ btcOiChangePct1h15m,
23715
+ solOpenInterest15m,
23716
+ xrpFundingZScore15m,
23717
+ derivativesRegimePocket,
23289
23718
  sessionPhase,
23290
23719
  hardBlockReasons,
23291
23720
  structuralHardBlockReasons: [...hardBlockReasons],
23292
23721
  deterministicQuality,
23293
23722
  approvalAllowedNow,
23294
- maxAllowedQuality: deterministicQuality
23723
+ maxAllowedQuality
23295
23724
  };
23296
23725
  };
23297
23726
  var getVolumeDivergenceContextFromPayload = (payload, signal) => {
@@ -23342,6 +23771,7 @@ var postProcessAnalysis2 = ({
23342
23771
  );
23343
23772
  const needRetest = finalDirection == null;
23344
23773
  const retestPrice = needRetest ? context.confirmationPrice : null;
23774
+ const approvedQuality = finalDirection != null && context.maxAllowedQuality >= 4 ? Math.max(finalQuality, 4) : finalQuality;
23345
23775
  if (finalDirection == null) {
23346
23776
  return {
23347
23777
  ...analysis,
@@ -23359,7 +23789,7 @@ var postProcessAnalysis2 = ({
23359
23789
  return {
23360
23790
  ...analysis,
23361
23791
  direction: finalDirection,
23362
- quality: finalQuality,
23792
+ quality: approvedQuality,
23363
23793
  needRetest,
23364
23794
  retestPrice,
23365
23795
  takeProfitPrice: signal.prices?.takeProfitPrice ?? null,
@@ -23405,6 +23835,10 @@ Additional VolumeDivergence context:
23405
23835
  - venueSpreadZScore=${context.venueSpreadZScore?.toFixed?.(3) ?? "n/a"}
23406
23836
  - volumeRel20=${context.volumeRel20?.toFixed?.(3) ?? "n/a"}
23407
23837
  - rangePosition20=${context.rangePosition20?.toFixed?.(3) ?? "n/a"}
23838
+ - btcOiChangePct1h15m=${context.btcOiChangePct1h15m?.toFixed?.(3) ?? "n/a"}
23839
+ - solOpenInterest15m=${context.solOpenInterest15m?.toFixed?.(0) ?? "n/a"}
23840
+ - xrpFundingZScore15m=${context.xrpFundingZScore15m?.toFixed?.(3) ?? "n/a"}
23841
+ - derivativesRegimePocket=${context.derivativesRegimePocket}
23408
23842
  - barsSincePivot=${context.barsSincePivot ?? "n/a"}
23409
23843
  - barsBetweenPivotConfirmations=${context.barsBetweenPivotConfirmations ?? "n/a"}
23410
23844
  - entryTiming=${context.entryTiming ?? "n/a"}