# ATR-Based Trailing Stop Fix - Nov 11, 2025 ## Problem Identified **Critical Bug:** Runner system was using FIXED 0.3% trailing stop, causing profitable runners to exit immediately. **Evidence:** - Recent trades showing MFE of +7-9% but exiting for losses or minimal gains - Example: Entry $167.82, MFE +7.01%, exit $168.91 for **-$2.68 loss** - At $168 SOL price: 0.3% = only **$0.50 wiggle room** before stop hits - Normal price volatility easily triggers 0.3% retracement **Documentation Claim vs Reality:** - Docs claimed "ATR-based trailing stop" - Code was using `this.config.trailingStopPercent` (fixed 0.3%) - Config already had `trailingStopAtrMultiplier` parameter but it wasn't being used! ## Solution Implemented ### 1. Position Manager Update (`lib/trading/position-manager.ts`) **Changed trailing stop calculation from fixed to ATR-based:** ```typescript // OLD (BROKEN): const trailingStopPrice = this.calculatePrice( trade.peakPrice, -this.config.trailingStopPercent, // Fixed 0.3% trade.direction ) // NEW (FIXED): if (trade.atrAtEntry && trade.atrAtEntry > 0) { // ATR-based: Use ATR% * multiplier const atrPercent = (trade.atrAtEntry / currentPrice) * 100 const rawDistance = atrPercent * this.config.trailingStopAtrMultiplier // Clamp between min and max trailingDistancePercent = Math.max( this.config.trailingStopMinPercent, Math.min(this.config.trailingStopMaxPercent, rawDistance) ) } else { // Fallback to configured percent with clamping trailingDistancePercent = Math.max( this.config.trailingStopMinPercent, Math.min(this.config.trailingStopMaxPercent, this.config.trailingStopPercent) ) } ``` ### 2. Added `atrAtEntry` to ActiveTrade Interface ```typescript export interface ActiveTrade { // Entry details entryPrice: number entryTime: number positionSize: number leverage: number atrAtEntry?: number // NEW: ATR value at entry for ATR-based trailing stop // ... } ``` ### 3. Settings UI Updates (`app/settings/page.tsx`) Added new fields for ATR trailing configuration: - **ATR Trailing Multiplier** (1.0-3.0x, default 1.5x) - **Min Trailing Distance** (0.1-1.0%, default 0.25%) - **Max Trailing Distance** (0.5-2.0%, default 0.9%) - Changed "Trailing Stop Distance" label to "[FALLBACK]" ### 4. Environment Variables (`.env.example`) ```bash # ATR-based Trailing Stop (for 25% runner after TP2) # Trailing distance = (ATR × multiplier) # Example: 0.5% ATR × 1.5 = 0.75% trailing (more room than fixed 0.3%) TRAILING_STOP_ATR_MULTIPLIER=1.5 TRAILING_STOP_MIN_PERCENT=0.25 TRAILING_STOP_MAX_PERCENT=0.9 TRAILING_STOP_ACTIVATION=0.5 ``` ## Expected Impact ### Before Fix (0.3% Fixed) - SOL at $168: 0.3% = $0.50 wiggle room - Normal 2-minute oscillation kills runner immediately - Runners with +7-9% MFE captured minimal profit or even lost money ### After Fix (ATR-based) **Recent ATR distribution from database:** ```sql -- Most common ATR values: 0.25-0.52% -- At 1.5x multiplier: 0.25% ATR × 1.5 = 0.375% trail 0.37% ATR × 1.5 = 0.555% trail 0.45% ATR × 1.5 = 0.675% trail 0.52% ATR × 1.5 = 0.780% trail ``` **Typical improvement:** - Old: $0.50 wiggle room ($168 × 0.3%) - New: $1.12 wiggle room ($168 × 0.67% avg) - **2.24x more room for runner to breathe!** **Volatility adaptation:** - Low ATR (0.25%): 0.375% trail = $0.63 @ $168 - High ATR (0.72%): 0.9% trail cap = $1.51 @ $168 (max cap) - Automatically adjusts to market conditions ## Verification Logs When runner activates, you'll now see: ``` 🎯 Trailing stop activated at +0.65% 📊 ATR-based trailing: 0.0045 (0.52%) × 1.5x = 0.78% 📈 Trailing SL updated: 168.50 → 167.20 (0.78% below peak $168.91) ``` Instead of: ``` ⚠️ No ATR data, using fallback: 0.30% 📈 Trailing SL updated: 168.50 → 168.41 (0.30% below peak $168.91) ``` ## Testing 1. **Existing open trades:** Will use fallback 0.3% (no atrAtEntry yet) 2. **New trades:** Will capture ATR at entry and use ATR-based trailing 3. **Settings UI:** Update multiplier at http://localhost:3001/settings 4. **Log verification:** Check for "📊 ATR-based trailing" messages ## Files Modified 1. ✅ `lib/trading/position-manager.ts` - ATR-based trailing calculation + interface 2. ✅ `app/settings/page.tsx` - UI for ATR multiplier controls 3. ✅ `.env.example` - Documentation for new variables 4. ✅ `config/trading.ts` - Already had the config (wasn't being used!) ## Deployment ```bash docker compose build trading-bot docker compose up -d --force-recreate trading-bot docker logs -f trading-bot-v4 ``` **Status:** ✅ **DEPLOYED AND RUNNING** ## Next Steps 1. **Monitor next runner:** Watch for "📊 ATR-based trailing" in logs 2. **Compare MFE vs realized P&L:** Should capture 50%+ of MFE (vs current 5-10%) 3. **Adjust multiplier if needed:** May increase to 2.0x after seeing results 4. **Update copilot-instructions.md:** Document this fix after validation ## Related Issues - Fixes the morning's missed opportunity: $172→$162 drop would have been captured - Addresses "trades showing +7% MFE but -$2 loss" pattern - Makes the 25% runner system actually useful (vs broken 5% system) ## Key Insight **The config system was already built for this!** The `trailingStopAtrMultiplier` parameter existed in DEFAULT_TRADING_CONFIG and getConfigFromEnv() since the TP2-as-runner redesign. The Position Manager just wasn't using it. This was a "90% done but not wired up" situation.