Files
trading_bot_v4/SIGNAL_QUALITY_OPTIMIZATION_ROADMAP.md
mindesbunister d309eb783c docs: Update roadmaps with v8 indicator progress
- Added v8 Money Line indicator status to master roadmap
- Updated signal quality roadmap with v8 deployment (Nov 18)
- Ready for live testing and v6 vs v8 comparison
- Awaiting first signals with indicatorVersion='v8' tracking
2025-11-18 14:10:06 +01:00

20 KiB
Raw Blame History

Signal Quality Optimization Roadmap

Goal: Optimize signal quality thresholds and scoring logic using data-driven analysis

Current Status: Phase 1 - Data Collection + v8 Indicator Testing (Active)
Last Updated: November 18, 2025

🚀 NEW: v8 Money Line Indicator Deployed (Nov 18, 2025)

  • Sticky trend detection with 0.8% flip threshold + momentum confirmation
  • Awaiting first live signals for performance comparison vs v6
  • Will enable A/B testing: v6 (filtered) vs v8 (sticky flips)

Overview

This roadmap guides the systematic improvement of signal quality filtering. We follow a data-first approach: collect evidence, analyze patterns, then make changes. No premature optimization.

Current System

  • Quality Score Threshold: 65 points (recently raised from 60)
  • Executed Trades: 157 total (155 closed, 2 open)
  • Performance: +$3.43 total P&L, 44.5% win rate
  • Score Distribution:
    • 80-100 (Excellent): 49 trades, +$46.48, 46.9% WR
    • 70-79 (Good): 15 trades, -$2.20, 40.0% WR ⚠️
    • 65-69 (Pass): 13 trades, +$28.28, 53.8% WR
    • 60-64 (Just Below): 2 trades, +$45.78, 100% WR 🔥
    • 0-49 (Very Weak): 13 trades, -$127.89, 30.8% WR 💀

Phase 1: Data Collection (CURRENT) IN PROGRESS

Status: Infrastructure complete, collecting data
Started: November 11, 2025
Target: Collect 10-20 blocked signals (1-2 weeks)

Completed (Nov 11, 2025)

  • Created BlockedSignal database table
  • Implemented automatic saving in check-risk endpoint
  • Deployed to production (trading-bot-v4 container)
  • Created tracking documentation (BLOCKED_SIGNALS_TRACKING.md)

What's Being Tracked

Every blocked signal captures:

  • Metrics: ATR, ADX, RSI, volume ratio, price position, timeframe
  • Score: Quality score (0-100), version, detailed breakdown
  • Block Reason: Quality score, cooldown, hourly limit, daily drawdown
  • Context: Symbol, direction, price at signal time, timestamp

What We're Looking For

  1. How many signals score 60-64 (just below threshold)?
  2. What are their characteristics (ADX, ATR, price position)?
  3. Are there patterns (extreme positions, specific timeframes)?
  4. Do they cluster around specific block reasons?

Phase 1 Completion Criteria

  • Minimum 10 blocked signals with quality scores 55-64
  • At least 2 signals in 60-64 range (close calls)
  • Mix of block reasons (not all quality score)
  • Data spans multiple market conditions (trending, choppy, volatile)

SQL Queries for Phase 1

-- Check progress
SELECT COUNT(*) as total_blocked 
FROM "BlockedSignal";

-- Score distribution
SELECT 
  CASE 
    WHEN signalQualityScore >= 60 THEN '60-64 (Close)'
    WHEN signalQualityScore >= 55 THEN '55-59 (Marginal)'
    WHEN signalQualityScore >= 50 THEN '50-54 (Weak)'
    ELSE '0-49 (Very Weak)'
  END as tier,
  COUNT(*) as count
FROM "BlockedSignal"
WHERE blockReason = 'QUALITY_SCORE_TOO_LOW'
GROUP BY tier
ORDER BY MIN(signalQualityScore) DESC;

Phase 1.5: Signal Frequency Penalties DEPLOYED Nov 14, 2025

Status: Production deployment complete (with critical bug fix)
Initial Commit: 111e3ed (07:28 CET)
Bug Fix Commit: 795026a (09:22 CET)
Container: trading-bot-v4

What Was Implemented

Real-time database analysis that detects overtrading and flip-flop patterns before trade execution.

