Files
trading_bot_v3/lib/drift-order-cleanup-service.js
mindesbunister 167d7ff5bc feat: implement comprehensive AI decision display and reasoning panel
Major Features Added:
- Complete AI decision tracking system with detailed reasoning display
- Prominent gradient-styled AI reasoning panel on automation-v2 page
- Test AI decision generator with realistic trading scenarios
- Enhanced decision transparency showing entry/exit logic and leverage calculations

- Fixed orphaned order cleanup to preserve reduce-only SL/TP orders
- Integrated AI leverage calculator with 100x capability (up from 10x limit)
- Added lastDecision property to automation status for UI display
- Enhanced position monitoring with better cleanup triggers

- Beautiful gradient-styled AI Trading Analysis panel
- Color-coded confidence levels and recommendation displays
- Detailed breakdown of entry strategy, stop loss logic, and take profit targets
- Real-time display of AI leverage reasoning with safety buffer explanations
- Test AI button for demonstration of decision-making process

- SL/TP orders now execute properly (fixed cleanup interference)
- AI calculates sophisticated leverage (8.8x-42.2x vs previous 1x hardcoded)
- Complete decision audit trail with execution details
- Risk management transparency with liquidation safety calculations

- Why This Decision? - Prominent reasoning section
- Entry & Exit Strategy - Price levels with color coding
- AI Leverage Decision - Detailed calculation explanations
- Execution status with success/failure indicators
- Transaction IDs and comprehensive trade details

All systems now provide full transparency of AI decision-making process.
2025-07-26 22:41:55 +02:00

205 lines
5.9 KiB
JavaScript

/**
* Drift Order Cleanup Service
* Automatically detects and cancels orphaned orders when positions are closed
*/
class DriftOrderCleanupService {
constructor() {
this.isRunning = false
this.monitoringInterval = null
this.lastCleanupTime = 0
this.cleanupCooldown = 30000 // 30 seconds between cleanups
}
/**
* Start monitoring for orphaned orders
*/
start(intervalMs = 60000) { // Check every 60 seconds by default
if (this.isRunning) {
console.log('⚠️ Drift order cleanup service already running')
return
}
this.isRunning = true
console.log(`🧹 Starting Drift order cleanup service (checking every ${intervalMs/1000}s)`)
this.monitoringInterval = setInterval(async () => {
try {
await this.checkAndCleanupOrders()
} catch (error) {
console.error('❌ Error in order cleanup monitoring:', error)
}
}, intervalMs)
// Also run an initial check
setTimeout(() => this.checkAndCleanupOrders().catch(console.error), 5000)
}
/**
* Stop monitoring
*/
stop() {
if (!this.isRunning) {
console.log('⚠️ Drift order cleanup service not running')
return
}
this.isRunning = false
if (this.monitoringInterval) {
clearInterval(this.monitoringInterval)
this.monitoringInterval = null
}
console.log('🛑 Drift order cleanup service stopped')
}
/**
* Check for orphaned orders and clean them up
*/
async checkAndCleanupOrders() {
if (!this.isRunning) return
// Prevent too frequent cleanups
const now = Date.now()
if (now - this.lastCleanupTime < this.cleanupCooldown) {
return
}
try {
console.log('🔍 Checking for orphaned orders...')
// Get current positions and orders
const [positionsResponse, ordersResponse] = await Promise.all([
fetch('http://localhost:9001/api/drift/positions'),
fetch('http://localhost:9001/api/drift/orders')
])
if (!positionsResponse.ok || !ordersResponse.ok) {
console.warn('⚠️ Failed to fetch positions or orders for cleanup check')
return
}
const positionsData = await positionsResponse.json()
const ordersData = await ordersResponse.json()
if (!positionsData.success || !ordersData.success) {
console.warn('⚠️ API responses indicate failure, skipping cleanup')
return
}
const positions = positionsData.positions || []
const orders = ordersData.orders || []
console.log(`📊 Current state: ${positions.length} positions, ${orders.length} orders`)
// Quick check: if no orphaned orders, skip cleanup
const positionMarkets = new Set(positions.map(pos => pos.marketIndex))
const orphanedOrders = orders.filter(order =>
// CRITICAL FIX: Only cancel non-reduce-only orders when no position exists
// Stop Loss and Take Profit orders are reduce-only and should exist with positions
!positionMarkets.has(order.marketIndex) && !order.reduceOnly
)
if (orphanedOrders.length === 0) {
console.log('✅ No orphaned orders detected')
return
}
console.log(`🎯 Found ${orphanedOrders.length} potentially orphaned orders`)
// Trigger cleanup
const cleanupResponse = await fetch('http://localhost:9001/api/drift/cleanup-orders', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
})
if (!cleanupResponse.ok) {
throw new Error(`Cleanup API failed: ${cleanupResponse.status}`)
}
const cleanupResult = await cleanupResponse.json()
if (cleanupResult.success) {
const summary = cleanupResult.summary
console.log('🧹 Order cleanup completed:')
console.log(` 📊 Orphaned orders: ${summary.orphanedOrders}`)
console.log(` ⚠️ Conflicting orders: ${summary.conflictingOrders}`)
console.log(` ✅ Successfully canceled: ${summary.totalCanceled}`)
console.log(` ❌ Failed to cancel: ${summary.totalFailed}`)
this.lastCleanupTime = now
// Log each canceled order
cleanupResult.canceledOrders.forEach(order => {
if (order.success) {
console.log(` ✅ Canceled ${order.symbol} order ${order.orderId} (${order.reason})`)
} else {
console.log(` ❌ Failed to cancel order ${order.orderId}: ${order.error}`)
}
})
} else {
console.error('❌ Order cleanup failed:', cleanupResult.error)
}
} catch (error) {
console.error('❌ Error during order cleanup check:', error)
}
}
/**
* Manual cleanup trigger
*/
async forceCleanup() {
console.log('🧹 Manual order cleanup triggered...')
try {
const response = await fetch('http://localhost:9001/api/drift/cleanup-orders', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
})
if (!response.ok) {
throw new Error(`Cleanup API failed: ${response.status}`)
}
const result = await response.json()
if (result.success) {
console.log('✅ Manual cleanup completed:', result.summary)
return result
} else {
throw new Error(result.error)
}
} catch (error) {
console.error('❌ Manual cleanup failed:', error)
throw error
}
}
/**
* Get service status
*/
getStatus() {
return {
isRunning: this.isRunning,
lastCleanupTime: this.lastCleanupTime,
lastCleanupAgo: this.lastCleanupTime ? Date.now() - this.lastCleanupTime : null,
cooldownRemaining: Math.max(0, this.cleanupCooldown - (Date.now() - this.lastCleanupTime))
}
}
}
// Export singleton instance
export const driftOrderCleanupService = new DriftOrderCleanupService()
// For CommonJS compatibility
if (typeof module !== 'undefined' && module.exports) {
module.exports = { driftOrderCleanupService, DriftOrderCleanupService }
}