feat: implement blocked signals tracking system
- Add BlockedSignal table with 25 fields for comprehensive signal analysis - Track all blocked signals with metrics (ATR, ADX, RSI, volume, price position) - Store quality scores, block reasons, and detailed breakdowns - Include future fields for automated price analysis (priceAfter1/5/15/30Min) - Restore signalQualityVersion field to Trade table Database changes: - New table: BlockedSignal with indexes on symbol, createdAt, score, blockReason - Fixed schema drift from manual changes API changes: - Modified check-risk endpoint to save blocked signals automatically - Fixed hasContextMetrics variable scope (moved to line 209) - Save blocks for: quality score too low, cooldown period, hourly limit - Use config.minSignalQualityScore instead of hardcoded 60 Database helpers: - Added createBlockedSignal() function with try/catch safety - Added getRecentBlockedSignals(limit) for queries - Added getBlockedSignalsForAnalysis(olderThanMinutes) for automation Documentation: - Created BLOCKED_SIGNALS_TRACKING.md with SQL queries and analysis workflow - Created SIGNAL_QUALITY_OPTIMIZATION_ROADMAP.md with 5-phase plan - Documented data-first approach: collect 10-20 signals before optimization Rationale: Only 2 historical trades scored 60-64 (insufficient sample size for threshold decision). Building data collection infrastructure before making premature optimizations. Phase 1 (current): Collect blocked signals for 1-2 weeks Phase 2 (next): Analyze patterns and make data-driven threshold decision Phase 3-5 (future): Automation and ML optimization
This commit is contained in:
@@ -471,6 +471,88 @@ export async function getTradeStats(days: number = 30) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save blocked signal for analysis
|
||||
*/
|
||||
export interface CreateBlockedSignalParams {
|
||||
symbol: string
|
||||
direction: 'long' | 'short'
|
||||
timeframe?: string
|
||||
signalPrice: number
|
||||
atr?: number
|
||||
adx?: number
|
||||
rsi?: number
|
||||
volumeRatio?: number
|
||||
pricePosition?: number
|
||||
signalQualityScore: number
|
||||
signalQualityVersion?: string
|
||||
scoreBreakdown?: any
|
||||
minScoreRequired: number
|
||||
blockReason: string
|
||||
blockDetails?: string
|
||||
}
|
||||
|
||||
export async function createBlockedSignal(params: CreateBlockedSignalParams) {
|
||||
const client = getPrismaClient()
|
||||
|
||||
try {
|
||||
const blockedSignal = await client.blockedSignal.create({
|
||||
data: {
|
||||
symbol: params.symbol,
|
||||
direction: params.direction,
|
||||
timeframe: params.timeframe,
|
||||
signalPrice: params.signalPrice,
|
||||
atr: params.atr,
|
||||
adx: params.adx,
|
||||
rsi: params.rsi,
|
||||
volumeRatio: params.volumeRatio,
|
||||
pricePosition: params.pricePosition,
|
||||
signalQualityScore: params.signalQualityScore,
|
||||
signalQualityVersion: params.signalQualityVersion,
|
||||
scoreBreakdown: params.scoreBreakdown,
|
||||
minScoreRequired: params.minScoreRequired,
|
||||
blockReason: params.blockReason,
|
||||
blockDetails: params.blockDetails,
|
||||
},
|
||||
})
|
||||
|
||||
console.log(`📝 Blocked signal saved: ${params.symbol} ${params.direction} (score: ${params.signalQualityScore}/${params.minScoreRequired})`)
|
||||
return blockedSignal
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to save blocked signal:', error)
|
||||
// Don't throw - blocking shouldn't fail the check-risk process
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get recent blocked signals for analysis
|
||||
*/
|
||||
export async function getRecentBlockedSignals(limit: number = 20) {
|
||||
const client = getPrismaClient()
|
||||
return client.blockedSignal.findMany({
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: limit,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get blocked signals that need price analysis
|
||||
*/
|
||||
export async function getBlockedSignalsForAnalysis(olderThanMinutes: number = 30) {
|
||||
const client = getPrismaClient()
|
||||
const cutoffTime = new Date(Date.now() - olderThanMinutes * 60 * 1000)
|
||||
|
||||
return client.blockedSignal.findMany({
|
||||
where: {
|
||||
analysisComplete: false,
|
||||
createdAt: { lt: cutoffTime },
|
||||
},
|
||||
orderBy: { createdAt: 'asc' },
|
||||
take: 50,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect Prisma client (for graceful shutdown)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user