fix: Resolve win rate and P&L discrepancies between Status and AI Learning sections

- Fixed analysis-details API to use stored profit field as fallback when exit prices missing
- Updated UI to use Status API data instead of calculating from limited recent trades
- Modified AI Learning Status to use real database trade data instead of demo numbers
- Enhanced price monitor with automatic trade closing logic for TP/SL hits
- Modified automation service to create trades with OPEN status for proper monitoring
- Added test scripts for creating OPEN trades and validating monitoring system

Key changes:
- Status section now shows accurate 50% win rate from complete database
- AI Learning Status shows consistent metrics based on real trading performance
- Both sections display same correct P&L (8.62) from actual trade results
- Real-time price monitor properly detects and tracks OPEN status trades
- Fixed trade lifecycle: OPEN → monitoring → COMPLETED when TP/SL hit

All trading performance metrics now display consistent, accurate data from the same source.
This commit is contained in:
mindesbunister
2025-07-21 12:56:14 +02:00
parent aae715dd07
commit d7a1b96a80
9 changed files with 1454 additions and 75 deletions

View File

@@ -142,6 +142,14 @@ class PriceMonitor extends EventEmitter {
// Update trade in database with current PnL
await this.updateTradeCurrentData(trade.id, currentPrice, monitoring.currentPnL!)
// Check if trade should be closed (TP/SL hit)
const shouldClose = await this.checkTradeClose(trade, currentPrice)
if (shouldClose) {
await this.closeTrade(trade.id, currentPrice, shouldClose.reason)
console.log(`🔒 Trade ${trade.id.slice(-8)} closed: ${shouldClose.reason} at $${currentPrice}`)
continue // Skip further processing for this trade
}
// Check if analysis is needed
const needsAnalysis = this.shouldTriggerAnalysis(monitoring)
if (needsAnalysis) {
@@ -384,6 +392,67 @@ class PriceMonitor extends EventEmitter {
}
return null
}
// Check if a trade should be closed based on TP/SL
private async checkTradeClose(trade: any, currentPrice: number): Promise<{ reason: string } | null> {
const entryPrice = trade.entryPrice || trade.price
// Check Take Profit
if (trade.takeProfit) {
const tpHit = (trade.side === 'BUY' && currentPrice >= trade.takeProfit) ||
(trade.side === 'SELL' && currentPrice <= trade.takeProfit)
if (tpHit) {
return { reason: 'TAKE_PROFIT' }
}
}
// Check Stop Loss
if (trade.stopLoss) {
const slHit = (trade.side === 'BUY' && currentPrice <= trade.stopLoss) ||
(trade.side === 'SELL' && currentPrice >= trade.stopLoss)
if (slHit) {
return { reason: 'STOP_LOSS' }
}
}
return null
}
// Close a trade by updating its status and exit data
private async closeTrade(tradeId: string, exitPrice: number, reason: string): Promise<void> {
try {
const trade = await prisma.trade.findUnique({ where: { id: tradeId } })
if (!trade) return
const entryPrice = trade.entryPrice || trade.price
const pnl = this.calculatePnL(trade.side, entryPrice, exitPrice, trade.amount)
const tradingAmount = trade.amount * entryPrice // Estimate trading amount
const pnlPercent = ((pnl / tradingAmount) * 100)
await prisma.trade.update({
where: { id: tradeId },
data: {
status: 'COMPLETED',
exitPrice: exitPrice,
closedAt: new Date(),
profit: pnl,
pnlPercent: pnlPercent,
outcome: pnl > 0 ? 'WIN' : pnl < 0 ? 'LOSS' : 'BREAK_EVEN'
}
})
} catch (error) {
console.error('Error closing trade:', error)
}
}
// Calculate P&L for a trade
private calculatePnL(side: string, entryPrice: number, exitPrice: number, amount: number): number {
if (side === 'BUY') {
return (exitPrice - entryPrice) * amount
} else {
return (entryPrice - exitPrice) * amount
}
}
}
export const priceMonitor = PriceMonitor.getInstance()