Penalties Applied

  1. Overtrading (3+ signals in 30min): -20 points

    • Counts both executed trades AND blocked signals
    • Prevents excessive trading in consolidation zones
  2. Flip-flop with price context (opposite direction <15min): -25 points

    • NEW: Only applies if price moved <2% from opposite signal
    • Distinguishes chop from reversals
    • Example chop: $154.50 SHORT → $154.30 LONG (0.13% move) = blocked ⚠️
    • Example reversal: $170 SHORT → $153 LONG (10% move) = allowed
    • Blocks rapid long→short→long whipsaws in tight ranges
    • BUG FIX (795026a): Now uses Pyth price data for accurate calculations
    • Previous issue: showed "100% move" for 0.2% actual movement (allowed false flip-flop)
  3. Alternating pattern (last 3 trades): -30 points

    • Detects choppy market conditions
    • Pattern: long→short→long = chop detection

Technical Details

  • Function: getRecentSignals() in lib/database/trades.ts
  • Price source: Pyth price monitor via getPythPriceMonitor() in check-risk
  • Architecture: scoreSignalQuality() now async
  • Endpoints updated: check-risk, execute, reentry-check
  • Performance: Indexed queries, <10ms overhead
  • Validation: Logs "🔍 Flip-flop price check: $X → $Y = Z%" for debugging

Expected Impact

  • Eliminate tight-range flip-flops (Nov 14 chart: $141-145 SOL)
  • Reduce overtrading during sideways markets
  • Target: +5-10% win rate improvement
  • Better capital preservation in chop

Monitoring

Watch for detailed penalty and allowance messages in logs:

🔍 Flip-flop price check: $143.86 → $143.58 = 0.20%
⚠️ Overtrading zone: 3 signals in 30min (-20 pts)
⚠️ Flip-flop in tight range: 4min ago, only 0.20% move ($143.86 → $143.58) (-25 pts)
✅ Direction change after 10.0% move ($170.00 → $153.00, 12min ago) - reversal allowed
⚠️ Chop pattern: last 3 trades alternating (long → short → long) (-30 pts)

Known Issues Fixed

  • Nov 14, 06:05 CET: Initial deployment allowed 0.2% flip-flop due to incorrect price data
    • Trade: SHORT at $143.58 (should have been blocked)
    • Result: -$1.56 loss in 5 minutes
    • Fix deployed: 09:22 CET (795026a) - now uses Pyth price monitor

Validation Plan

  1. Monitor next 5-10 signals for accurate price calculations
  2. Verify penalties trigger with correct percentages
  3. Analyze if blocked signals would have lost
  4. If effective, proceed to Phase 6 (range compression)

Phase 2: Pattern Analysis 🔜 NEXT

Prerequisites: 10-20 blocked signals collected
Estimated Duration: 2-3 days
Owner: Manual analysis + SQL queries

Analysis Tasks

2.1: Score Distribution Analysis

-- Analyze blocked signals by score range
SELECT 
  CASE 
    WHEN signalQualityScore >= 60 THEN '60-64'
    WHEN signalQualityScore >= 55 THEN '55-59'
    ELSE '50-54'
  END as score_range,
  COUNT(*) as count,
  ROUND(AVG(atr)::numeric, 2) as avg_atr,
  ROUND(AVG(adx)::numeric, 1) as avg_adx,
  ROUND(AVG(pricePosition)::numeric, 1) as avg_price_pos,
  ROUND(AVG(volumeRatio)::numeric, 2) as avg_volume
FROM "BlockedSignal"
WHERE blockReason = 'QUALITY_SCORE_TOO_LOW'
GROUP BY score_range
ORDER BY MIN(signalQualityScore) DESC;

2.2: Compare with Executed Trades

-- Find executed trades with similar scores to blocked signals
SELECT 
  'Executed' as type,
  signalQualityScore,
  COUNT(*) as trades,
  ROUND(AVG(realizedPnL)::numeric, 2) as avg_pnl,
  ROUND(100.0 * SUM(CASE WHEN realizedPnL > 0 THEN 1 ELSE 0 END) / COUNT(*)::numeric, 1) as win_rate
FROM "Trade"
WHERE exitReason IS NOT NULL
  AND signalQualityScore BETWEEN 60 AND 69
GROUP BY signalQualityScore
ORDER BY signalQualityScore;

2.3: ADX Pattern Analysis

Key finding from existing data: ADX 20-25 is a trap zone!

