Files
trading_bot_v4/INDICATOR_V9_MA_GAP_ROADMAP.md
mindesbunister ff92e7b78c feat(v9): Complete MA gap backend integration
Integrated MA gap analysis into signal quality evaluation pipeline:

BACKEND SCORING (lib/trading/signal-quality.ts):
- Added maGap?: number parameter to scoreSignalQuality interface
- Implemented convergence/divergence scoring logic:
  * LONG: +15pts tight bullish (0-2%), +12pts converging (-2-0%), +8pts early momentum (-5--2%)
  * SHORT: +15pts tight bearish (-2-0%), +12pts converging (0-2%), +8pts early momentum (2-5%)
  * Penalties: -5pts for misaligned MA structure (>5% wrong direction)

N8N PARSER (workflows/trading/parse_signal_enhanced.json):
- Added MAGAP:([-\d.]+) regex pattern for negative number support
- Extracts maGap from TradingView v9 alert messages
- Returns maGap in parsed output (backward compatible with v8)
- Updated comment to show v9 format

API ENDPOINTS:
- app/api/trading/check-risk/route.ts: Pass maGap to scoreSignalQuality (2 calls)
- app/api/trading/execute/route.ts: Pass maGap to scoreSignalQuality (2 calls)

FULL PIPELINE NOW COMPLETE:
1. TradingView v9 → Generates signal with MAGAP field
2. n8n webhook → Extracts maGap from alert message
3. Backend scoring → Evaluates MA gap convergence (+8 to +15 pts)
4. Quality threshold → Borderline signals (75-85) can reach 91+
5. Execute decision → Only signals scoring ≥91 are executed

MOTIVATION:
Helps borderline quality signals reach execution threshold without overriding
safety rules. Addresses Nov 25 missed opportunity where good signal had MA
convergence but borderline quality score.

TESTING REQUIRED:
- Verify n8n parses MAGAP correctly from v9 alerts
- Confirm backend receives maGap parameter
- Validate MA gap scoring applied to quality calculation
- Monitor first 10-20 v9 signals for scoring accuracy
2025-11-26 10:50:25 +01:00

12 KiB

Indicator v9: MA Gap Quality Enhancement

Status: 📋 PLANNED
Priority: HIGH (addresses $380 missed profit from Nov 25 blocked signal)
Motivation: v8 indicator catches trend changes BEFORE classic MA crossovers, but quality filter blocks these early signals


Problem Statement

Real Incident (Nov 25, 2025 21:15 UTC):

  • v8 generated LONG signal at $136.91 (quality 75, ADX 17.9)
  • Signal BLOCKED by quality threshold (75 < 90 required for LONGs)
  • Chart showed 50 MA converging toward 200 MA (gap ≈ -1% to 0%)
  • Golden cross occurred a few bars AFTER entry signal
  • Price moved to $142+ = $380 missed profit (~4% move)

Key Insight:

  • v8 indicator is BETTER than MA crossover timing - catches moves earlier
  • BUT quality filter doesn't recognize when MAs are positioned for breakout
  • Need to reward MA convergence/proximity, not just crossover events

v9 Enhancement: MA Gap Analysis

Core Concept

Instead of detecting exact crossover moment (lagging), measure MA gap percentage:

  • Tight gap (0-2%) = Strong trend with momentum or imminent crossover
  • Converging gap (-2% to 0%) = Potential golden cross brewing
  • Wide gap (>2%) = Established trend, less explosive but stable

TradingView Indicator Changes

Add after context metrics calculation (~line 221):

// ═══════════════════════════════════════════════════════════
// 🎯 MA GAP ANALYSIS (v9 - for quality scoring)
// ═══════════════════════════════════════════════════════════

// Calculate 50 and 200 period moving averages
ma50 = ta.sma(calcC, 50)
ma200 = ta.sma(calcC, 200)

// Calculate MA gap as percentage (negative = 50 below 200)
maGap = ((ma50 - ma200) / ma200) * 100

// Detect convergence (MAs getting closer = potential crossover)
maConverging = math.abs(maGap) < 2.0  // Within 2% = tight squeeze

// Current alignment
maAlignmentBullish = ma50 > ma200

// Optional: Plot MAs on chart for visual confirmation
plot(ma50, title="MA 50", color=color.yellow, linewidth=1)
plot(ma200, title="MA 200", color=color.red, linewidth=1)

Update alert messages (~lines 257-258):

longAlertMsg = baseCurrency + " buy " + timeframe.period + " | ATR:" + str.tostring(atrPercent, "#.##") + " | ADX:" + str.tostring(adxVal, "#.#") + " | RSI:" + str.tostring(rsi14, "#.#") + " | VOL:" + str.tostring(volumeRatio, "#.##") + " | POS:" + str.tostring(pricePosition, "#.#") + " | MAGAP:" + str.tostring(maGap, "#.##") + " | IND:v9"

