From f8141009a812fdf00f83cc07f5464ef260dee570 Mon Sep 17 00:00:00 2001 From: mindesbunister Date: Sat, 15 Nov 2025 11:36:16 +0100 Subject: [PATCH] docs: Document runner stop loss gap bug (Common Pitfall #34) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CRITICAL BUG DOCUMENTATION: Runner had ZERO stop loss protection between TP1-TP2 Context: - User reported: 'runner close did not work. still open and the price is above 141,98' - Investigation revealed Position Manager only checked SL before TP1 OR after TP2 - Runner between TP1-TP2 had NO stop loss checks = hours of unlimited loss exposure Bug Impact: - SHORT at $141.317, TP1 closed 70% at $140.942, runner had SL at $140.89 - Price rose to $141.98 (way above SL) → NO PROTECTION → Position stayed open - Potential unlimited loss on 25-30% runner position Fix Verification: - After fix deployed: Runner closed at $141.133 with +$0.59 profit - Database shows exitReason='SL', proving runner stop loss triggered correctly - Log: '🔴 RUNNER STOP LOSS: SOL-PERP at 0.3% (profit lock triggered)' Lesson: Every conditional branch in risk management MUST have explicit SL checks Files: .github/copilot-instructions.md (added Common Pitfall #34) --- .github/copilot-instructions.md | 42 +++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 16bc094..24f1645 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1346,6 +1346,48 @@ trade.realizedPnL += actualRealizedPnL // NOT: result.realizedPnL from SDK - **Manual fix required once:** Had to manually UPDATE database for existing position, then restart container - **Lesson:** Always prefer on-chain data over cached database values for critical trading parameters +34. **Runner stop loss gap - NO protection between TP1 and TP2 (CRITICAL - Fixed Nov 15, 2025):** + - **Symptom:** Runner position remained open despite price moving far above stop loss level + - **Root Cause:** Position Manager only checked stop loss BEFORE TP1 hit (line 693) OR AFTER TP2 hit (line 835), creating a gap + - **Bug sequence:** + 1. SHORT opened at $141.317, TP1 hit at $140.942 (70% closed) + 2. Runner (30% remaining, $12.70) had stop loss at $140.89 (profit lock) + 3. Price rose to $141.98 (way above $140.89 SL) → NO STOP LOSS CHECK + 4. Position exposed to unlimited loss for hours during TP1→TP2 window + 5. User manually checked: "runner close did not work. still open and the price is above 141,98" + - **Impact:** Hours of unprotected runner exposure = potential unlimited loss on 25-30% remaining position + - **Code analysis:** + ```typescript + // Line 693: Stop loss checked ONLY before TP1 + if (!trade.tp1Hit && this.shouldStopLoss(currentPrice, trade)) { + console.log(`🔴 STOP LOSS: ${trade.symbol}`) + await this.executeExit(trade, 100, 'SL', currentPrice) + } + + // Lines 706-831: TP1 and TP2 processing - NO STOP LOSS CHECK + + // Line 835: Stop loss checked ONLY after TP2 + if (trade.tp2Hit && this.config.useTrailingStop && this.shouldStopLoss(currentPrice, trade)) { + console.log(`🔴 TRAILING STOP: ${trade.symbol}`) + await this.executeExit(trade, 100, 'SL', currentPrice) + } + + // BUG: Runner between TP1-TP2 has ZERO stop loss protection! + ``` + - **Fix:** Added explicit runner stop loss check at line ~795: + ```typescript + // CRITICAL: Check stop loss for runner (after TP1, before TP2) + if (trade.tp1Hit && !trade.tp2Hit && this.shouldStopLoss(currentPrice, trade)) { + console.log(`🔴 RUNNER STOP LOSS: ${trade.symbol} at ${profitPercent.toFixed(2)}% (profit lock triggered)`) + await this.executeExit(trade, 100, 'SL', currentPrice) + return + } + ``` + - **Verification:** After fix deployed, runner closed at $141.133 with +$0.59 profit (+4.6% on $12.70 runner) + - **Database evidence:** Trade shows `exitReason='SL'`, proving runner stop loss triggered correctly + - **Why undetected:** Runner system relatively new (Nov 11), most trades hit TP2 quickly without price reversals + - **Lesson:** Every conditional branch in risk management MUST have explicit stop loss checks - never assume "it'll get caught somewhere" + 34. **Flip-flop price context using wrong data (CRITICAL - Fixed Nov 14, 2025):** - **Symptom:** Flip-flop detection showing "100% price move" when actual movement was 0.2%, allowing trades that should be blocked - **Root Cause:** `currentPrice` parameter not available in check-risk endpoint (trade hasn't opened yet), so calculation used undefined/zero