Implement risk checks: cooldown, hourly limit, and daily drawdown
Implemented 3 critical risk checks in /api/trading/check-risk: 1. Daily Drawdown Check - Blocks trades if today's P&L < maxDailyDrawdown - Prevents catastrophic daily losses - Currently: -0 limit (configurable via MAX_DAILY_DRAWDOWN) 2. Hourly Trade Limit - Blocks trades if tradesInLastHour >= maxTradesPerHour - Prevents overtrading / algorithm malfunction - Currently: 20 trades/hour (configurable via MAX_TRADES_PER_HOUR) 3. Cooldown Period - Blocks trades if timeSinceLastTrade < minTimeBetweenTrades - Enforces breathing room between trades - Uses minutes (not seconds) thanks to previous commit - Currently: 0 min = disabled (configurable via MIN_TIME_BETWEEN_TRADES) Added database helper functions: - getLastTradeTime() - Returns timestamp of most recent trade - getTradesInLastHour() - Counts trades in last 60 minutes - getTodayPnL() - Sums realized P&L since midnight All checks include detailed logging with values and thresholds. Risk check called by n8n workflow before every trade execution.
This commit is contained in:
@@ -251,6 +251,78 @@ export async function getOpenTrades() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the most recent trade entry time (for cooldown checking)
|
||||
*/
|
||||
export async function getLastTradeTime(): Promise<Date | null> {
|
||||
const prisma = getPrismaClient()
|
||||
|
||||
try {
|
||||
const lastTrade = await prisma.trade.findFirst({
|
||||
orderBy: { entryTime: 'desc' },
|
||||
select: { entryTime: true },
|
||||
})
|
||||
|
||||
return lastTrade?.entryTime || null
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to get last trade time:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of trades in the last hour
|
||||
*/
|
||||
export async function getTradesInLastHour(): Promise<number> {
|
||||
const prisma = getPrismaClient()
|
||||
|
||||
try {
|
||||
const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000)
|
||||
|
||||
const count = await prisma.trade.count({
|
||||
where: {
|
||||
entryTime: {
|
||||
gte: oneHourAgo,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return count
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to get trades in last hour:', error)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total P&L for today
|
||||
*/
|
||||
export async function getTodayPnL(): Promise<number> {
|
||||
const prisma = getPrismaClient()
|
||||
|
||||
try {
|
||||
const startOfDay = new Date()
|
||||
startOfDay.setHours(0, 0, 0, 0)
|
||||
|
||||
const result = await prisma.trade.aggregate({
|
||||
where: {
|
||||
entryTime: {
|
||||
gte: startOfDay,
|
||||
},
|
||||
status: 'closed',
|
||||
},
|
||||
_sum: {
|
||||
realizedPnL: true,
|
||||
},
|
||||
})
|
||||
|
||||
return result._sum.realizedPnL || 0
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to get today PnL:', error)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add price update for a trade (for tracking max gain/drawdown)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user