-- ADX distribution in blocked signals
SELECT 
  CASE 
    WHEN adx >= 25 THEN 'Strong (25+)'
    WHEN adx >= 20 THEN 'Moderate (20-25)'
    WHEN adx >= 15 THEN 'Weak (15-20)'
    ELSE 'Very Weak (<15)'
  END as adx_tier,
  COUNT(*) as count,
  ROUND(AVG(signalQualityScore)::numeric, 1) as avg_score
FROM "BlockedSignal"
WHERE blockReason = 'QUALITY_SCORE_TOO_LOW'
  AND adx IS NOT NULL
GROUP BY adx_tier
ORDER BY MIN(adx) DESC;

2.4: Extreme Position Analysis

Test hypothesis: Extremes (<10% or >90%) need different thresholds

-- Blocked signals at range extremes
SELECT 
  direction,
  signalQualityScore,
  ROUND(pricePosition::numeric, 1) as pos,
  ROUND(adx::numeric, 1) as adx,
  ROUND(volumeRatio::numeric, 2) as vol
FROM "BlockedSignal"
WHERE blockReason = 'QUALITY_SCORE_TOO_LOW'
  AND (pricePosition < 10 OR pricePosition > 90)
ORDER BY signalQualityScore DESC;

Phase 2 Deliverables

  • Score distribution report
  • ADX pattern analysis
  • Extreme position analysis
  • Comparison with executed trades
  • DECISION: Keep threshold at 65, lower to 60, or implement dual-threshold system

Phase 3: Implementation (Conditional) 🎯 FUTURE

Trigger: Analysis shows clear pattern worth exploiting
Prerequisites: Phase 2 complete + statistical significance (15+ blocked signals)

IF data shows extreme positions (price <10% or >90%) with scores 60-64 are profitable:

Implementation:

// In check-risk endpoint
const isExtremePosition = pricePosition < 10 || pricePosition > 90
const requiredScore = isExtremePosition ? 60 : 65

if (qualityScore.score < requiredScore) {
  // Block signal
}

Changes Required:

  • app/api/trading/check-risk/route.ts - Add dual threshold logic
  • lib/trading/signal-quality.ts - Add isExtremePosition helper
  • config/trading.ts - Add minScoreForExtremes config option
  • Update AI instructions with new logic

Option B: ADX-Based Gates (Alternative)

IF data shows strong ADX trends (25+) with lower scores are profitable:

Implementation:

const requiredScore = adx >= 25 ? 60 : 65

Changes Required:

  • Similar to Option A but based on ADX threshold

Option C: Keep Current (If No Clear Pattern)

IF data shows no consistent profit opportunity in blocked signals:

  • No changes needed
  • Continue monitoring
  • Revisit in 20 more trades

Phase 3 Checklist

  • Decision made based on Phase 2 analysis
  • Code changes implemented
  • Updated signalQualityVersion to 'v5' in database
  • AI instructions updated
  • Tested with historical blocked signals
  • Deployed to production
  • Monitoring for 10 trades to validate improvement

Phase 4: Price Analysis Automation 🤖 FUTURE

Goal: Automatically track if blocked signals would have been profitable
Complexity: Medium - requires price monitoring job
Prerequisites: Phase 3 complete OR 50+ blocked signals collected

Architecture

Monitoring Job (runs every 30 min)
  ↓
  Fetch BlockedSignal records where:
    - analysisComplete = false
    - createdAt > 30 minutes ago
  ↓
  For each signal:
    - Get price history from Pyth/Drift
    - Calculate if TP1/TP2/SL would have been hit
    - Update priceAfter1Min/5Min/15Min/30Min
    - Set wouldHitTP1/TP2/SL flags
    - Mark analysisComplete = true
  ↓
  Save results back to database

Implementation Tasks

  • Create price history fetching service
  • Implement TP/SL hit calculation logic
  • Create cron job or Next.js API route with scheduler
  • Add monitoring dashboard for blocked signal outcomes
  • Generate weekly reports on missed opportunities

Success Metrics

  • X% of blocked signals would have hit SL (blocks were correct)
  • Y% would have hit TP1/TP2 (missed opportunities)
  • Overall P&L of hypothetical blocked trades

Phase 5: ML-Based Scoring (DISTANT FUTURE) 🤖

Status: Future consideration - requires extensive data
Estimated Start: Q2 2026 or later
Prerequisites: 500+ trades with quality scores, proven manual optimization

Approach

  1. Build ML model to predict trade success from metrics
  2. Use predicted success rate as quality score
  3. Continuously learn from new trades
  4. Auto-adjust weights based on market regime

