Make TP2 the runner - no more partial closes

CHANGE: TP2 now activates trailing stop on full 25% remaining instead
of closing 80% and leaving 5% runner.

Benefits:
- 5x larger runner (25% vs 5%) = 25 vs 05 on 100 position
- Eliminates Drift minimum size issues completely
- Simplifies logic - no more canUseRunner() viability checks
- Better R:R on extended moves

New flow:
- TP1 (+0.4%): Close 75%, keep 25%
- TP2 (+0.7%): Skip close, activate trailing stop on full 25%
- Runner: 25% with ATR-based trailing (0.25-0.9%)

Config change: takeProfit2SizePercent: 80 → 0
Position Manager: Remove canUseRunner logic, activate trailing at TP2 hit
This commit is contained in:
mindesbunister
2025-11-07 15:29:50 +01:00
parent 36ba3809a1
commit 0c644ccabe
2 changed files with 15 additions and 52 deletions

View File

@@ -9,7 +9,6 @@ import { closePosition } from '../drift/orders'
import { getPythPriceMonitor, PriceUpdate } from '../pyth/price-monitor'
import { getMergedConfig, TradingConfig, getMarketConfig } from '../../config/trading'
import { updateTradeExit, updateTradeState, getOpenTrades } from '../database/trades'
import { canUseRunner, getViableTP2Percent } from './runner-calculator'
export interface ActiveTrade {
id: string
@@ -704,61 +703,24 @@ export class PositionManager {
await this.saveTradeState(trade)
}
// 5. Take profit 2 (remaining position)
// 5. TP2 Hit - Activate runner (no close, just start trailing)
if (trade.tp1Hit && !trade.tp2Hit && this.shouldTakeProfit2(currentPrice, trade)) {
console.log(`🎊 TP2 HIT: ${trade.symbol} at ${profitPercent.toFixed(2)}%`)
console.log(`🎊 TP2 HIT: ${trade.symbol} at ${profitPercent.toFixed(2)}% - Activating 25% runner!`)
// Check if runner would be viable with current position size
const runnerCheck = canUseRunner(
trade.symbol,
trade.currentSize,
currentPrice,
this.config.takeProfit1SizePercent,
this.config.takeProfit2SizePercent
// Mark TP2 as hit and activate trailing stop on full remaining 25%
trade.tp2Hit = true
trade.peakPrice = currentPrice
trade.runnerTrailingPercent = this.getRunnerTrailingPercent(trade)
console.log(
`🏃 Runner activated on full remaining position: ${((trade.currentSize / trade.positionSize) * 100).toFixed(1)}% | trailing buffer ${trade.runnerTrailingPercent?.toFixed(3)}%`
)
if (!runnerCheck.viable) {
console.log(`⚠️ Runner not viable: ${runnerCheck.reason}`)
console.log(` Skipping TP2 close, will use trailing stop on full 25% remaining`)
// Mark TP2 as "hit" but don't close anything - activate trailing on full 25%
trade.tp2Hit = true
trade.trailingStopActive = true
trade.runnerTrailingPercent = this.getRunnerTrailingPercent(trade)
console.log(
`🏃 Runner activated on full remaining position: ${((trade.currentSize / trade.positionSize) * 100).toFixed(1)}% | trailing buffer ${trade.runnerTrailingPercent?.toFixed(3)}%`
)
await this.saveTradeState(trade)
return
}
// Runner is viable - proceed with TP2 close
const percentToClose = this.config.takeProfit2SizePercent
console.log(`✅ Runner viable: ${runnerCheck.runnerSizeBase.toFixed(4)} base (${runnerCheck.runnerSizeUSD.toFixed(2)} USD)`)
await this.executeExit(trade, percentToClose, 'TP2', currentPrice)
// If some position remains, mark TP2 as hit and activate trailing stop
if (percentToClose < 100) {
trade.tp2Hit = true
trade.currentSize = trade.currentSize * ((100 - percentToClose) / 100)
trade.runnerTrailingPercent = this.getRunnerTrailingPercent(trade)
console.log(
`🏃 Runner activated: ${((trade.currentSize / trade.positionSize) * 100).toFixed(1)}% remaining | trailing buffer ${trade.runnerTrailingPercent?.toFixed(3)}%`
)
// Save state after TP2
await this.saveTradeState(trade)
}
// Save state after TP2 activation
await this.saveTradeState(trade)
return
}
// 6. Trailing stop for runner (after TP2)
} // 6. Trailing stop for runner (after TP2 activation)
if (trade.tp2Hit && this.config.useTrailingStop) {
// Check if trailing stop should be activated
if (!trade.trailingStopActive && profitPercent >= this.config.trailingStopActivation) {