Files
trading_bot_v3/test-drift-real-orders.js
mindesbunister 9c4bee0dd7 feat: Remove artificial percentage minimums - AI now has complete freedom
REMOVED ARTIFICIAL CONSTRAINTS:
- Eliminated 3% minimum stop loss requirement
- Eliminated 1% minimum take profit requirement
- AI can now choose ANY percentage based on market analysis

- Updated app/api/drift/trade/route.js to use exact AI percentages
- Removed Math.max() constraints that forced minimums
- AI now has 0.1%+ to 50%+ percentage freedom

- Modified AI_RISK_MANAGEMENT.md to reflect new freedom
- Removed all references to artificial 3%/1% minimums
- Added ultra-tight scalping examples (0.1%-1%)
- Updated volatility guidelines for all trading styles

 PROVEN WITH REAL ORDERS:
- Transaction: 35QmCqWFzwJ1X2nm5M8rgExKEMbWTRqxCa1GryEsR595zYwBLqCzDowUYm3J2u13WMvYR2PRoS3eAMSzXfGvEVbe
- Confirmed: 0.5% SL / 0.25% TP working on Drift Protocol
- Verified: Orders visible in Drift UI with correct trigger prices

- Optimal risk management based on actual market conditions
- Support for all trading styles: scalping to position trading
- No more forced suboptimal stops due to artificial limits
- Professional-grade percentage precision

The AI can now freely optimize percentages for maximum trading effectiveness!
2025-07-24 09:58:30 +02:00

