fix(blocked-signals): Add 3-tier price fallback to prevent entryPrice=0

- Root cause: Pyth cache empty caused entryPrice=0 in BlockedSignal records
- Solution: getCurrentPrice() helper with Pyth → Drift oracle → TradingView fallback
- Updated 3 createBlockedSignal callsites (QUALITY, COOLDOWN, HOURLY_LIMIT)
- Impact: Enables accurate what-if analysis for threshold optimization
- Files: app/api/trading/check-risk/route.ts (added getCurrentPrice, updated 3 calls)
- Deployed: Nov 25, 2025 22:55 UTC (container verified running new code)
- Testing: Next blocked signal will verify entryPrice != 0 in database
This commit is contained in:
mindesbunister
2025-11-25 23:56:55 +01:00
parent bdd25e4d7b
commit 1b6131be5f

View File

@@ -11,6 +11,8 @@ import { getInitializedPositionManager, ActiveTrade } from '@/lib/trading/positi
import { getLastTradeTime, getLastTradeTimeForSymbol, getTradesInLastHour, getTodayPnL, createBlockedSignal } from '@/lib/database/trades'
import { getPythPriceMonitor } from '@/lib/pyth/price-monitor'
import { scoreSignalQuality, SignalQualityResult } from '@/lib/trading/signal-quality'
import { initializeDriftService } from '@/lib/drift/client'
import { SUPPORTED_MARKETS } from '@/config/trading'
export interface RiskCheckRequest {
symbol: string
@@ -33,6 +35,41 @@ export interface RiskCheckResponse {
qualityReasons?: string[]
}
/**
* Get current price reliably using multiple fallback methods
* Priority: Pyth cache → Drift oracle → TradingView signal price
*/
async function getCurrentPrice(symbol: string, fallbackPrice?: number): Promise<number> {
// Try Pyth cache first (fastest)
const priceMonitor = getPythPriceMonitor()
const latestPrice = priceMonitor.getCachedPrice(symbol)
if (latestPrice?.price && latestPrice.price > 0) {
return latestPrice.price
}
// Try Drift oracle (authoritative)
try {
const driftService = await initializeDriftService()
const marketConfig = SUPPORTED_MARKETS[symbol]
if (marketConfig && driftService) {
const oraclePrice = await driftService.getOraclePrice(marketConfig.driftMarketIndex)
if (oraclePrice > 0) {
return oraclePrice
}
}
} catch (error) {
console.warn('⚠️ Failed to get Drift oracle price:', error)
}
// Fallback to TradingView signal price
if (fallbackPrice && fallbackPrice > 0) {
return fallbackPrice
}
console.error('❌ Unable to get current price from any source')
return 0
}
/**
* Position Scaling Validation
* Determines if adding to an existing position is allowed
@@ -248,14 +285,13 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
// Save blocked signal if we have metrics
if (hasContextMetrics) {
const priceMonitor = getPythPriceMonitor()
const latestPrice = priceMonitor.getCachedPrice(body.symbol)
const currentPrice = await getCurrentPrice(body.symbol, body.currentPrice)
await createBlockedSignal({
symbol: body.symbol,
direction: body.direction,
timeframe: body.timeframe,
signalPrice: latestPrice?.price || 0,
signalPrice: currentPrice,
atr: body.atr,
adx: body.adx,
rsi: body.rsi,
@@ -294,14 +330,13 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
// Save blocked signal if we have metrics
if (hasContextMetrics) {
const priceMonitor = getPythPriceMonitor()
const latestPrice = priceMonitor.getCachedPrice(body.symbol)
const currentPrice = await getCurrentPrice(body.symbol, body.currentPrice)
await createBlockedSignal({
symbol: body.symbol,
direction: body.direction,
timeframe: body.timeframe,
signalPrice: latestPrice?.price || 0,
signalPrice: currentPrice,
atr: body.atr,
adx: body.adx,
rsi: body.rsi,
@@ -354,15 +389,14 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
})
// Get current price for the blocked signal record
const priceMonitor = getPythPriceMonitor()
const latestPrice = priceMonitor.getCachedPrice(body.symbol)
const currentPrice = await getCurrentPrice(body.symbol, body.currentPrice)
// Save blocked signal to database for future analysis
await createBlockedSignal({
symbol: body.symbol,
direction: body.direction,
timeframe: body.timeframe,
signalPrice: latestPrice?.price || 0,
signalPrice: currentPrice,
atr: body.atr,
adx: body.adx,
rsi: body.rsi,