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.
164 lines
5.9 KiB
JavaScript
164 lines
5.9 KiB
JavaScript
#!/usr/bin/env node
|
||
|
||
/**
|
||
* Test Stop Loss / Take Profit Preservation Fix
|
||
* Verifies that SL/TP orders are not being incorrectly canceled as orphaned orders
|
||
*/
|
||
|
||
console.log('🧪 Testing Stop Loss / Take Profit Preservation Fix...');
|
||
|
||
async function testSLTPPreservation() {
|
||
try {
|
||
console.log('\n1️⃣ Testing Cleanup Logic...');
|
||
|
||
// Simulate position data
|
||
const mockPositions = [
|
||
{
|
||
marketIndex: 0, // SOL-PERP
|
||
symbol: 'SOL-PERP',
|
||
side: 'long',
|
||
size: 1.5,
|
||
entryPrice: 165.50
|
||
}
|
||
];
|
||
|
||
// Simulate orders including SL/TP
|
||
const mockOrders = [
|
||
{
|
||
orderId: 1,
|
||
marketIndex: 0, // Same market as position
|
||
direction: 1, // SHORT (opposite to position - correct for SL)
|
||
reduceOnly: true, // This is a Stop Loss order
|
||
baseAssetAmount: { isZero: () => false },
|
||
status: { open: true }
|
||
},
|
||
{
|
||
orderId: 2,
|
||
marketIndex: 0, // Same market as position
|
||
direction: 1, // SHORT (opposite to position - correct for TP)
|
||
reduceOnly: true, // This is a Take Profit order
|
||
baseAssetAmount: { isZero: () => false },
|
||
status: { open: true }
|
||
},
|
||
{
|
||
orderId: 3,
|
||
marketIndex: 1, // Different market - truly orphaned
|
||
direction: 0, // LONG
|
||
reduceOnly: false, // Regular order
|
||
baseAssetAmount: { isZero: () => false },
|
||
status: { open: true }
|
||
}
|
||
];
|
||
|
||
// Test the fixed logic
|
||
const positionMarkets = new Set(mockPositions.map(pos => pos.marketIndex));
|
||
console.log('📊 Position markets:', Array.from(positionMarkets));
|
||
|
||
// OLD BROKEN LOGIC (what was causing the bug):
|
||
const oldOrphanedOrders = mockOrders.filter(order =>
|
||
!positionMarkets.has(order.marketIndex) ||
|
||
(order.reduceOnly && !positionMarkets.has(order.marketIndex))
|
||
);
|
||
|
||
// NEW FIXED LOGIC:
|
||
const newOrphanedOrders = mockOrders.filter(order =>
|
||
!positionMarkets.has(order.marketIndex) && !order.reduceOnly
|
||
);
|
||
|
||
console.log(`❌ OLD LOGIC would cancel: ${oldOrphanedOrders.length} orders`);
|
||
oldOrphanedOrders.forEach(order => {
|
||
const type = order.reduceOnly ? 'SL/TP' : 'Regular';
|
||
console.log(` - Order ${order.orderId} (${type}) on market ${order.marketIndex}`);
|
||
});
|
||
|
||
console.log(`✅ NEW LOGIC will cancel: ${newOrphanedOrders.length} orders`);
|
||
newOrphanedOrders.forEach(order => {
|
||
const type = order.reduceOnly ? 'SL/TP' : 'Regular';
|
||
console.log(` - Order ${order.orderId} (${type}) on market ${order.marketIndex}`);
|
||
});
|
||
|
||
// Verify the fix
|
||
const slTpOrdersPreserved = mockOrders
|
||
.filter(order => order.reduceOnly && positionMarkets.has(order.marketIndex))
|
||
.filter(order => !newOrphanedOrders.includes(order));
|
||
|
||
console.log(`🛡️ SL/TP orders preserved: ${slTpOrdersPreserved.length}`);
|
||
slTpOrdersPreserved.forEach(order => {
|
||
console.log(` ✅ Order ${order.orderId} (SL/TP) preserved for market ${order.marketIndex}`);
|
||
});
|
||
|
||
console.log('\n2️⃣ Testing API Endpoints...');
|
||
|
||
// Test cleanup API with mock data
|
||
console.log('📡 Testing cleanup-orders API...');
|
||
|
||
const baseUrl = 'http://localhost:9001';
|
||
|
||
// Test positions endpoint
|
||
try {
|
||
const positionsResponse = await fetch(`${baseUrl}/api/drift/positions`);
|
||
const positionsData = await positionsResponse.json();
|
||
console.log(`✅ Positions API: ${positionsData.success ? 'Working' : 'Failed'}`);
|
||
|
||
if (positionsData.success) {
|
||
console.log(` 📊 Found ${positionsData.positions?.length || 0} positions`);
|
||
}
|
||
} catch (error) {
|
||
console.log(`❌ Positions API error: ${error.message}`);
|
||
}
|
||
|
||
// Test orders endpoint
|
||
try {
|
||
const ordersResponse = await fetch(`${baseUrl}/api/drift/orders`);
|
||
const ordersData = await ordersResponse.json();
|
||
console.log(`✅ Orders API: ${ordersData.success ? 'Working' : 'Failed'}`);
|
||
|
||
if (ordersData.success) {
|
||
console.log(` 📋 Found ${ordersData.orders?.length || 0} orders`);
|
||
|
||
// Analyze order types
|
||
const orders = ordersData.orders || [];
|
||
const reduceOnlyOrders = orders.filter(order => order.reduceOnly);
|
||
const regularOrders = orders.filter(order => !order.reduceOnly);
|
||
|
||
console.log(` 🛡️ Reduce-only orders (SL/TP): ${reduceOnlyOrders.length}`);
|
||
console.log(` 📈 Regular orders: ${regularOrders.length}`);
|
||
}
|
||
} catch (error) {
|
||
console.log(`❌ Orders API error: ${error.message}`);
|
||
}
|
||
|
||
console.log('\n3️⃣ Testing Position Monitor...');
|
||
|
||
try {
|
||
const monitorResponse = await fetch(`${baseUrl}/api/automation/position-monitor`);
|
||
const monitorData = await monitorResponse.json();
|
||
|
||
if (monitorData.success) {
|
||
const monitor = monitorData.monitor;
|
||
console.log(`✅ Position Monitor: Working`);
|
||
console.log(` 📊 Has Position: ${monitor.hasPosition}`);
|
||
console.log(` 🧹 Cleanup Triggered: ${monitor.orphanedOrderCleanup?.triggered || false}`);
|
||
console.log(` 📝 Message: ${monitor.orphanedOrderCleanup?.message || 'N/A'}`);
|
||
} else {
|
||
console.log(`❌ Position Monitor failed: ${monitorData.error}`);
|
||
}
|
||
} catch (error) {
|
||
console.log(`❌ Position Monitor error: ${error.message}`);
|
||
}
|
||
|
||
console.log('\n✅ Testing Complete!');
|
||
console.log('\n📋 Summary of Fixes:');
|
||
console.log(' 🛡️ Stop Loss and Take Profit orders are now preserved');
|
||
console.log(' 🧹 Only truly orphaned orders (non-reduce-only) will be cleaned up');
|
||
console.log(' 📊 Position monitor is more conservative about cleanup');
|
||
console.log(' ⚠️ Background cleanup services should be stopped to prevent interference');
|
||
|
||
} catch (error) {
|
||
console.error('❌ Test failed:', error);
|
||
}
|
||
}
|
||
|
||
// Run the test
|
||
testSLTPPreservation();
|