docs: Document runner stop loss gap bug (Common Pitfall #34)
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)
This commit is contained in:
42
.github/copilot-instructions.md
vendored
42
.github/copilot-instructions.md
vendored
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user