feat: Implement adaptive leverage based on signal quality score
- Quality-based risk adjustment: 95+ = 15x, 90-94 = 10x, <90 = blocked - Data-driven decision: v8 quality 95+ = 100% WR (4/4 wins) - Config fields: useAdaptiveLeverage, highQualityLeverage, lowQualityLeverage, qualityLeverageThreshold - Helper function: getLeverageForQualityScore() returns appropriate leverage tier - Position sizing: Modified getActualPositionSizeForSymbol() to accept optional qualityScore param - Execute endpoint: Calculate quality score early (before sizing) for leverage determination - Test endpoint: Uses quality 100 for maximum leverage on manual test trades - ENV variables: USE_ADAPTIVE_LEVERAGE, HIGH_QUALITY_LEVERAGE, LOW_QUALITY_LEVERAGE, QUALITY_LEVERAGE_THRESHOLD - Impact: 33% less exposure on borderline quality signals (90-94) - Example: $540 × 10x = $5,400 vs $8,100 (saves $2,700 exposure on volatile signals) - Files changed: * config/trading.ts (interface, config, ENV, helper function, position sizing) * app/api/trading/execute/route.ts (early quality calculation, pass to sizing) * app/api/trading/test/route.ts (quality 100 for test trades)
This commit is contained in:
@@ -167,12 +167,28 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
|
||||
const health = await driftService.getAccountHealth()
|
||||
console.log(`🩺 Account health: Free collateral $${health.freeCollateral.toFixed(2)}`)
|
||||
|
||||
// Get symbol-specific position sizing (supports percentage-based sizing)
|
||||
// Calculate quality score EARLY for adaptive leverage (Nov 24, 2025)
|
||||
// This needs to happen before position sizing so leverage can be adjusted based on quality
|
||||
const qualityResult = await scoreSignalQuality({
|
||||
atr: body.atr || 0,
|
||||
adx: body.adx || 0,
|
||||
rsi: body.rsi || 0,
|
||||
volumeRatio: body.volumeRatio || 0,
|
||||
pricePosition: body.pricePosition || 0,
|
||||
direction: body.direction,
|
||||
symbol: driftSymbol,
|
||||
currentPrice: body.signalPrice || 0,
|
||||
timeframe: body.timeframe,
|
||||
})
|
||||
console.log(`📊 Signal quality score: ${qualityResult.score} (calculated early for adaptive leverage)`)
|
||||
|
||||
// Get symbol-specific position sizing with quality score for adaptive leverage
|
||||
const { getActualPositionSizeForSymbol } = await import('@/config/trading')
|
||||
const { size: positionSize, leverage, enabled, usePercentage } = await getActualPositionSizeForSymbol(
|
||||
driftSymbol,
|
||||
config,
|
||||
health.freeCollateral
|
||||
health.freeCollateral,
|
||||
qualityResult.score // Pass quality score for adaptive leverage
|
||||
)
|
||||
|
||||
// Check if trading is enabled for this symbol
|
||||
@@ -748,23 +764,9 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
|
||||
console.log('🔍 DEBUG: Exit orders section complete, about to calculate quality score...')
|
||||
|
||||
// Save trade to database FIRST (CRITICAL: Must succeed before Position Manager)
|
||||
let qualityResult
|
||||
try {
|
||||
// Calculate quality score if metrics available
|
||||
console.log('🔍 DEBUG: Calling scoreSignalQuality()...')
|
||||
qualityResult = await scoreSignalQuality({
|
||||
atr: body.atr || 0,
|
||||
adx: body.adx || 0,
|
||||
rsi: body.rsi || 0,
|
||||
volumeRatio: body.volumeRatio || 0,
|
||||
pricePosition: body.pricePosition || 0,
|
||||
direction: body.direction,
|
||||
symbol: driftSymbol,
|
||||
currentPrice: openResult.fillPrice,
|
||||
timeframe: body.timeframe,
|
||||
})
|
||||
|
||||
console.log('🔍 DEBUG: scoreSignalQuality() completed, score:', qualityResult.score)
|
||||
// Quality score already calculated earlier for adaptive leverage
|
||||
console.log('🔍 DEBUG: Using quality score from earlier calculation:', qualityResult.score)
|
||||
console.log('🔍 DEBUG: About to call createTrade()...')
|
||||
|
||||
await createTrade({
|
||||
|
||||
@@ -74,11 +74,13 @@ export async function POST(request: NextRequest): Promise<NextResponse<TestTrade
|
||||
}
|
||||
|
||||
// Get symbol-specific position sizing (with percentage support)
|
||||
// Test trades use quality score 100 for maximum leverage (manual override)
|
||||
const { getActualPositionSizeForSymbol } = await import('@/config/trading')
|
||||
const { size: positionSize, leverage, enabled, usePercentage } = await getActualPositionSizeForSymbol(
|
||||
driftSymbol,
|
||||
config,
|
||||
health.freeCollateral
|
||||
health.freeCollateral,
|
||||
100 // Test trades always use max leverage (quality 100)
|
||||
)
|
||||
|
||||
// Check if trading is enabled for this symbol
|
||||
|
||||
Reference in New Issue
Block a user