feat: Implement re-entry analytics system with fresh TradingView data

- Add market data cache service (5min expiry) for storing TradingView metrics
- Create /api/trading/market-data webhook endpoint for continuous data updates
- Add /api/analytics/reentry-check endpoint for validating manual trades
- Update execute endpoint to auto-cache metrics from incoming signals
- Enhance Telegram bot with pre-execution analytics validation
- Support --force flag to override analytics blocks
- Use fresh ADX/ATR/RSI data when available, fallback to historical
- Apply performance modifiers: -20 for losing streaks, +10 for winning
- Minimum re-entry score 55 (vs 60 for new signals)
- Fail-open design: proceeds if analytics unavailable
- Show data freshness and source in Telegram responses
- Add comprehensive setup guide in docs/guides/REENTRY_ANALYTICS_QUICKSTART.md

Phase 1 implementation for smart manual trade validation.
This commit is contained in:
mindesbunister
2025-11-07 20:40:07 +01:00
parent 6d5991172a
commit 9b767342dc
14 changed files with 1150 additions and 568 deletions

View File

@@ -15,7 +15,6 @@ import { scoreSignalQuality, SignalQualityResult } from '@/lib/trading/signal-qu
export interface RiskCheckRequest {
symbol: string
direction: 'long' | 'short'
timeframe?: string // e.g., '5', '15', '60', '1D'
// Optional context metrics from TradingView
atr?: number
adx?: number
@@ -58,7 +57,6 @@ function shouldAllowScaling(
pricePosition: newSignal.pricePosition,
direction: newSignal.direction,
minScore: config.minScaleQualityScore,
timeframe: newSignal.timeframe,
})
// 2. Check quality score (higher bar than initial entry)
@@ -148,9 +146,8 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
const config = getMergedConfig()
// Check for existing positions on the same symbol
const positionManager = await getInitializedPositionManager()
await positionManager.reconcileTrade(body.symbol)
const existingTrades = Array.from(positionManager.getActiveTrades().values())
const positionManager = await getInitializedPositionManager()
const existingTrades = Array.from(positionManager.getActiveTrades().values())
const existingPosition = existingTrades.find(trade => trade.symbol === body.symbol)
if (existingPosition) {
@@ -273,8 +270,7 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
volumeRatio: body.volumeRatio || 0,
pricePosition: body.pricePosition || 0,
direction: body.direction,
minScore: 60, // Hardcoded threshold
timeframe: body.timeframe,
minScore: 60 // Hardcoded threshold
})
if (!qualityScore.passed) {