Files
trading_bot_v4/docs/IMPLEMENTATION_GUIDE.md
mindesbunister 634738bfb4 Deploy Q≥95 strategy: unified thresholds + instant-reversal filter + 5-candle time exit
Backtest results (28 days):
- Original: 32 trades, 43.8% win rate, -16.82 loss
- New: 13 trades, 69.2% win rate, +49.99 profit
- Improvement: +66.81 (+991%), +25.5% hit rate

Changes:
1. Set MIN_SIGNAL_QUALITY_SCORE_LONG/SHORT=95 (was 90/85)
2. Added instant-reversal filter: blocks re-entry within 15min after fast SL (<5min hold)
3. Added 5-candle time exit: exits after 25min if MFE <0
4. HTF filter already effective (no Q≥95 trades blocked)

Expected outcome: Turn consistent losses into consistent profits with 69% win rate
2025-12-18 09:35:36 +01:00

526 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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<Array<{ open: number; high: number; low: number; close: number; timestamp: Date }>> {
// 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)