- BlockedSignalTracker deployed Nov 19-22, 2025 - 34 signals tracked: 21 multi-timeframe + 13 quality-blocked - Price tracking at 1/5/15/30 min intervals operational - TP/SL hit detection using ATR-based targets working - First validation: Quality 80 blocked signal would've won +0.52% - Updated milestones and metrics with current data - Changed status from FUTURE to COMPLETE with deployment dates
22 KiB
Signal Quality Optimization Roadmap
Goal: Optimize signal quality thresholds and scoring logic using data-driven analysis
Current Status: Phase 4 Complete ✅ - Automated price tracking operational | Phase 1-2 Active - Collecting + analyzing data
Last Updated: November 24, 2025
🎉 MAJOR UPDATE: Phase 4 Complete (Nov 19-22, 2025)
- BlockedSignalTracker deployed and fully operational
- 34 signals tracked: 21 multi-timeframe + 13 quality-blocked
- Price tracking at 1/5/15/30 min intervals with TP/SL hit detection
- First validation: Quality 80 signal blocked, would've profited +0.52%
🚀 v8 Money Line Indicator (Nov 18, 2025)
- Sticky trend detection with 0.6% flip threshold + momentum confirmation
- 8 trades completed: 57.1% WR, +$262.70 total, 93.6 avg quality
- Perfect quality separation: All winners ≥95, all losers ≤90
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: 91 points (raised from 81 on Nov 21, 2025 after trade #7 analysis)
- Trade #7: ADX 19.0, quality 90 → -$387 loss (weak trend, emergency stop)
- Perfect Separation: Analysis of 7 v8 trades:
- ALL 4 winners had quality ≥95 (95, 95, 100, 105) ✅
- ALL 3 losers had quality ≤90 (80, 90, 90) ❌
- 91 threshold would have prevented 100% of losses (-$624.90)
- v8 Performance: 7 trades, 57.1% WR, $262.70 total, 93.6 avg quality
- Historical Performance (v5/v6): 157 total, +$3.43 P&L, 44.5% 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
BlockedSignaldatabase 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
- How many signals score 60-64 (just below threshold)?
- What are their characteristics (ADX, ATR, price position)?
- Are there patterns (extreme positions, specific timeframes)?
- 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
-
Overtrading (3+ signals in 30min): -20 points
- Counts both executed trades AND blocked signals
- Prevents excessive trading in consolidation zones
-
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)
-
Alternating pattern (last 3 trades): -30 points
- Detects choppy market conditions
- Pattern: long→short→long = chop detection
Technical Details
- Function:
getRecentSignals()inlib/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
- Monitor next 5-10 signals for accurate price calculations
- Verify penalties trigger with correct percentages
- Analyze if blocked signals would have lost
- 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)
Option A: Dual-Threshold System (Recommended)
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 logiclib/trading/signal-quality.ts- AddisExtremePositionhelperconfig/trading.ts- AddminScoreForExtremesconfig 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 ✅ COMPLETE
Goal: Automatically track if blocked signals would have been profitable
Status: Deployed Nov 19-22, 2025 - Fully operational
Implementation: BlockedSignalTracker background service
Architecture ✅
BlockedSignalTracker (runs every 5 min)
↓
Fetch BlockedSignal records where:
- analysisComplete = false
- createdAt within last 30 minutes
↓
For each signal (both DATA_COLLECTION_ONLY and QUALITY_SCORE_TOO_LOW):
- Query current price from Drift oracle
- Calculate profit % based on direction
- Check if TP1 (~0.86%), TP2 (~1.72%), SL (~1.29%) would have hit
- Update priceAfter1Min/5Min/15Min/30Min
- Track maxFavorableExcursion and maxAdverseExcursion
- Set wouldHitTP1/TP2/SL flags
- Mark analysisComplete = true after 30 minutes
↓
Save results back to database
Implementation Complete ✅
- Created BlockedSignalTracker service (
lib/analysis/blocked-signal-tracker.ts) - Price tracking from Drift oracle (not history, but real-time monitoring)
- TP/SL hit calculation using ATR-based targets
- Background job running every 5 minutes
- Auto-starts on container startup
- API endpoint (
/api/analytics/signal-tracking) for monitoring - Enhanced Nov 22: Tracks both multi-timeframe AND quality-blocked signals
Current Data (Nov 24, 2025)
- 34 total blocked signals tracked
- 21 multi-timeframe (DATA_COLLECTION_ONLY): 19 complete
- 13 quality-blocked (QUALITY_SCORE_TOO_LOW): 6 complete
- First validation result: Quality 80 signal would have profited +0.52% (+$43)
Success Metrics ✅
- System validates if blocks were correct (SL hits) vs missed opportunities (TP hits)
- Enables data-driven threshold optimization
- Risk-free analysis of non-executed signals
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
- Build ML model to predict trade success from metrics
- Use predicted success rate as quality score
- Continuously learn from new trades
- 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
- Add calculations to TradingView strategy (30 min)
- Update webhook JSON to include new fields (15 min)
- Modify
scoreSignalQuality()to use range metrics (30 min) - Test alerts on historical data (1 hour)
- 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:
- Detect price in node → apply -25 to -35 penalty
- Block most entries in that zone
- Wait for breakout above/below node
- Bonus points when price clears node with volume
Implementation Complexity
High - Requires:
- Modify Volume S/R Zones indicator source code (Pine Script)
- Expose new variables in indicator settings
- Add webhook outputs from indicator (JSON formatting)
- Parse in n8n workflow (new data structure)
- Update quality scorer with volume logic (complex conditionals)
- Test on historical data with indicator overlays
- 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)
- Nov 19, 2025: Phase 4 COMPLETE (multi-timeframe price tracking deployed)
- Nov 22, 2025: Phase 4 ENHANCED (quality threshold validation added)
- 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 5 ML-based scoring (Q2 2026 or later)
Metrics to Watch
- Blocked signals collected: 34/10 minimum ✅ (21 multi-timeframe + 13 quality-blocked)
- Data collection complete: 25/34 signals (73.5% completion rate) ✅
- Quality-blocked signals: 13 collected, 6 complete (Nov 22 enhancement)
- Multi-timeframe signals: 21 collected, 19 complete (Nov 19 deployment)
- First validation: Quality 80 blocked signal would've profited +0.52% (+$43) - FALSE NEGATIVE
- Days of data collection: 5 days (Nov 19-24) - ongoing
- Market conditions covered: 3/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:
- SHORT at 05:15 - Executed (score likely 65+) → Losing trade
- LONG at 05:20 - Executed (score likely 65+) → Losing trade
- 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.