critical: Fix Bug #1 - Smart Entry using wrong signal price
PROBLEM:
Smart Entry showed 'Signal Price: $70.80' when actual SOL price was ~$139.70
Calculated 'Pullback: -97.38%' when actual price change was <1%
Smart Entry queue completely broken due to wrong price
ROOT CAUSE:
TradingView webhook (or n8n workflow) sends pricePosition percentage (73.77)
as signalPrice instead of actual dollar price ($139.70)
Code used body.signalPrice directly without validation
EVIDENCE:
Webhook payload: "pricePosition": 73.7704918033, "signalPrice": 73.7704918033
Identical values = pricePosition mapped incorrectly to signalPrice
Percentage value (0-100) treated as dollar price = 100× too low
FIXES:
1. Added detection: If signalPrice < $10, log warning (likely percentage)
2. Changed signalPrice source: Use currentPrice from Pyth (NOT body.signalPrice)
3. At signal time: priceChange = 0, pullbackMagnitude = 0 (no pullback yet)
4. Queue with correct price: Smart Entry timer gets current market price
5. Added comments explaining bug and fix
IMPACT:
Smart Entry will now use correct signal price ($130-150 for SOL)
Pullback calculations will be accurate (0.15-0.5% range, not 97%)
Queue will work correctly (wait for actual dips/bounces)
Next signal will validate fix in production logs
TESTING REQUIRED:
- Wait for next signal (LONG or SHORT)
- Verify log: 'Signal Price: $XXX.XX (using current market price)'
- Verify log: 'Current Price: $XXX.XX (same as signal)'
- Verify: No more -97% pullback calculations
- Verify: Smart Entry queues correctly if no pullback yet
FILES CHANGED:
- app/api/trading/execute/route.ts lines 485-555 (rewritten Smart Entry logic)
LOCATION:
- Line 495: Added currentPrice null check
- Line 502: Added percentage detection warning
- Line 507: Changed to use currentPrice as signalPrice
- Line 509-511: Set priceChange/pullback to 0 at signal time
- Line 517: Queue with corrected signalPrice
RELATED:
- Bug #2: Leverage thresholds (FIXED separately, commit 58f812f)
- Bug #3: Missing Telegram entry notifications (pending investigation)
This commit is contained in:
@@ -489,40 +489,54 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
|
|||||||
if (smartEntryTimer.isEnabled() && body.signalPrice) {
|
if (smartEntryTimer.isEnabled() && body.signalPrice) {
|
||||||
console.log(`🎯 Smart Entry: Evaluating entry timing...`)
|
console.log(`🎯 Smart Entry: Evaluating entry timing...`)
|
||||||
|
|
||||||
// Get current price to check if already at favorable level
|
// CRITICAL FIX (Dec 3, 2025): Use current market price, not body.signalPrice
|
||||||
|
// Bug: TradingView webhook sends pricePosition (percentage 0-100) as signalPrice
|
||||||
|
// Result: Shows "$70.80" when actual price is $139.70, calculates wrong pullback
|
||||||
const priceMonitor = getPythPriceMonitor()
|
const priceMonitor = getPythPriceMonitor()
|
||||||
const latestPrice = priceMonitor.getCachedPrice(driftSymbol)
|
const latestPrice = priceMonitor.getCachedPrice(driftSymbol)
|
||||||
const currentPrice = latestPrice?.price || body.signalPrice
|
const currentPrice = latestPrice?.price
|
||||||
|
|
||||||
const priceChange = ((currentPrice - body.signalPrice) / body.signalPrice) * 100
|
if (!currentPrice) {
|
||||||
const isPullbackDirection = body.direction === 'long' ? priceChange < 0 : priceChange > 0
|
console.warn(`⚠️ Smart Entry: No current price available, skipping timing check`)
|
||||||
const pullbackMagnitude = Math.abs(priceChange)
|
} else {
|
||||||
|
// CRITICAL: Detect if body.signalPrice looks like percentage (< $10)
|
||||||
|
const signalPriceIsPercentage = body.signalPrice && body.signalPrice < 10
|
||||||
|
if (signalPriceIsPercentage) {
|
||||||
|
console.warn(`⚠️ signalPrice (${body.signalPrice.toFixed(2)}) looks like percentage, using current price instead`)
|
||||||
|
}
|
||||||
|
|
||||||
const pullbackMin = parseFloat(process.env.SMART_ENTRY_PULLBACK_MIN || '0.15')
|
// FIXED: Use current price as both signal and entry price (not body.signalPrice)
|
||||||
const pullbackMax = parseFloat(process.env.SMART_ENTRY_PULLBACK_MAX || '0.50')
|
const signalPrice = currentPrice
|
||||||
|
|
||||||
console.log(` Signal Price: $${body.signalPrice.toFixed(2)}`)
|
const priceChange = 0 // At signal time, price change is always 0
|
||||||
console.log(` Current Price: $${currentPrice.toFixed(2)} (${priceChange >= 0 ? '+' : ''}${priceChange.toFixed(2)}%)`)
|
const isPullbackDirection = false // No pullback yet
|
||||||
|
const pullbackMagnitude = 0
|
||||||
|
|
||||||
if (isPullbackDirection && pullbackMagnitude >= pullbackMin && pullbackMagnitude <= pullbackMax) {
|
const pullbackMin = parseFloat(process.env.SMART_ENTRY_PULLBACK_MIN || '0.15')
|
||||||
// Already at favorable entry - execute immediately!
|
const pullbackMax = parseFloat(process.env.SMART_ENTRY_PULLBACK_MAX || '0.50')
|
||||||
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
|
console.log(` Signal Price: $${signalPrice.toFixed(2)} (using current market price)`)
|
||||||
const queuedSignal = smartEntryTimer.queueSignal({
|
console.log(` Current Price: $${currentPrice.toFixed(2)} (same as signal)`)
|
||||||
symbol: driftSymbol,
|
|
||||||
direction: body.direction,
|
if (isPullbackDirection && pullbackMagnitude >= pullbackMin && pullbackMagnitude <= pullbackMax) {
|
||||||
signalPrice: body.signalPrice,
|
// Already at favorable entry - execute immediately!
|
||||||
atr: body.atr,
|
console.log(`✅ Smart Entry: Already at favorable level (${pullbackMagnitude.toFixed(2)}% pullback)`)
|
||||||
adx: body.adx,
|
console.log(` Executing immediately - no need to wait`)
|
||||||
rsi: body.rsi,
|
} else if (!isPullbackDirection || pullbackMagnitude < pullbackMin) {
|
||||||
volumeRatio: body.volumeRatio,
|
// Not favorable yet - queue for smart entry
|
||||||
pricePosition: body.pricePosition,
|
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 CORRECTED signal price (current market price)
|
||||||
|
const queuedSignal = smartEntryTimer.queueSignal({
|
||||||
|
symbol: driftSymbol,
|
||||||
|
direction: body.direction,
|
||||||
|
signalPrice: signalPrice, // FIXED: Use current price, not body.signalPrice
|
||||||
|
atr: body.atr,
|
||||||
|
adx: body.adx,
|
||||||
|
rsi: body.rsi,
|
||||||
|
volumeRatio: body.volumeRatio,
|
||||||
|
pricePosition: body.pricePosition,
|
||||||
indicatorVersion: body.indicatorVersion,
|
indicatorVersion: body.indicatorVersion,
|
||||||
qualityScore: qualityResult.score,
|
qualityScore: qualityResult.score,
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user