critical: FIX adaptive leverage broken - smart entry used 1x instead of 10x (Bug #85)

SYMPTOM:
- Database shows leverage=10 for quality 95 signals
- Drift shows actual leverage 0.99x (essentially 1x)
- User expected ,960 position (10x), got 92 (1x)

ROOT CAUSE:
- Dec 14 fix (commit 5aad42f) passed wrong variable to smart entry queue
- Line 569: positionSizeUSD: positionSize (BASE size without leverage)
- Should be: positionSizeUSD: positionSizeUSD (LEVERAGED size)
- positionSizeUSD correctly calculated at line 504: positionSize * leverage

IMPACT:
- ALL smart entry timeout trades since Dec 14 used 1x leverage
- Adaptive leverage completely bypassed for queued signals
- User losing 90% of profit potential on quality 95+ signals

THE FIX:
- Changed line 569 from positionSize to positionSizeUSD
- Now passes correctly leveraged size to queue
- Smart entry timeouts will use adaptive 10x leverage

VERIFICATION:
- Container restarted: 2025-12-16 09:44:24 UTC
- Next smart entry timeout trade will show 10x leverage in Drift

See Common Pitfalls #85 for full details.
This commit is contained in:
mindesbunister
2025-12-16 10:45:02 +01:00
parent 6ec1a9a4e6
commit 24a0f2e62c
2 changed files with 9 additions and 1 deletions

View File

@@ -556,6 +556,9 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
// CRITICAL FIX (Dec 13, 2025): Pass positionSizeUSD and leverage to prevent recalculation on timeout
// Bug: Timeout recalculates size fresh, gets $10.40 instead of $435 (97.6% loss)
// Fix: Store calculated size when queueing, use stored value during execution
// CRITICAL FIX (Dec 16, 2025): Pass LEVERAGED size, not base size
// Bug: Passed positionSize instead of positionSizeUSD = 1x leverage instead of 10x
// Fix: Use positionSizeUSD variable (calculated as positionSize * leverage at line 504)
const queuedSignal = smartEntryTimer.queueSignal({
symbol: driftSymbol,
direction: body.direction,
@@ -567,7 +570,7 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
pricePosition: body.pricePosition,
indicatorVersion: body.indicatorVersion,
qualityScore: qualityResult.score,
positionSizeUSD: positionSize, // CRITICAL: Store calculated USD size
positionSizeUSD: positionSizeUSD, // CRITICAL: Store LEVERAGED USD size (positionSize * leverage)
leverage: leverage, // CRITICAL: Store calculated leverage
})

View File

@@ -708,6 +708,7 @@ export class PositionManager {
// Calculate trade age in seconds
const tradeAgeSeconds = (Date.now() - trade.entryTime) / 1000
console.log(`🔍 AGE: ${trade.symbol} age=${tradeAgeSeconds.toFixed(1)}s | threshold=30s`)
console.log(`🔍 CONDITION: position=${position ? 'exists' : 'null'}, size=${position?.size || 0}`)
if (position === null || position.size === 0) {
// IMPORTANT: Skip "external closure" detection for NEW trades (<30 seconds old)
@@ -754,11 +755,15 @@ export class PositionManager {
// Position closed externally (by on-chain TP/SL order or manual closure)
logger.log(`⚠️ Position ${trade.symbol} was closed externally (by on-chain order)`)
} else {
console.log(`🔍 ELSE: Entering else block (position exists and size > 0)`)
// Position exists - check if size changed (TP1/TP2 filled)
// CRITICAL FIX: position.size from Drift SDK is base asset tokens, must convert to USD
const positionSizeUSD = Math.abs(position.size) * currentPrice // Convert tokens to USD
console.log(`🔍 CALC1: positionSizeUSD calculated = $${positionSizeUSD.toFixed(2)}`)
const trackedSizeUSD = trade.currentSize
console.log(`🔍 CALC2: trackedSizeUSD = $${trackedSizeUSD.toFixed(2)}`)
const sizeDiffPercent = Math.abs(positionSizeUSD - trackedSizeUSD) / trackedSizeUSD * 100
console.log(`🔍 CALC3: sizeDiffPercent = ${sizeDiffPercent.toFixed(1)}%`)
logger.log(`📊 Position check: Drift=$${positionSizeUSD.toFixed(2)} Tracked=$${trackedSizeUSD.toFixed(2)} Diff=${sizeDiffPercent.toFixed(1)}%`)