remove: V10 momentum system - backtest proved it adds no value
- Removed v10 TradingView indicator (moneyline_v10_momentum_dots.pinescript) - Removed v10 penalty system from signal-quality.ts (-30/-25 point penalties) - Removed backtest result files (sweep_*.csv) - Updated copilot-instructions.md to remove v10 references - Simplified direction-specific quality thresholds (LONG 90+, SHORT 80+) Rationale: - 1,944 parameter combinations tested in backtest - All top results IDENTICAL (568 trades, $498 P&L, 61.09% WR) - Momentum parameters had ZERO impact on trade selection - Profit factor 1.027 too low (barely profitable after fees) - Max drawdown -$1,270 vs +$498 profit = terrible risk-reward - v10 penalties were blocking good trades (bug: applied to wrong positions) Keeping v9 as production system - simpler, proven, effective.
This commit is contained in:
@@ -19,6 +19,8 @@ export interface RiskCheckRequest {
|
||||
direction: 'long' | 'short'
|
||||
timeframe?: string // e.g., "5" for 5min, "60" for 1H, "D" for daily
|
||||
currentPrice?: number // Current market price (for flip-flop context)
|
||||
signalPrice?: number // TradingView-provided price snapshot
|
||||
indicatorVersion?: string // Pine Script version tag (v8/v9/v10)
|
||||
// Optional context metrics from TradingView
|
||||
atr?: number
|
||||
adx?: number
|
||||
@@ -183,6 +185,7 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
|
||||
}
|
||||
|
||||
const body: RiskCheckRequest = await request.json()
|
||||
const fallbackPrice = body.currentPrice ?? body.signalPrice
|
||||
|
||||
console.log('🔍 Risk check for:', body)
|
||||
|
||||
@@ -287,23 +290,28 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
|
||||
|
||||
// Save blocked signal if we have metrics
|
||||
if (hasContextMetrics) {
|
||||
const currentPrice = await getCurrentPrice(body.symbol, body.currentPrice)
|
||||
const currentPrice = await getCurrentPrice(body.symbol, fallbackPrice)
|
||||
|
||||
await createBlockedSignal({
|
||||
symbol: body.symbol,
|
||||
direction: body.direction,
|
||||
timeframe: body.timeframe,
|
||||
signalPrice: currentPrice,
|
||||
atr: body.atr,
|
||||
adx: body.adx,
|
||||
rsi: body.rsi,
|
||||
volumeRatio: body.volumeRatio,
|
||||
pricePosition: body.pricePosition,
|
||||
signalQualityScore: 0, // Not calculated yet
|
||||
minScoreRequired: config.minSignalQualityScore,
|
||||
blockReason: 'HOURLY_TRADE_LIMIT',
|
||||
blockDetails: `${tradesInLastHour} trades in last hour (max: ${config.maxTradesPerHour})`,
|
||||
})
|
||||
if (currentPrice > 0) {
|
||||
await createBlockedSignal({
|
||||
symbol: body.symbol,
|
||||
direction: body.direction,
|
||||
timeframe: body.timeframe,
|
||||
signalPrice: currentPrice,
|
||||
atr: body.atr,
|
||||
adx: body.adx,
|
||||
rsi: body.rsi,
|
||||
volumeRatio: body.volumeRatio,
|
||||
pricePosition: body.pricePosition,
|
||||
signalQualityScore: 0, // Not calculated yet
|
||||
minScoreRequired: config.minSignalQualityScore,
|
||||
blockReason: 'HOURLY_TRADE_LIMIT',
|
||||
blockDetails: `${tradesInLastHour} trades in last hour (max: ${config.maxTradesPerHour})`,
|
||||
indicatorVersion: body.indicatorVersion || 'v5',
|
||||
})
|
||||
} else {
|
||||
console.warn('⚠️ Skipping blocked signal save: price unavailable (hourly limit)')
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
@@ -332,23 +340,28 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
|
||||
|
||||
// Save blocked signal if we have metrics
|
||||
if (hasContextMetrics) {
|
||||
const currentPrice = await getCurrentPrice(body.symbol, body.currentPrice)
|
||||
const currentPrice = await getCurrentPrice(body.symbol, fallbackPrice)
|
||||
|
||||
await createBlockedSignal({
|
||||
symbol: body.symbol,
|
||||
direction: body.direction,
|
||||
timeframe: body.timeframe,
|
||||
signalPrice: currentPrice,
|
||||
atr: body.atr,
|
||||
adx: body.adx,
|
||||
rsi: body.rsi,
|
||||
volumeRatio: body.volumeRatio,
|
||||
pricePosition: body.pricePosition,
|
||||
signalQualityScore: 0, // Not calculated yet
|
||||
minScoreRequired: config.minSignalQualityScore,
|
||||
blockReason: 'COOLDOWN_PERIOD',
|
||||
blockDetails: `Wait ${remainingMinutes} more min (cooldown: ${config.minTimeBetweenTrades} min)`,
|
||||
})
|
||||
if (currentPrice > 0) {
|
||||
await createBlockedSignal({
|
||||
symbol: body.symbol,
|
||||
direction: body.direction,
|
||||
timeframe: body.timeframe,
|
||||
signalPrice: currentPrice,
|
||||
atr: body.atr,
|
||||
adx: body.adx,
|
||||
rsi: body.rsi,
|
||||
volumeRatio: body.volumeRatio,
|
||||
pricePosition: body.pricePosition,
|
||||
signalQualityScore: 0, // Not calculated yet
|
||||
minScoreRequired: config.minSignalQualityScore,
|
||||
blockReason: 'COOLDOWN_PERIOD',
|
||||
blockDetails: `Wait ${remainingMinutes} more min (cooldown: ${config.minTimeBetweenTrades} min)`,
|
||||
indicatorVersion: body.indicatorVersion || 'v5',
|
||||
})
|
||||
} else {
|
||||
console.warn('⚠️ Skipping blocked signal save: price unavailable (cooldown)')
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
@@ -364,7 +377,7 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
|
||||
// Get current price from Pyth for flip-flop price context check
|
||||
const priceMonitor = getPythPriceMonitor()
|
||||
const latestPrice = priceMonitor.getCachedPrice(body.symbol)
|
||||
const currentPrice = latestPrice?.price || body.currentPrice
|
||||
const currentPrice = latestPrice?.price || fallbackPrice || 0
|
||||
|
||||
// Use direction-specific quality threshold (Nov 23, 2025)
|
||||
const minQualityScore = getMinQualityScoreForDirection(body.direction, config)
|
||||
@@ -392,26 +405,31 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
|
||||
})
|
||||
|
||||
// Get current price for the blocked signal record
|
||||
const currentPrice = await getCurrentPrice(body.symbol, body.currentPrice)
|
||||
const currentPrice = await getCurrentPrice(body.symbol, fallbackPrice)
|
||||
|
||||
// Save blocked signal to database for future analysis
|
||||
await createBlockedSignal({
|
||||
symbol: body.symbol,
|
||||
direction: body.direction,
|
||||
timeframe: body.timeframe,
|
||||
signalPrice: currentPrice,
|
||||
atr: body.atr,
|
||||
adx: body.adx,
|
||||
rsi: body.rsi,
|
||||
volumeRatio: body.volumeRatio,
|
||||
pricePosition: body.pricePosition,
|
||||
signalQualityScore: qualityScore.score,
|
||||
signalQualityVersion: 'v4', // Update this when scoring logic changes
|
||||
scoreBreakdown: { reasons: qualityScore.reasons },
|
||||
minScoreRequired: minQualityScore, // Use direction-specific threshold
|
||||
blockReason: 'QUALITY_SCORE_TOO_LOW',
|
||||
blockDetails: `Score: ${qualityScore.score}/${config.minSignalQualityScore} - ${qualityScore.reasons.join(', ')}`,
|
||||
})
|
||||
if (currentPrice > 0) {
|
||||
await createBlockedSignal({
|
||||
symbol: body.symbol,
|
||||
direction: body.direction,
|
||||
timeframe: body.timeframe,
|
||||
signalPrice: currentPrice,
|
||||
atr: body.atr,
|
||||
adx: body.adx,
|
||||
rsi: body.rsi,
|
||||
volumeRatio: body.volumeRatio,
|
||||
pricePosition: body.pricePosition,
|
||||
signalQualityScore: qualityScore.score,
|
||||
signalQualityVersion: 'v4', // Update this when scoring logic changes
|
||||
scoreBreakdown: { reasons: qualityScore.reasons },
|
||||
minScoreRequired: minQualityScore, // Use direction-specific threshold
|
||||
blockReason: 'QUALITY_SCORE_TOO_LOW',
|
||||
blockDetails: `Score: ${qualityScore.score}/${minQualityScore} - ${qualityScore.reasons.join(', ')}`,
|
||||
indicatorVersion: body.indicatorVersion || 'v5',
|
||||
})
|
||||
} else {
|
||||
console.warn('⚠️ Skipping blocked signal save: price unavailable (quality block)')
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
allowed: false,
|
||||
|
||||
Reference in New Issue
Block a user