feat: Phase 2 Smart Entry Timing - COMPLETE

Implementation of 1-minute data enhancements Phase 2:
- Queue signals when price not at favorable pullback level
- Monitor every 15s for 0.15-0.5% pullback (LONG=dip, SHORT=bounce)
- Validate ADX hasn't dropped >2 points (trend still strong)
- Timeout at 2 minutes → execute at current price
- Expected improvement: 0.2-0.5% per trade = ,600-4,000 over 100 trades

Files:
- lib/trading/smart-entry-timer.ts (616 lines, zero TS errors)
- app/api/trading/execute/route.ts (integrated smart entry check)
- .env (SMART_ENTRY_* configuration, disabled by default)

Next steps:
- Test with SMART_ENTRY_ENABLED=true in development
- Monitor first 5-10 trades for improvement verification
- Enable in production after successful testing
This commit is contained in:
mindesbunister
2025-11-27 11:40:23 +01:00
parent cecdb8290c
commit a8c1b2ca06
4 changed files with 711 additions and 1 deletions

View File

@@ -16,6 +16,7 @@ import { scoreSignalQuality } from '@/lib/trading/signal-quality'
import { getMarketDataCache } from '@/lib/trading/market-data-cache'
import { getPythPriceMonitor } from '@/lib/pyth/price-monitor'
import { logCriticalError, logTradeExecution } from '@/lib/utils/persistent-logger'
import { getSmartEntryTimer } from '@/lib/trading/smart-entry-timer'
export interface ExecuteTradeRequest {
symbol: string // TradingView symbol (e.g., 'SOLUSDT')
@@ -427,6 +428,73 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
console.log(` Leverage: ${leverage}x`)
console.log(` Total position: $${positionSizeUSD}`)
// 🎯 SMART ENTRY TIMING - Check if we should wait for better entry (Phase 2 - Nov 27, 2025)
const smartEntryTimer = getSmartEntryTimer()
if (smartEntryTimer.isEnabled() && body.signalPrice) {
console.log(`🎯 Smart Entry: Evaluating entry timing...`)
// Get current price to check if already at favorable level
const priceMonitor = getPythPriceMonitor()
const latestPrice = priceMonitor.getCachedPrice(driftSymbol)
const currentPrice = latestPrice?.price || body.signalPrice
const priceChange = ((currentPrice - body.signalPrice) / body.signalPrice) * 100
const isPullbackDirection = body.direction === 'long' ? priceChange < 0 : priceChange > 0
const pullbackMagnitude = Math.abs(priceChange)
const pullbackMin = parseFloat(process.env.SMART_ENTRY_PULLBACK_MIN || '0.15')
const pullbackMax = parseFloat(process.env.SMART_ENTRY_PULLBACK_MAX || '0.50')
console.log(` Signal Price: $${body.signalPrice.toFixed(2)}`)
console.log(` Current Price: $${currentPrice.toFixed(2)} (${priceChange >= 0 ? '+' : ''}${priceChange.toFixed(2)}%)`)
if (isPullbackDirection && pullbackMagnitude >= pullbackMin && pullbackMagnitude <= pullbackMax) {
// Already at favorable entry - execute immediately!
console.log(`✅ Smart Entry: Already at favorable level (${pullbackMagnitude.toFixed(2)}% pullback)`)
console.log(` Executing immediately - no need to wait`)
} else if (!isPullbackDirection || pullbackMagnitude < pullbackMin) {
// Not favorable yet - queue for smart entry
console.log(`⏳ Smart Entry: Queuing signal for optimal entry timing`)
console.log(` Waiting for ${body.direction === 'long' ? 'dip' : 'bounce'} of ${pullbackMin}-${pullbackMax}%`)
// Queue the signal with full context
const queuedSignal = smartEntryTimer.queueSignal({
symbol: driftSymbol,
direction: body.direction,
signalPrice: body.signalPrice,
atr: body.atr,
adx: body.adx,
rsi: body.rsi,
volumeRatio: body.volumeRatio,
pricePosition: body.pricePosition,
indicatorVersion: body.indicatorVersion,
qualityScore: qualityResult.score,
})
// Return success immediately (n8n workflow continues)
return NextResponse.json({
success: true,
message: 'Signal queued for smart entry timing',
smartEntry: {
enabled: true,
queuedAt: new Date().toISOString(),
signalId: queuedSignal.id,
targetPullback: `${pullbackMin}-${pullbackMax}%`,
maxWait: `${parseInt(process.env.SMART_ENTRY_MAX_WAIT_MS || '120000') / 1000}s`,
currentPullback: `${priceChange.toFixed(2)}%`,
},
positionId: `queued-${queuedSignal.id}`,
symbol: driftSymbol,
direction: body.direction,
qualityScore: qualityResult.score,
}, { status: 200 })
} else if (pullbackMagnitude > pullbackMax) {
// Pullback too large - might be reversal, execute with caution
console.log(`⚠️ Smart Entry: Pullback too large (${pullbackMagnitude.toFixed(2)}% > ${pullbackMax}%)`)
console.log(` Possible reversal - executing at current price with caution`)
}
}
// Helper function for rate limit spacing
const rpcDelay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))