Requirements

  • Sufficient training data (500+ trades minimum)
  • Market regime classification system
  • ML infrastructure (model training, deployment)
  • Monitoring for model drift

Risks

  • Overfitting to past data
  • Model degrades as markets change
  • Black box decision-making
  • Increased system complexity

Note: Only pursue if manual optimization plateaus or if pursuing ML as learning exercise.


Phase 6: TradingView Range Compression Metrics (PLANNED) 📏

Status: Planned - Next after frequency penalties prove effective
Estimated Start: November 2025 (after Phase 1 validation)
Prerequisites: Phase 1 deployed, 5-10 signals monitored

What It Does

Adds NEW metrics to TradingView alerts to detect range compression and momentum mismatches that indicate choppy markets.

New TradingView Calculations

// 1. Range compression (20-bar high/low range as % of price)
rangePercent = ((highest(high, 20) - lowest(low, 20)) / close) * 100

// 2. Price change over 5 bars (momentum check)
priceChange5bars = ((close - close[5]) / close[5]) * 100

// 3. ADX-momentum mismatch (ADX says trend but price not moving)
adxMismatch = (adx > 15 AND abs(priceChange5bars) < 0.3)

Quality Score Penalties

  • Range < 1.5× ATR: -20 points (compressed range = chop likely)
  • ADX 15+ but price change < 0.3%: -20 points (fake trend signal)
  • Price oscillating around MA: -15 points (whipsaw zone)

Why This Helps

Current system can pass ADX 12-22 even when price just bouncing in tight zone. This detects the mismatch between "ADX says trending" vs "price says chopping."

Example from Nov 14 chart: Multiple signals in $141-145 range passed quality check despite obvious consolidation. Range compression would have caught this.

Implementation Steps

  1. Add calculations to TradingView strategy (30 min)
  2. Update webhook JSON to include new fields (15 min)
  3. Modify scoreSignalQuality() to use range metrics (30 min)
  4. Test alerts on historical data (1 hour)
  5. Deploy and monitor (ongoing)

Expected Impact

  • Catch "fake trends" where ADX misleads
  • Reduce entries in tight consolidation zones
  • Improve win rate by 3-5% in choppy markets
  • Complement frequency penalties (Phase 1)

Success Metrics

  • Reduction in flip-flop losses
  • Fewer blocked signals in validated trending moves
  • Better P&L in sideways market conditions

Phase 7: Volume Profile Integration (ADVANCED) 📊

Status: Future consideration - most complex but most powerful
Estimated Start: December 2025 or Q1 2026
Prerequisites: Phase 6 completed, Volume S/R Zones V2 indicator expertise

What It Does

Uses Volume S/R Zones V2 indicator to detect when price is stuck in high-volume consolidation nodes where flip-flops are most likely.

How Volume Profile Works

  • Shows horizontal bars representing volume at each price level
  • Volume nodes (thick bars) = high volume = price gets stuck (S/R zones)
  • Thin zones (low volume) = price moves through quickly (breakout zones)
  • Price bouncing inside volume node = high probability chop

Required Indicator Modifications

Expose these values from Volume S/R Zones V2:

// New indicator outputs (requires Pine Script modifications)
inVolumeNode: true/false       // Is price inside thick volume bar?
nearVolumeEdge: true/false     // Near top/bottom of node? (breakout setup)
nodeStrength: 0-100            // Volume concentration at this level
distanceFromNode: %            // How far from nearest node?
volumeNodeWidth: %             // How wide is current node? (tight = strong)

Quality Score Adjustments

Penalties:

  • In volume node (stuck): -25 points (high chop probability)
  • Node strength > 80: -30 points (VERY strong S/R = rejection likely)
  • Tight node width (<1%): -35 points (extreme consolidation)

Bonuses:

  • Near volume edge + high volume: +10 points (breakout setup)
  • Distance from node > 2%: +5 points (free movement zone)
  • Breaking through node with volume: +15 points (momentum trade)

Why This Is Powerful

Example from Nov 14 chart: Price bouncing $141-145. Volume profile would show THICK volume node at that exact level - instant warning. System would:

  1. Detect price in node → apply -25 to -35 penalty
  2. Block most entries in that zone
  3. Wait for breakout above/below node
  4. Bonus points when price clears node with volume

Implementation Complexity

