Fix: Critical bugs - TP2 runner calculation + race condition + order cleanup
**Issue 1: TP2 Runner Position Bug** ✅ FIXED - TP2 was calculated as 80% of ORIGINAL position instead of REMAINING - With TP1=75%, TP2=80%: Was closing 75%+80%=155% (capped at 100%) - Now correctly: TP1 closes 75%, TP2 closes 80% of remaining 25% = 20% - Result: 5% runner now remains for trailing stop as intended! **Issue 2: Race Condition - Orphaned SL Orders** ✅ FIXED - Orders were placed AFTER Position Manager started monitoring - If TP hit fast, PM detected 'external closure' before orders finished - Orders completed after position gone → orphaned SL orders on Drift - Now: Exit orders placed BEFORE starting monitoring - PM can now properly cancel remaining orders when position closes **Issue 3: 5min vs 15min Timeframe** ⚠️ NEEDS VERIFICATION - n8n workflow correctly filters for timeframe === '15' - Extracts timeframe with regex: /\.P\s+(\d+)/ - User needs to verify TradingView alert includes '.P 15' in message - Format should be: 'SOL buy .P 15' not just 'SOL buy' **Technical Changes:** - lib/drift/orders.ts: Fixed TP2 calculation to use remaining size - Added logging: Shows TP1, TP2, remaining, and runner amounts - app/api/trading/execute/route.ts: Reordered to place orders before monitoring - Prevents race condition where orders complete after position closed **Testing:** - Next trade will show proper runner position (5% remains) - No more orphaned SL orders after wins - Logs will show: 'Runner (if any): $X.XX' **Documentation:** - Created CRITICAL_ISSUES_FOUND.md explaining all 3 issues - Created FIXES_APPLIED.md with testing instructions
This commit is contained in:
@@ -243,31 +243,9 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
|
||||
lastUpdateTime: Date.now(),
|
||||
}
|
||||
|
||||
// Add to position manager for monitoring (reuse positionManager from above)
|
||||
await positionManager.addTrade(activeTrade)
|
||||
|
||||
console.log('✅ Trade added to position manager for monitoring')
|
||||
|
||||
// Create response object
|
||||
const response: ExecuteTradeResponse = {
|
||||
success: true,
|
||||
positionId: openResult.transactionSignature,
|
||||
symbol: driftSymbol,
|
||||
direction: body.direction,
|
||||
entryPrice: entryPrice,
|
||||
positionSize: positionSizeUSD,
|
||||
leverage: config.leverage,
|
||||
stopLoss: stopLossPrice,
|
||||
takeProfit1: tp1Price,
|
||||
takeProfit2: tp2Price,
|
||||
stopLossPercent: config.stopLossPercent,
|
||||
tp1Percent: config.takeProfit1Percent,
|
||||
tp2Percent: config.takeProfit2Percent,
|
||||
entrySlippage: openResult.slippage,
|
||||
timestamp: new Date().toISOString(),
|
||||
}
|
||||
|
||||
// Place on-chain TP/SL orders so they appear in Drift UI (reduce-only LIMIT orders)
|
||||
// CRITICAL FIX: Place on-chain TP/SL orders BEFORE adding to Position Manager
|
||||
// This prevents race condition where Position Manager detects "external closure"
|
||||
// while orders are still being placed, leaving orphaned stop loss orders
|
||||
let exitOrderSignatures: string[] = []
|
||||
try {
|
||||
const exitRes = await placeExitOrders({
|
||||
@@ -292,15 +270,39 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
|
||||
console.log('📨 Exit orders placed on-chain:', exitRes.signatures)
|
||||
exitOrderSignatures = exitRes.signatures || []
|
||||
}
|
||||
|
||||
// Attach signatures to response when available
|
||||
if (exitRes.signatures && exitRes.signatures.length > 0) {
|
||||
;(response as any).exitOrderSignatures = exitRes.signatures
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('❌ Unexpected error placing exit orders:', err)
|
||||
}
|
||||
|
||||
// Add to position manager for monitoring AFTER orders are placed
|
||||
await positionManager.addTrade(activeTrade)
|
||||
|
||||
console.log('✅ Trade added to position manager for monitoring')
|
||||
|
||||
// Create response object
|
||||
const response: ExecuteTradeResponse = {
|
||||
success: true,
|
||||
positionId: openResult.transactionSignature,
|
||||
symbol: driftSymbol,
|
||||
direction: body.direction,
|
||||
entryPrice: entryPrice,
|
||||
positionSize: positionSizeUSD,
|
||||
leverage: config.leverage,
|
||||
stopLoss: stopLossPrice,
|
||||
takeProfit1: tp1Price,
|
||||
takeProfit2: tp2Price,
|
||||
stopLossPercent: config.stopLossPercent,
|
||||
tp1Percent: config.takeProfit1Percent,
|
||||
tp2Percent: config.takeProfit2Percent,
|
||||
entrySlippage: openResult.slippage,
|
||||
timestamp: new Date().toISOString(),
|
||||
}
|
||||
|
||||
// Attach exit order signatures to response
|
||||
if (exitOrderSignatures.length > 0) {
|
||||
(response as any).exitOrderSignatures = exitOrderSignatures
|
||||
}
|
||||
|
||||
// Save trade to database
|
||||
try {
|
||||
await createTrade({
|
||||
|
||||
Reference in New Issue
Block a user