feat: ADX-based adaptive runner SL positioning after TP1
Implements intelligent runner protection based on trend strength:
ADX-based SL positioning (Nov 19, 2025):
- ADX < 20: SL at 0% (breakeven) - Weak trend, preserve capital
- ADX 20-25: SL at -0.3% - Moderate trend, some retracement room
- ADX > 25: SL at -0.55% - Strong trend, full retracement tolerance
Rationale:
- User observation: Entry at candle close = always at top
- Screenshots showed -1% to -1.5% pullbacks even on valid trends
- Fixed -0.55% SL would cause unnecessary losses on weak trends
- Adaptive approach: Protect capital when trend weak, give room when strong
Benefits:
1. Capital preservation: Weak trends (ADX <20) get breakeven SL
2. Optimized risk/reward: Only risk runner drawdown on high-probability setups
3. Data-driven thresholds: Based on historical ADX distribution (18-32 range)
4. Complements ADX trailing stop multiplier (also trend-strength adaptive)
Example scenarios:
- ADX 18 (weak): TP1 +$38.70, Runner SL at breakeven → Total: +$38.70
- ADX 29 (strong): TP1 +$38.70, Runner SL at -0.55% → Survives pullback, captures big move
Logging:
- Shows ADX value and selected SL percentage
- Format: "🔒 ADX-based runner SL: 29.3 → -0.55% (60% closed, 40% remaining): $139.23"
Data collection phase:
- After 50-100 trades, will analyze optimal ADX thresholds
- May adjust breakpoints (20/25) based on actual performance
- Tracks runner stop-out rate vs ADX for optimization
Files changed:
- lib/trading/position-manager.ts: ADX-based SL calculation in TP1 handler
- Replaces fixed PROFIT_LOCK_AFTER_TP1_PERCENT with dynamic logic
- Uses trade.adxAtEntry (already tracked in database)
This commit is contained in:
@@ -1061,15 +1061,29 @@ export class PositionManager {
|
||||
|
||||
await this.executeExit(trade, this.config.takeProfit1SizePercent, 'TP1', currentPrice)
|
||||
trade.currentSize = trade.positionSize * ((100 - this.config.takeProfit1SizePercent) / 100)
|
||||
|
||||
// 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, preserve capital
|
||||
} else if (adx < 25) {
|
||||
runnerSlPercent = -0.3 // Moderate trend: some room
|
||||
} else {
|
||||
runnerSlPercent = -0.55 // Strong trend: full retracement room
|
||||
}
|
||||
|
||||
const newStopLossPrice = this.calculatePrice(
|
||||
trade.entryPrice,
|
||||
this.config.profitLockAfterTP1Percent, // Lock profit on remaining position
|
||||
runnerSlPercent,
|
||||
trade.direction
|
||||
)
|
||||
trade.stopLossPrice = newStopLossPrice
|
||||
trade.slMovedToBreakeven = true
|
||||
|
||||
console.log(`🔒 SL moved to lock +${this.config.profitLockAfterTP1Percent}% profit (${this.config.takeProfit1SizePercent}% closed, ${100 - this.config.takeProfit1SizePercent}% remaining): ${newStopLossPrice.toFixed(4)}`)
|
||||
console.log(`🔒 ADX-based runner SL: ${adx.toFixed(1)} → ${runnerSlPercent}% (${this.config.takeProfit1SizePercent}% closed, ${100 - this.config.takeProfit1SizePercent}% remaining): ${newStopLossPrice.toFixed(4)}`)
|
||||
|
||||
// CRITICAL: Cancel old on-chain SL orders and place new ones at updated price
|
||||
// BUT: Only if this is the ONLY active trade on this symbol
|
||||
|
||||
Reference in New Issue
Block a user