High - Requires:

  1. Modify Volume S/R Zones indicator source code (Pine Script)
  2. Expose new variables in indicator settings
  3. Add webhook outputs from indicator (JSON formatting)
  4. Parse in n8n workflow (new data structure)
  5. Update quality scorer with volume logic (complex conditionals)
  6. Test on historical data with indicator overlays
  7. Validate against manual chart analysis

Estimated Time: 2-3 hours + TradingView Pine Script knowledge

Risks & Considerations

  • Indicator must stay updated (TradingView updates can break)
  • Volume profile changes dynamically (recalculates with new data)
  • May over-filter in ranging markets (miss valid mean-reversion trades)
  • Complexity increases debugging difficulty

Success Metrics

  • Elimination of entries in obvious consolidation zones
  • Higher win rate specifically in ranging markets
  • Reduction in whipsaw losses (target: 30-50% fewer)
  • Improved P&L per trade (better entries near node edges)

Alternatives to Consider

  • Use simpler "volume concentration" metric (easier to calculate)
  • Implement fixed support/resistance zones instead of dynamic profile
  • Combine with Phase 6 range compression (may be sufficient)

Recommendation: Only implement if Phase 1 + Phase 6 don't adequately solve flip-flop problem. Volume profile is most powerful but also most fragile.


Progress Tracking


Key Principles

1. Data Before Action

  • Minimum 10 samples before any decision
  • Prefer 20+ for statistical confidence
  • No changes based on 1-2 outliers

2. Incremental Changes

  • Change one variable at a time
  • Test for 10-20 trades after each change
  • Revert if performance degrades

3. Version Tracking

  • Every scoring logic change gets new version (v4 → v5)
  • Store version with each trade/blocked signal
  • Enables A/B testing and rollback

4. Document Everything

  • Update this roadmap after each phase
  • Record decisions and rationale
  • Link to SQL queries and analysis

Progress Tracking

Milestones

  • Nov 11, 2025: Phase 1 infrastructure complete (blocked signals tracking)
  • Nov 14, 2025: Phase 1.5 complete (signal frequency penalties deployed)
  • Target: ~Nov 20-25, 2025: Phase 2 analysis complete (10-20 blocked signals)
  • Target: ~Nov 25-30, 2025: Phase 3 implementation (threshold adjustment)
  • Target: ~Dec 1-7, 2025: Phase 6 implementation (TradingView range metrics)
  • Target: ~Dec 15-31, 2025: Phase 7 evaluation (Volume Profile integration)
  • TBD: Phase 4 automation (blocked signal price tracking)
  • TBD: Phase 5 ML-based scoring (Q2 2026 or later)

Metrics to Watch

  • Blocked signals collected: 0/10 minimum
  • Close calls (60-64 score): 0/2 minimum
  • Days of data collection: 0/7 minimum
  • Market conditions covered: 0/3 (trending, choppy, volatile)

Review Schedule

  • Weekly: Check blocked signal count
  • After 10 blocked: Run Phase 2 analysis
  • After Phase 2: Decide on Phase 3 implementation
  • Monthly: Review overall system performance

Questions to Answer

Phase 1 Questions

  • How many signals get blocked per day?
  • What's the score distribution of blocked signals?
  • Are most blocks from quality score or other reasons?

Phase 2 Questions

  • Do blocked signals at 60-64 have common characteristics?
  • Would lowering threshold to 60 improve performance?
  • Do extreme positions need different treatment?
  • Is ADX pattern valid in blocked signals?

Phase 3 Questions

  • Did the change improve win rate?
  • Did it increase profitability?
  • Any unintended side effects?

Appendix: Historical Context

Why This Roadmap Exists

Date: November 11, 2025

Situation: Three TradingView signals fired:

  1. SHORT at 05:15 - Executed (score likely 65+) → Losing trade
  2. LONG at 05:20 - Executed (score likely 65+) → Losing trade
  3. SHORT at 05:30 - BLOCKED (score 45) → Would have been profitable

User Question: "What can we do about this?"

Analysis Findings:

  • Only 2 historical trades scored 60-64 (both winners +$45.78)
  • Sample size too small for confident decision
  • ADX 20-25 is a trap zone (-$23.41 in 23 trades)
  • Low volume (<0.8x) outperforms high volume (counterintuitive!)

Decision: Build data collection system instead of changing thresholds prematurely

This Roadmap: Systematic approach to optimization with proper data backing


Remember: The goal isn't to catch every winning trade. The goal is to optimize the risk-adjusted return by catching more winners than losers at each threshold level. Sometimes blocking a potential winner is correct if it also blocks 3 losers.