333 lines
11 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* REAL DRIFT PROTOCOL MINIMUM PERCENTAGE TEST
*
* This test places ACTUAL small orders on Drift Protocol to validate
* that the reduced minimum percentages work in real trading conditions.
*
* SAFETY MEASURES:
* - Uses very small position sizes ($0.50 - $2.00)
* - Tests on SOL-PERP with high liquidity
* - Automatically cancels test orders after validation
* - Monitors for order rejection reasons
*/
const https = require('https');
const http = require('http');
// Test configuration
const API_BASE = 'http://localhost:3000/api';
const TEST_SYMBOL = 'SOLUSD';
const TEST_AMOUNT = 0.5; // $0.50 position size for safety
// Minimum percentages to test (progressively tighter)
const TEST_CASES = [
{ sl: 1.5, tp: 1.0, desc: 'Conservative scalping (1.5%/1.0%)' },
{ sl: 1.0, tp: 0.75, desc: 'Moderate scalping (1.0%/0.75%)' },
{ sl: 0.75, tp: 0.5, desc: 'Tight scalping (0.75%/0.5%)' },
{ sl: 0.5, tp: 0.25, desc: 'Ultra-tight scalping (0.5%/0.25%)' },
{ sl: 0.25, tp: 0.1, desc: 'Extreme scalping (0.25%/0.1%)' }
];
async function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function makeApiCall(endpoint, method = 'GET', body = null) {
return new Promise((resolve, reject) => {
const url = `http://localhost:3000/api${endpoint}`;
const parsedUrl = new URL(url);
const options = {
hostname: parsedUrl.hostname,
port: parsedUrl.port,
path: parsedUrl.pathname + parsedUrl.search,
method: method,
headers: {
'Content-Type': 'application/json',
},
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const jsonData = JSON.parse(data);
resolve({ success: res.statusCode >= 200 && res.statusCode < 300, data: jsonData, status: res.statusCode });
} catch (error) {
resolve({ success: false, error: `Parse error: ${error.message}`, data: data });
}
});
});
req.on('error', (error) => {
resolve({ success: false, error: error.message });
});
if (body) {
req.write(JSON.stringify(body));
}
req.end();
});
}
async function getCurrentBalance() {
console.log('💰 Checking current Drift balance...');
const result = await makeApiCall('/drift/balance');
if (!result.success) {
throw new Error(`Failed to get balance: ${result.error}`);
}
console.log(` Balance: $${result.data.totalCollateral}`);
console.log(` Available: $${result.data.availableBalance}`);
return parseFloat(result.data.availableBalance);
}
async function getCurrentPositions() {
console.log('📋 Checking current positions...');
const result = await makeApiCall('/drift/positions');
if (!result.success) {
throw new Error(`Failed to get positions: ${result.error}`);
}
console.log(` Active positions: ${result.data.positions.length}`);
return result.data.positions;
}
async function testOrderPlacement(testCase, entryPrice) {
console.log(`\n🔬 Testing: ${testCase.desc}`);
console.log(` Entry: $${entryPrice.toFixed(4)}`);
console.log(` Stop Loss: ${testCase.sl}% (${(entryPrice * (1 - testCase.sl/100)).toFixed(4)})`);
console.log(` Take Profit: ${testCase.tp}% (${(entryPrice * (1 + testCase.tp/100)).toFixed(4)})`);
// Calculate position size based on test amount
const positionSize = TEST_AMOUNT / entryPrice;
const tradeRequest = {
symbol: TEST_SYMBOL,
side: 'long',
amount: positionSize.toFixed(6),
stopLossPercent: testCase.sl,
takeProfitPercent: testCase.tp,
leverage: 1, // Conservative leverage for testing
orderType: 'market'
};
console.log(` Position size: ${positionSize.toFixed(6)} SOL ($${TEST_AMOUNT})`);
try {
// Place the order
console.log(' 📤 Placing order...');
const result = await makeApiCall('/drift/trade', 'POST', tradeRequest);
if (result.success) {
console.log(` ✅ SUCCESS: Order placed with ${testCase.sl}%/${testCase.tp}% levels`);
console.log(` 📋 Transaction: ${result.data.signature || 'N/A'}`);
// Wait a moment for order to process
await delay(2000);
// Check if position was created
const positions = await getCurrentPositions();
const newPosition = positions.find(p => p.symbol === TEST_SYMBOL);
if (newPosition) {
console.log(` 💼 Position created: ${newPosition.size} SOL`);
console.log(` 🎯 Stop Loss: $${newPosition.stopLoss || 'N/A'}`);
console.log(` 📈 Take Profit: $${newPosition.takeProfit || 'N/A'}`);
// IMPORTANT: Close the test position immediately
console.log(' 🧹 Closing test position...');
const closeResult = await makeApiCall('/drift/trade', 'POST', {
symbol: TEST_SYMBOL,
side: 'sell',
amount: Math.abs(parseFloat(newPosition.size)),
orderType: 'market'
});
if (closeResult.success) {
console.log(' ✅ Test position closed successfully');
} else {
console.log(` ⚠️ Warning: Could not close position: ${closeResult.error}`);
}
}
return { success: true, details: result.data };
} else {
console.log(` ❌ FAILED: ${result.data.error || result.error}`);
// Analyze the failure reason
const errorMsg = result.data.error || result.error || '';
if (errorMsg.includes('trigger') || errorMsg.includes('price')) {
console.log(` 🔍 Analysis: Price level too close to market`);
return { success: false, reason: 'price_too_close' };
} else if (errorMsg.includes('margin') || errorMsg.includes('collateral')) {
console.log(` 🔍 Analysis: Insufficient margin/collateral`);
return { success: false, reason: 'insufficient_margin' };
} else {
console.log(` 🔍 Analysis: Other error - ${errorMsg}`);
return { success: false, reason: 'other', error: errorMsg };
}
}
} catch (error) {
console.log(` ❌ EXCEPTION: ${error.message}`);
return { success: false, reason: 'exception', error: error.message };
}
}
async function getCurrentPrice() {
console.log('📊 Getting current SOL price...');
return new Promise((resolve, reject) => {
const options = {
hostname: 'api.binance.com',
port: 443,
path: '/api/v3/ticker/price?symbol=SOLUSDT',
method: 'GET',
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const jsonData = JSON.parse(data);
const price = parseFloat(jsonData.price);
console.log(` SOL Price: $${price.toFixed(4)}`);
resolve(price);
} catch (error) {
console.log(` ⚠️ Could not parse price data: ${error.message}`);
console.log(' Using fallback price: $200.00');
resolve(200.00);
}
});
});
req.on('error', (error) => {
console.log(` ⚠️ Could not get price from Binance: ${error.message}`);
console.log(' Using fallback price: $200.00');
resolve(200.00);
});
req.end();
});
}
async function runRealDriftTest() {
console.log('🚀 REAL DRIFT PROTOCOL MINIMUM PERCENTAGE TEST');
console.log('=' .repeat(60));
console.log('⚠️ WARNING: This test places REAL orders with REAL money');
console.log('💡 Position size limited to $0.50 for safety');
console.log('🧹 Test positions are automatically closed');
console.log('=' .repeat(60));
try {
// Pre-flight checks
const balance = await getCurrentBalance();
if (balance < 10) {
throw new Error(`Insufficient balance: $${balance}. Minimum $10 required for safe testing.`);
}
const initialPositions = await getCurrentPositions();
const entryPrice = await getCurrentPrice();
// Run tests
console.log('\n📋 Test Results Summary:');
console.log('-' .repeat(60));
const results = [];
for (const testCase of TEST_CASES) {
const result = await testOrderPlacement(testCase, entryPrice);
results.push({ ...testCase, ...result });
// Wait between tests to avoid rate limits
await delay(3000);
}
// Analysis
console.log('\n🎯 FINAL ANALYSIS:');
console.log('=' .repeat(60));
const successful = results.filter(r => r.success);
const failed = results.filter(r => !r.success);
console.log(`✅ Successful: ${successful.length}/${results.length} test cases`);
console.log(`❌ Failed: ${failed.length}/${results.length} test cases`);
if (successful.length > 0) {
const tightest = successful[successful.length - 1];
console.log(`\n🏆 TIGHTEST WORKING PERCENTAGES:`);
console.log(` Stop Loss: ${tightest.sl}%`);
console.log(` Take Profit: ${tightest.tp}%`);
console.log(` Description: ${tightest.desc}`);
console.log(`\n💡 RECOMMENDED NEW MINIMUMS:`);
console.log(` stopLossPercentCalc = Math.max(stopLossPercent / 100, ${(tightest.sl / 100).toFixed(4)}) // ${tightest.sl}%`);
console.log(` takeProfitPercentCalc = Math.max(takeProfitPercent / 100, ${(tightest.tp / 100).toFixed(4)}) // ${tightest.tp}%`);
}
if (failed.length > 0) {
console.log(`\n⚠️ FAILURES ANALYSIS:`);
failed.forEach(f => {
console.log(` ${f.desc}: ${f.reason}`);
});
}
// Final position check
console.log('\n🧹 POST-TEST CLEANUP CHECK:');
const finalPositions = await getCurrentPositions();
const newPositions = finalPositions.length - initialPositions.length;
if (newPositions > 0) {
console.log(`⚠️ Warning: ${newPositions} test positions remain open`);
console.log(' Manual cleanup may be required');
} else {
console.log('✅ All test positions cleaned up successfully');
}
const finalBalance = await getCurrentBalance();
const balanceChange = finalBalance - balance;
console.log(`💰 Balance change: ${balanceChange >= 0 ? '+' : ''}$${balanceChange.toFixed(2)}`);
} catch (error) {
console.error('❌ Test failed:', error.message);
console.log('\n This could be due to:');
console.log(' - Network connectivity issues');
console.log(' - Drift Protocol API changes');
console.log(' - Insufficient balance or margin');
console.log(' - Market conditions (low liquidity)');
}
}
// Safety confirmation
console.log('⚠️ SAFETY CONFIRMATION REQUIRED ⚠️');
console.log('This test will place REAL orders on Drift Protocol');
console.log('Position size is limited to $0.50 per test');
console.log('Orders will be automatically closed');
console.log('');
console.log('To proceed, run: node test-drift-real-orders.js --confirm');
if (process.argv.includes('--confirm')) {
runRealDriftTest();
} else {
console.log('Test not run - confirmation required');
process.exit(0);
}