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.
205 lines
5.9 KiB
JavaScript
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 }
|
|
}
|