diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 16e4d26..998b10c 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1388,7 +1388,7 @@ trade.realizedPnL += actualRealizedPnL // NOT: result.realizedPnL from SDK - **v5:** Buy/Sell Signal strategy (pre-Nov 12) - **v6:** HalfTrend + BarColor strategy (Nov 12-18) - **v7:** v6 with toggle filters (deprecated - no fundamental improvements) - - **v8:** Money Line Sticky Trend (Nov 18+) - 0.8% flip threshold, momentum confirmation, anti-whipsaw + - **v8:** Money Line Sticky Trend (Nov 18+) - 0.6% flip threshold, momentum confirmation, anti-whipsaw - Used for performance comparison between strategies (v6 vs v8 A/B testing) 27. **Runner stop loss gap - NO protection between TP1 and TP2 (CRITICAL - Fixed Nov 15, 2025):** @@ -2457,6 +2457,164 @@ trade.realizedPnL += actualRealizedPnL // NOT: result.realizedPnL from SDK - **Git commit:** de57c96 "fix: Correct TP1 detection for on-chain order fills" - **Lesson:** When orders fill externally (on-chain), state flags (tp1Hit) unreliable. Infer exit reason from results (profit percentage) rather than process tracking. Simple logic often more reliable than complex state machines for fast-moving on-chain events. +52. **ADX-based runner SL only applied in one code path (CRITICAL - Fixed Nov 19, 2025):** + - **Symptom:** TP1 fills via on-chain order, runner gets breakeven SL instead of ADX-based positioning + - **Root Cause:** Two separate TP1 detection paths in Position Manager: + 1. **Direct price check** (lines 1050-1100) - Has ADX-based runner SL ✅ + 2. **On-chain fill detection** (lines 590-650) - Hard-coded breakeven ❌ + - **Real incident (Nov 19, 12:40 CET):** + * SHORT opened: $138.3550, ADX 20.0 + * TP1 filled via on-chain order (60% closed) + * Expected: ADX 20.0 (moderate tier) → runner SL at -0.3% ($138.77) + * Actual: Hard-coded breakeven SL ($138.355) + * Bug: On-chain fill detection bypassed ADX logic completely + - **Why two paths exist:** + * Direct price check: Position Manager detects TP1 price crossed + * On-chain fill: Detects size reduction from order fill (most common) + * Both paths mark `tp1Hit = true` but only direct path had ADX logic + - **Impact:** Most TP1 triggers happen via on-chain orders, so ADX system not working for majority of trades + - **Fix (Nov 19, 13:50 CET):** + ```typescript + // In lib/trading/position-manager.ts lines 607-642 + // On-chain fill detection path + + // ADX-based runner SL positioning (Nov 19, 2025) + // Strong trends get more room, weak trends protect capital + let runnerSlPercent: number + const adx = trade.adxAtEntry || 0 + + if (adx < 20) { + runnerSlPercent = 0 // Weak trend: breakeven + console.log(`🔒 ADX-based runner SL: ${adx.toFixed(1)} → 0% (breakeven - weak trend)`) + } else if (adx < 25) { + runnerSlPercent = -0.3 // Moderate trend + console.log(`🔒 ADX-based runner SL: ${adx.toFixed(1)} → -0.3% (moderate trend)`) + } else { + runnerSlPercent = -0.55 // Strong trend + console.log(`🔒 ADX-based runner SL: ${adx.toFixed(1)} → -0.55% (strong trend)`) + } + + const newStopLossPrice = this.calculatePrice( + trade.entryPrice, + runnerSlPercent, + trade.direction + ) + trade.stopLossPrice = newStopLossPrice + ``` + - **Commits:** + * b2cb6a3 "critical: Fix ADX-based runner SL in on-chain fill detection path" + * 66b2922 "feat: ADX-based runner SL positioning" (original implementation) + - **Verification:** Next TP1 hit via on-chain order will show ADX-based log message + - **Lesson:** When implementing adaptive logic, check ALL code paths that reach that decision point. Don't assume one implementation covers all cases. + +53. **Container restart kills positions + phantom detection bug (CRITICAL - Fixed Nov 19, 2025):** + - **Two simultaneous bugs** caused by container restart during active trade: + + **Bug 1: Startup order restore failure** + - **Symptom:** Container restart fails to restore on-chain TP/SL orders + - **Root Cause:** Wrong database field names in `lib/startup/init-position-manager.ts` + - **Error:** `Unknown argument 'takeProfit1OrderTx'` - schema uses `tp1OrderTx` not `takeProfit1OrderTx` + - **Impact:** Position left with NO on-chain orders, only Position Manager monitoring + - **Fix:** Changed to correct field names: + ```typescript + await prisma.trade.update({ + where: { id: trade.id }, + data: { + tp1OrderTx: result.signatures?.[0], // NOT: takeProfit1OrderTx + tp2OrderTx: result.signatures?.[1], // NOT: takeProfit2OrderTx + slOrderTx: result.signatures?.[2], // NOT: stopLossOrderTx + } + }) + ``` + + **Bug 2: Phantom detection killing runners** + - **Symptom:** Runner after TP1 flagged as phantom trade, P&L set to $0.00 + - **Root Cause:** Phantom detection logic in external closure handler: + ```typescript + // BROKEN: Flagged runners as phantom + const wasPhantom = trade.currentSize > 0 && (trade.currentSize / trade.positionSize) < 0.5 + // Example: $3,317 runner / $8,325 original = 40% → PHANTOM! + ``` + - **Impact:** Profitable runner exits recorded with $0.00 P&L in database + + - **Real incident (Nov 19, 13:56 CET):** + * SHORT $138.355, ADX 20.0, quality 85 + * TP1 hit: 60% closed at $137.66 → +$22.78 profit (Drift confirmed) + * Runner: 40% trailing perfectly, peak at $136.72 + * Container restart at 13:50 (deploying ADX fix) + * Orders failed to restore (field name error) + * Position Manager detected "closed externally" + * Phantom detection triggered: 40% remaining = phantom! + * Database: exitReason="SL", realizedPnL=$0.00 + * **Actual profit from Drift: $54.19** (TP1 $22.78 + runner $31.41) + + - **Fix for phantom detection:** + ```typescript + // FIXED: Check TP1 status before phantom detection + const sizeForPnL = trade.tp1Hit ? trade.currentSize : trade.originalPositionSize + const wasPhantom = !trade.tp1Hit && trade.currentSize > 0 && (trade.currentSize / trade.positionSize) < 0.5 + + // Logic: + // - If TP1 hit: We're closing RUNNER (currentSize), NOT a phantom + // - If TP1 not hit: Check if opening was <50% = phantom + // - Runners are legitimate 25-40% remaining positions, not errors + ``` + + - **Commit:** eccecf7 "critical: Fix container restart killing positions + phantom detection" + - **Prevention:** + * Schema errors now fixed - orders restore correctly + * Phantom detection only checks pre-TP1 positions + * Runner P&L calculated on actual runner size + - **Lesson:** Container restarts during active trades are high-risk events. All startup validation MUST use correct schema fields and understand trade lifecycle state (pre-TP1 vs post-TP1). + +54. **Settings UI quality score variable name mismatch (CRITICAL - Fixed Nov 19, 2025):** + - **Symptom:** User changes "Min Signal Quality" in settings UI (e.g., 60 → 81), but trades continue executing with old threshold + - **Root Cause:** Settings API reading/writing wrong ENV variable name + - **Variable name inconsistency:** + * **Settings API used:** `MIN_QUALITY_SCORE` (incorrect) + * **Code actually reads:** `MIN_SIGNAL_QUALITY_SCORE` (correct, used in config/trading.ts) + * Settings UI writes to non-existent variable, bot never sees changes + - **Real incident (Nov 19):** + * User increased quality threshold from 60 to 81 + * Goal: Block small chop trades (avoid -$99 trade with quality score 80) + * Settings UI confirmed save: "Min Signal Quality: 81" + * But trades with score 60-80 continued executing + * Quality score changes had ZERO effect on bot behavior + - **Impact:** All quality score adjustments via settings UI silently ignored since UI launch + - **Code locations:** + * `app/api/settings/route.ts` - Settings API read/write operations + * `config/trading.ts` - Bot reads `MIN_SIGNAL_QUALITY_SCORE` (correct name) + * `.env` file - Contains `MIN_SIGNAL_QUALITY_SCORE=60` (correct name) + - **Fix:** + ```typescript + // In app/api/settings/route.ts (lines ~150, ~270) + // BEFORE (BROKEN): + MIN_QUALITY_SCORE: process.env.MIN_QUALITY_SCORE || '60', + + // AFTER (FIXED): + MIN_SIGNAL_QUALITY_SCORE: process.env.MIN_SIGNAL_QUALITY_SCORE || '60', + + // Also update .env file writes: + newEnvContent = newEnvContent.replace(/MIN_SIGNAL_QUALITY_SCORE=.*/g, `MIN_SIGNAL_QUALITY_SCORE=${settings.minSignalQualityScore}`) + ``` + - **Manual .env correction:** + ```bash + # User's intended change (Nov 19): + sed -i 's/MIN_SIGNAL_QUALITY_SCORE=60/MIN_SIGNAL_QUALITY_SCORE=81/' /home/icke/traderv4/.env + docker restart trading-bot-v4 + ``` + - **Why this matters:** + * Quality score is PRIMARY filter for trade execution + * User relies on settings UI for rapid threshold adjustments + * Silent failure = user thinks system protecting capital but it's not + * In this case: 81 threshold would block small chop trades (60-80 score range) + - **Verification:** + * Settings UI "Save" → Check .env file has `MIN_SIGNAL_QUALITY_SCORE` updated + * Container restart → Bot logs show: `Min quality score: 81` + * Next blocked signal: Log shows `Quality score 78 below minimum 81` + - **Git commit:** "fix: Correct MIN_QUALITY_SCORE to MIN_SIGNAL_QUALITY_SCORE" + - **Lesson:** When creating settings UI, always use EXACT ENV variable names from actual bot code. Mismatched names cause silent failures where user actions have no effect. Test settings changes end-to-end (UI → .env → bot behavior). + 46. **100% position sizing causes InsufficientCollateral (Fixed Nov 16, 2025):** - **Symptom:** Bot configured for 100% position size gets InsufficientCollateral errors, but Drift UI can open same size position - **Root Cause:** Drift's margin calculation includes fees, slippage buffers, and rounding - exact 100% leaves no room diff --git a/OPTIMIZATION_MASTER_ROADMAP.md b/OPTIMIZATION_MASTER_ROADMAP.md index b86b584..4f20504 100644 --- a/OPTIMIZATION_MASTER_ROADMAP.md +++ b/OPTIMIZATION_MASTER_ROADMAP.md @@ -27,7 +27,7 @@ Filter out bad trades BEFORE entry by optimizing quality score thresholds. ### Current Status 🚀 **NEW: v8 Indicator Deployed** (Nov 18, 2025) -- **Money Line v8:** Sticky trend detection with 0.8% flip threshold +- **Money Line v8:** Sticky trend detection with 0.6% flip threshold - **Improvements:** Stickier ATR multipliers (3.8x-3.0x), entry buffer 0.2 ATR, ADX 18+ - **Anti-whipsaw:** Momentum confirmation prevents rapid flip-flops - **Status:** Ready for TradingView alerts, awaiting first live signals diff --git a/SIGNAL_QUALITY_OPTIMIZATION_ROADMAP.md b/SIGNAL_QUALITY_OPTIMIZATION_ROADMAP.md index 13e7316..db5a155 100644 --- a/SIGNAL_QUALITY_OPTIMIZATION_ROADMAP.md +++ b/SIGNAL_QUALITY_OPTIMIZATION_ROADMAP.md @@ -6,7 +6,7 @@ **Last Updated:** November 18, 2025 **🚀 NEW: v8 Money Line Indicator Deployed (Nov 18, 2025)** -- Sticky trend detection with 0.8% flip threshold + momentum confirmation +- Sticky trend detection with 0.6% flip threshold + momentum confirmation - Awaiting first live signals for performance comparison vs v6 - Will enable A/B testing: v6 (filtered) vs v8 (sticky flips)