shortAlertMsg = baseCurrency + " sell " + timeframe.period + " | ATR:" + str.tostring(atrPercent, "#.##") + " | ADX:" + str.tostring(adxVal, "#.#") + " | RSI:" + str.tostring(rsi14, "#.#") + " | VOL:" + str.tostring(volumeRatio, "#.##") + " | POS:" + str.tostring(pricePosition, "#.#") + " | MAGAP:" + str.tostring(maGap, "#.##") + " | IND:v9"

Backend Quality Scoring Changes

Update scoreSignalQuality() function

File: lib/trading/signal-quality.ts

Add parameters:

export async function scoreSignalQuality(params: {
  // ... existing params ...
  maGap?: number            // NEW: % gap between 50 and 200 MA
  maAlignmentBullish?: boolean  // NEW: is 50 above 200?
}): Promise<SignalQualityResult> {

Add scoring logic (after existing metrics):

// ═══════════════════════════════════════════════════════════
// MA Gap Analysis (v9 - Nov 26, 2025)
// ═══════════════════════════════════════════════════════════

if (params.maGap !== undefined) {
  if (params.direction === 'long') {
    // LONG scenarios
    if (params.maGap >= 0 && params.maGap < 2.0) {
      // 50 MA above 200 MA, tight gap (0-2%)
      // = Bullish trend with momentum OR fresh golden cross
      score += 15
      reasons.push(`🎯 MA bullish + tight gap (${params.maGap.toFixed(2)}%) = strong momentum (+15 pts)`)
      
    } else if (params.maGap < 0 && params.maGap > -2.0) {
      // 50 MA below 200 MA but converging (-2% to 0%)
      // = Potential golden cross brewing (early detection like Nov 25 signal!)
      score += 12
      reasons.push(`🌟 MA converging (${params.maGap.toFixed(2)}%) = golden cross potential (+12 pts)`)
      
    } else if (params.maGap >= 2.0 && params.maGap < 5.0) {
      // 50 MA well above 200 MA (2-5%)
      // = Established bullish trend, stable but less explosive
      score += 8
      reasons.push(`📈 MA strong bullish trend (${params.maGap.toFixed(2)}%) (+8 pts)`)
      
    } else if (params.maGap >= 5.0) {
      // 50 MA far above 200 MA (>5%)
      // = Very extended, potential exhaustion
      score += 5
      reasons.push(`⚠️ MA extended bullish (${params.maGap.toFixed(2)}%) = overbought risk (+5 pts)`)
      
    } else if (params.maGap <= -2.0) {
      // 50 MA significantly below 200 MA
      // = Bearish trend, LONG signal is counter-trend (risky)
      score -= 10
      reasons.push(`❌ MA bearish divergence (${params.maGap.toFixed(2)}%) = counter-trend risk (-10 pts)`)
    }
    
  } else if (params.direction === 'short') {
    // SHORT scenarios (inverse of LONG logic)
    if (params.maGap <= 0 && params.maGap > -2.0) {
      // 50 MA below 200 MA, tight gap (-2% to 0%)
      // = Bearish trend with momentum OR fresh death cross
      score += 15
      reasons.push(`🎯 MA bearish + tight gap (${params.maGap.toFixed(2)}%) = strong momentum (+15 pts)`)
      
    } else if (params.maGap > 0 && params.maGap < 2.0) {
      // 50 MA above 200 MA but converging (0% to 2%)
      // = Potential death cross brewing
      score += 12
      reasons.push(`🌟 MA converging (${params.maGap.toFixed(2)}%) = death cross potential (+12 pts)`)
      
    } else if (params.maGap <= -2.0 && params.maGap > -5.0) {
      // 50 MA well below 200 MA (-5% to -2%)
      // = Established bearish trend
      score += 8
      reasons.push(`📉 MA strong bearish trend (${params.maGap.toFixed(2)}%) (+8 pts)`)
      
    } else if (params.maGap <= -5.0) {
      // 50 MA far below 200 MA (<-5%)
      // = Very extended, potential bounce risk
      score += 5
      reasons.push(`⚠️ MA extended bearish (${params.maGap.toFixed(2)}%) = oversold risk (+5 pts)`)
      
    } else if (params.maGap >= 2.0) {
      // 50 MA significantly above 200 MA
      // = Bullish trend, SHORT signal is counter-trend (risky)
      score -= 10
      reasons.push(`❌ MA bullish divergence (${params.maGap.toFixed(2)}%) = counter-trend risk (-10 pts)`)
    }
  }
}

Expected Impact

Nov 25 21:15 Signal Reanalysis

Original (v8):

  • Quality: 75 (blocked)
  • ADX: 17.9 (weak)
  • MA Gap: ≈ -1.0% (50 below 200, converging)

With v9 MA Gap Enhancement:

  • Base quality: 75
  • MA converging bonus: +12
  • New quality: 87 (closer but still blocked)

Note: Would still need ADX improvement OR slightly lower threshold (88-89?) to catch this specific signal. But the +12 points get us much closer and would catch signals with ADX 18-20.

Alternative Scenarios

Scenario A: MA Gap -0.5% (very tight convergence)

  • Quality 75 + 12 = 87 (close)

Scenario B: MA Gap +0.5% (just crossed, tight)

  • Quality 75 + 15 = 90 PASSES!

Scenario C: MA Gap +1.8% (recent golden cross, momentum strong)

  • Quality 75 + 15 = 90 PASSES!

Implementation Checklist

Phase 1: TradingView Indicator

  • Add MA50 and MA200 calculations
  • Calculate maGap percentage
  • Add maGap to alert message payload
  • Optional: Plot MA lines on chart
  • Update indicatorVer from "v8" to "v9"
  • Test on SOL-PERP 5min chart

Phase 2: Backend Integration

  • Update TypeScript interfaces for maGap parameter
  • Modify scoreSignalQuality() with MA gap logic
  • Update check-risk endpoint to accept maGap
  • Update execute endpoint to accept maGap
  • Add maGap to database fields (Trade table, BlockedSignal table)

Phase 3: Testing & Validation

  • Deploy v9 indicator to TradingView
  • Trigger test signals manually
  • Verify maGap calculation matches chart visual
  • Check quality scores increase appropriately
  • Monitor first 20-30 signals for validation

Phase 4: Data Collection

  • Collect 50+ v9 signals
  • Compare v8 vs v9 win rates
  • Analyze: Did MA gap bonus catch missed winners?
  • SQL queries to validate improvement
  • Adjust bonus points if needed (12/15 → 10/12 or 15/18)

Success Metrics

Target Improvements:

  1. Catch signals like Nov 25 21:15: Quality 75 + MA converging → 87-90 range
  2. Reduce false negatives: Fewer blocked signals that would have been winners
  3. Maintain safety: Don't add too many low-quality signals
  4. Win rate: v9 should maintain or improve v8's 57.1% WR

Validation Queries:

-- Compare v9 MA gap bonus impact
SELECT 
  CASE 
    WHEN "signalQualityScore" >= 90 THEN 'Passed'
    WHEN "signalQualityScore" >= 80 THEN 'Close (80-89)'
    ELSE 'Blocked (<80)'
  END as category,
  COUNT(*) as signals,
  AVG("scoreBreakdown"->>'maGap')::numeric as avg_ma_gap
FROM "BlockedSignal"
WHERE "indicatorVersion" = 'v9'
  AND "scoreBreakdown"->>'maGap' IS NOT NULL
GROUP BY category;

-- Find signals that would pass with v9 but were blocked in v8
SELECT 
  TO_CHAR("createdAt", 'MM-DD HH24:MI') as time,
  symbol, direction,
  "signalQualityScore" as original_score,
  -- Simulate v9 score (add 12 for converging, 15 for tight)
  CASE 
    WHEN ("scoreBreakdown"->>'maGap')::numeric >= 0 AND ("scoreBreakdown"->>'maGap')::numeric < 2.0 
      THEN "signalQualityScore" + 15
    WHEN ("scoreBreakdown"->>'maGap')::numeric < 0 AND ("scoreBreakdown"->>'maGap')::numeric > -2.0 
      THEN "signalQualityScore" + 12
    ELSE "signalQualityScore"
  END as v9_score,
  "blockReason"
FROM "BlockedSignal"
WHERE "signalQualityScore" < 90  -- Was blocked
  AND "indicatorVersion" = 'v8'
ORDER BY "createdAt" DESC
LIMIT 20;

Risk Mitigation

Potential Issues

  1. MA calculation lag: 200-period MA requires significant history

    • Mitigation: TradingView has full history, no issue
  2. Whipsaw during sideways markets: MAs converge often in chop

    • Mitigation: ADX filter still applies (weak ADX = less bonus effect)
  3. Over-optimization on single signal: Nov 25 may be outlier

    • Mitigation: Collect 50+ v9 signals before final judgment
  4. Bonus points too generous: Could inflate scores artificially

    • Mitigation: Start conservative (12/15), adjust based on data

Rollback Plan

If v9 performs worse than v8:

  1. Revert TradingView indicator to v8
  2. Keep backend code but disable MA gap bonus
  3. Analyze what went wrong (false positives? whipsaw signals?)
  4. Redesign MA gap logic with tighter conditions

Timeline

Estimated Implementation Time:

  • TradingView changes: 30 minutes
  • Backend integration: 1 hour
  • Testing & deployment: 30 minutes
  • Total: ~2 hours

Data Collection:

  • Minimum 50 signals: 2-3 weeks (at ~3-5 signals/day)
  • Comparative analysis: 1 week after 50 signals

Decision Point:

  • After 50 v9 signals: Keep, adjust, or revert based on performance data

Notes

  • This enhancement preserves v8's early detection advantage
  • Adds context awareness of MA positioning
  • Rewards both imminent crossovers (converging) AND fresh crossovers (tight gap)
  • Balances explosive potential (tight gaps) with trend stability (wider gaps)
  • Counter-trend penalties prevent chasing wrong direction

Key Insight: v8 catches momentum shifts BEFORE visible MA crossovers. v9 validates those shifts by checking if MA structure supports the move.


Created: Nov 26, 2025
Motivation: $380 missed profit from Nov 25 21:15 blocked signal
Expected Impact: Catch 15-25% more profitable signals while maintaining quality standards