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:
mindesbunister
2025-11-24 00:47:09 +01:00
parent 1e64e8145b
commit bfdb0ba779
4 changed files with 85 additions and 23 deletions

View File

@@ -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({