# Quick Implementation Guide: Q>=95 Strategy **Date:** December 18, 2025 **Target:** Update quality thresholds + add instant reversal filter **Expected Impact:** Turn -$687.98 baseline into +$178.91 profit (3.88 PF) --- ## Pre-Implementation Checklist - [x] Strategy validated on 11 trades (Nov 19 - Dec 17, 2025) - [x] Performance documented: 63.6% WR, +183.4% return, 3.88 PF - [x] Risk warnings documented (small sample size, outlier dependency) - [x] User approval obtained: "implement the winner you found" - [x] Documentation complete (copilot-instructions.md + STRATEGY_OPTIMIZATION_DEC_2025.md) - [ ] Code changes ready - [ ] Testing plan prepared - [ ] Monitoring dashboard ready --- ## Step 1: Update Quality Thresholds (5 minutes) ### File: `lib/trading/signal-quality.ts` **Location:** Search for `MIN_SIGNAL_QUALITY_SCORE` **Current code:** ```typescript // Direction-specific thresholds const MIN_LONG_QUALITY = 90; const MIN_SHORT_QUALITY = 80; ``` **New code:** ```typescript // Unified Q>=95 threshold (Dec 18, 2025 optimization) const MIN_LONG_QUALITY = 95; const MIN_SHORT_QUALITY = 95; ``` **OR update .env file:** ```bash MIN_SIGNAL_QUALITY_SCORE_LONG=95 MIN_SIGNAL_QUALITY_SCORE_SHORT=95 ``` **Verify:** - [ ] Run `grep -r "MIN_SIGNAL_QUALITY" lib/` to find all usages - [ ] Check if thresholds are hardcoded or read from config - [ ] Confirm both LONG and SHORT get updated to 95 --- ## Step 2: Add Instant Reversal Filter (30-60 minutes) ### Option A: Add to check-risk endpoint (RECOMMENDED) **File:** `app/api/check-risk/route.ts` (or similar) **Logic to add:** ```typescript /** * Block signals that would likely hit SL within 1-2 candles (instant reversals) * These indicate poor timing, false breakouts, or late entries */ async function checkInstantReversalRisk( symbol: string, direction: 'LONG' | 'SHORT', entryPrice: number, stopLoss: number ): Promise<{ blocked: boolean; reason?: string }> { // 1. Fetch last 5-10 price candles for symbol (5-minute timeframe) const recentCandles = await getRecentCandles(symbol, '5', 10); if (!recentCandles || recentCandles.length < 3) { // Insufficient data - fail-open (allow trade) return { blocked: false }; } // 2. Calculate recent volatility (ATR proxy from last 5 candles) const recentRanges = recentCandles.slice(0, 5).map(c => Math.abs(c.high - c.low) / c.close ); const avgRange = recentRanges.reduce((a, b) => a + b, 0) / recentRanges.length; // 3. Calculate stop loss distance as percentage const slDistance = Math.abs(stopLoss - entryPrice) / entryPrice; // 4. Check if SL distance is less than 1-2 candle average range const instantReversalThreshold = avgRange * 1.5; // 1.5 candles worth of movement if (slDistance < instantReversalThreshold) { // 5. Check recent price action - is there momentum in our direction? const lastCandle = recentCandles[0]; const priceMovement = (lastCandle.close - lastCandle.open) / lastCandle.open; const momentumInDirection = ( (direction === 'LONG' && priceMovement > 0) || (direction === 'SHORT' && priceMovement < 0) ); if (!momentumInDirection) { // No momentum + tight SL = likely instant reversal return { blocked: true, reason: `Instant reversal risk: SL distance ${(slDistance * 100).toFixed(2)}% < ${(instantReversalThreshold * 100).toFixed(2)}% (1.5 candles), no momentum in direction` }; } } return { blocked: false }; } // Add to main check-risk logic: const instantReversalCheck = await checkInstantReversalRisk( symbol, direction, entryPrice, calculatedStopLoss ); if (instantReversalCheck.blocked) { console.log(`⚠️ BLOCKED: ${instantReversalCheck.reason}`); // Log to BlockedSignal table await prisma.blockedSignal.create({ data: { symbol, direction, timeframe: '5', blockReason: 'INSTANT_REVERSAL_RISK', details: instantReversalCheck.reason, // ... other fields } }); return Response.json({ success: false, reason: 'INSTANT_REVERSAL_RISK', message: instantReversalCheck.reason }); } ``` **Helper function needed:** ```typescript async function getRecentCandles( symbol: string, timeframe: string, count: number ): Promise> { // Option 1: Query BlockedSignal table for recent candles const signals = await prisma.blockedSignal.findMany({ where: { symbol, timeframe, timestamp: { gte: new Date(Date.now() - count * 5 * 60 * 1000) // Last N × 5 minutes } }, orderBy: { timestamp: 'desc' }, take: count, select: { price: true, atr: true, timestamp: true } }); // Option 2: Fetch from Drift/Pyth price feed history // (if BlockedSignal doesn't have OHLC data) return signals.map(s => ({ open: s.price, // Approximate - may need actual OHLC high: s.price + s.atr, low: s.price - s.atr, close: s.price, timestamp: s.timestamp })); } ``` ### Option B: Add to Position Manager (Alternative) **File:** `lib/trading/position-manager.ts` **Add check in entry logic before opening position:** ```typescript // Before: await driftClient.openPosition(...) const instantReversalCheck = await checkInstantReversalRisk( symbol, direction, entryPrice, stopLoss ); if (instantReversalCheck.blocked) { console.log(`⚠️ Position NOT opened: ${instantReversalCheck.reason}`); return { success: false, reason: 'INSTANT_REVERSAL_RISK' }; } // Continue with normal position opening... ``` **Pros/Cons:** - **Option A (check-risk):** ✅ Blocks earlier, consistent with other filters, easier to test - **Option B (position-manager):** ✅ Has access to real-time price data, but later in pipeline **Recommendation:** Implement in check-risk endpoint (Option A) for consistency with HTF filter and quality threshold checks. --- ## Step 3: Environment Variables (if needed) Add to `.env`: ```bash # Quality Score Optimization (Dec 18, 2025) MIN_SIGNAL_QUALITY_SCORE_LONG=95 MIN_SIGNAL_QUALITY_SCORE_SHORT=95 # Instant Reversal Filter (Dec 18, 2025) INSTANT_REVERSAL_DETECTION_ENABLED=true INSTANT_REVERSAL_THRESHOLD_CANDLES=1.5 # SL must be > 1.5 candles away ``` --- ## Step 4: Database Updates (if needed) **Add new block reason to BlockedSignal table:** Check if `blockReason` enum includes `INSTANT_REVERSAL_RISK`: ```sql SELECT enumlabel FROM pg_enum WHERE enumtypid = ( SELECT oid FROM pg_type WHERE typname = 'BlockReason' ); ``` If not present, add it: ```sql ALTER TYPE "BlockReason" ADD VALUE 'INSTANT_REVERSAL_RISK'; ``` OR update Prisma schema: ```prisma enum BlockReason { // ... existing reasons INSTANT_REVERSAL_RISK // Add this } ``` Then run: ```bash npx prisma db push ``` --- ## Step 5: Testing Protocol ### 5.1 Unit Tests (if test suite exists) Create `tests/instant-reversal-filter.test.ts`: ```typescript describe('Instant Reversal Filter', () => { it('should block trades with SL < 1.5 candles', async () => { const result = await checkInstantReversalRisk( 'SOL', 'LONG', 100, 99.5, // Entry $100, SL $99.50 (0.5%) [{ high: 101, low: 99, close: 100 }] // 2% range candle ); expect(result.blocked).toBe(true); }); it('should allow trades with SL > 1.5 candles', async () => { const result = await checkInstantReversalRisk( 'SOL', 'LONG', 100, 98.5, // Entry $100, SL $98.50 (1.5%) [{ high: 101, low: 99, close: 100 }] // 2% range candle ); expect(result.blocked).toBe(false); }); }); ``` Run: ```bash npm test -- instant-reversal-filter.test.ts ``` ### 5.2 Integration Test (Manual) 1. **Trigger a test signal:** - Send webhook to n8n with quality score 95 - Verify: Trade executes (quality threshold passed) 2. **Check BlockedSignal table:** ```sql SELECT * FROM "BlockedSignal" WHERE "blockReason" = 'INSTANT_REVERSAL_RISK' ORDER BY timestamp DESC LIMIT 10; ``` 3. **Verify logs:** - Check container logs: `docker logs trading-bot-v4 --tail 100` - Look for: `⚠️ BLOCKED: Instant reversal risk` or `✅ Quality: 95 → Trade approved` ### 5.3 Paper Trade (if available) - Switch to testnet/paper mode - Run for 24 hours - Verify: Fewer trades executed (~0.44/day vs 1.0/day) - Check: Quality scores of executed trades all >=95 --- ## Step 6: Deployment ### 6.1 Commit Changes ```bash cd /home/icke/traderv4 # Stage changes git add lib/trading/signal-quality.ts git add app/api/check-risk/route.ts # Or wherever instant reversal filter added git add .env # If ENV vars changed git add docs/STRATEGY_OPTIMIZATION_DEC_2025.md git add docs/IMPLEMENTATION_GUIDE.md git add .github/copilot-instructions.md # Commit git commit -m "feat: Implement Q>=95 quality threshold + instant reversal filter - Update quality thresholds: LONG 90→95, SHORT 80→95 - Add instant reversal detection (blocks SL <1.5 candles) - Validated performance: 11 trades, 63.6% WR, +183.4% return, 3.88 PF - Ref: docs/STRATEGY_OPTIMIZATION_DEC_2025.md" # Push git push origin main ``` ### 6.2 Restart Container ```bash # Rebuild and restart docker compose down docker compose up -d --build # Verify container started docker ps | grep trading-bot-v4 # Check logs docker logs trading-bot-v4 --tail 50 --follow ``` ### 6.3 Verify Deployment ```bash # 1. Check container timestamp docker inspect trading-bot-v4 | grep Created # 2. Verify commit deployed docker exec trading-bot-v4 git log -1 --oneline # 3. Test health endpoint curl http://localhost:3000/api/health # 4. Check ENV vars docker exec trading-bot-v4 printenv | grep QUALITY ``` --- ## Step 7: Post-Deployment Monitoring ### Day 1 Checklist - [ ] Monitor logs every 2 hours for first 24h - [ ] Check for any Q>=95 signals received - [ ] Verify instant reversal filter triggers (if any) - [ ] Confirm first trade execution (quality logged correctly) - [ ] Check database: `SELECT * FROM "Trade" ORDER BY entryTime DESC LIMIT 3;` - [ ] Review BlockedSignal: `SELECT blockReason, COUNT(*) FROM "BlockedSignal" WHERE timestamp > NOW() - INTERVAL '1 day' GROUP BY blockReason;` ### Week 1 Analysis After 7 days or first 3-5 trades: ```sql -- Performance check WITH recent_trades AS ( SELECT realizedPnL, CASE WHEN realizedPnL > 0 THEN 1 ELSE 0 END as is_win, signalQualityScore FROM "Trade" WHERE entryTime >= '2025-12-18' -- Deployment date AND exitTime IS NOT NULL AND timeframe = '5' ) SELECT COUNT(*) as trades, ROUND(100.0 * SUM(is_win) / COUNT(*), 1) as win_rate_pct, ROUND(SUM(realizedPnL)::numeric, 2) as total_pnl, ROUND(AVG(CASE WHEN is_win=1 THEN realizedPnL END)::numeric, 2) as avg_win, ROUND(AVG(CASE WHEN is_win=0 THEN realizedPnL END)::numeric, 2) as avg_loss, ROUND(AVG(signalQualityScore)::numeric, 1) as avg_quality, MIN(signalQualityScore) as min_quality FROM recent_trades; ``` **Compare to validated backtest:** - Expected: ~3 trades (0.44/day × 7 days) - Expected WR: 60-65% - Expected avg win: ~$34 - Expected avg loss: ~$21 - Expected PF: 2.0+ (conservative), 3.88 (optimistic) **Alert if:** - ❌ Win rate <50% - ❌ Avg loss >$35 - ❌ Profit factor <1.5 - ❌ Zero trades in 5 days (threshold too strict) - ❌ Any quality score <95 (filter bypass bug) ### Rollback Procedure (if needed) ```bash # 1. Revert git commit git revert HEAD git push origin main # 2. Rebuild container docker compose down docker compose up -d --build # 3. Verify rollback docker logs trading-bot-v4 | grep "Quality threshold" # Should show: LONG=90, SHORT=80 (old values) # 4. Document failure # Add notes to docs/STRATEGY_OPTIMIZATION_DEC_2025.md under "Rollback Criteria" ``` --- ## Quick Reference Commands ```bash # Check logs docker logs trading-bot-v4 --tail 100 --follow # Recent trades docker exec trading-bot-v4 psql $DATABASE_URL -c " SELECT entryTime, direction, realizedPnL, exitReason, signalQualityScore FROM \"Trade\" WHERE entryTime >= '2025-12-18' ORDER BY entryTime DESC LIMIT 10; " # Blocked signals today docker exec trading-bot-v4 psql $DATABASE_URL -c " SELECT blockReason, COUNT(*) FROM \"BlockedSignal\" WHERE timestamp > CURRENT_DATE GROUP BY blockReason; " # Quality score distribution (last 24h) docker exec trading-bot-v4 psql $DATABASE_URL -c " SELECT CASE WHEN \"qualityScore\" >= 95 THEN '95+' WHEN \"qualityScore\" >= 90 THEN '90-94' WHEN \"qualityScore\" >= 85 THEN '85-89' ELSE '<85' END as quality_bucket, COUNT(*) FROM \"BlockedSignal\" WHERE timestamp > NOW() - INTERVAL '24 hours' GROUP BY quality_bucket ORDER BY quality_bucket DESC; " # Restart if needed docker restart trading-bot-v4 ``` --- ## Success Criteria (After 25 trades or 60 days) ✅ **Strategy validated if:** 1. Win rate >= 55% 2. Profit factor >= 1.5 3. Average loss <= $35 4. Total P&L positive 5. No catastrophic losses (>$100 single trade) ❌ **Strategy failed if:** 1. Win rate < 40% 2. Profit factor < 0.8 3. Average loss > $50 4. Total drawdown > 50% 5. Multiple instant reversal filter bypasses (bugs) --- ## Contact & Support - **Documentation:** `docs/STRATEGY_OPTIMIZATION_DEC_2025.md` - **Code Locations:** - Quality thresholds: `lib/trading/signal-quality.ts` - Instant reversal: `app/api/check-risk/route.ts` (to be added) - HTF filter: (existing, no changes) - 5-candle exit: Position Manager (existing, no changes) - **User Approval:** Obtained Dec 18, 2025 - **Questions:** Review conversation history or ask user --- **Last Updated:** December 18, 2025 **Status:** 📋 Documentation complete, ready for implementation **Next Step:** Begin Step 1 (Update quality thresholds)