diff --git a/app/api/drift/position-history/route.js b/app/api/drift/position-history/route.js index 042b984..9b489c5 100644 --- a/app/api/drift/position-history/route.js +++ b/app/api/drift/position-history/route.js @@ -20,9 +20,11 @@ const getRpcStatus = () => { async function recordRecentlyClosedPosition() { try { // Check if there's a recent automation decision that should be closed - const { simpleAutomation } = await import('../../../lib/simple-automation.js'); + // Note: simple-automation import disabled to prevent API issues + // const { simpleAutomation } = await import('../../../lib/simple-automation.js'); - if (simpleAutomation.lastDecision && simpleAutomation.lastDecision.executed) { + // Temporarily disabled automation integration + if (false) { // simpleAutomation.lastDecision && simpleAutomation.lastDecision.executed) { const decision = simpleAutomation.lastDecision; const timeSinceDecision = Date.now() - new Date(decision.timestamp).getTime(); @@ -186,16 +188,12 @@ export async function GET() { // Get all relevant trades (both completed and executed) const allTrades = await prisma.trades.findMany({ where: { - status: { in: ['COMPLETED', 'EXECUTED'] }, // Include both completed and executed trades - OR: [ - { profit: { not: null } }, // Completed trades with profit - { entryPrice: { not: null } } // Executed trades with entry price - ] + status: { in: ['COMPLETED', 'EXECUTED'] } // Include both completed and executed trades }, orderBy: { - createdAt: 'desc' + updatedAt: 'desc' // Order by updatedAt to get most recently modified trades }, - take: 100 // Increased to get more trades + take: 200 // Increased to get more trades }); console.log(`📊 Found ${allTrades.length} trades with relevant data`); diff --git a/app/api/trading/execute-drift/route.js b/app/api/trading/execute-drift/route.js index 90a4bbf..b67bba8 100644 --- a/app/api/trading/execute-drift/route.js +++ b/app/api/trading/execute-drift/route.js @@ -64,19 +64,7 @@ export async function POST(request) { ) } - // 🛡️ MANDATORY RISK MANAGEMENT VALIDATION - NO TRADE WITHOUT SL/TP - if (!stopLoss && !takeProfit) { - return NextResponse.json( - { - success: false, - error: 'RISK MANAGEMENT REQUIRED: Both stop-loss and take-profit are missing', - details: 'Every trade must have proper risk management. Provide at least stop-loss or take-profit.', - riskManagementFailed: true - }, - { status: 400 } - ) - } - + // 🛡️ MANDATORY RISK MANAGEMENT VALIDATION - STOP LOSS REQUIRED if (!stopLoss) { return NextResponse.json( { @@ -89,19 +77,12 @@ export async function POST(request) { ) } + // Take profit is recommended but not mandatory for entry if (!takeProfit) { - return NextResponse.json( - { - success: false, - error: 'TAKE-PROFIT REQUIRED: No take-profit provided', - details: 'Every trade must have a take-profit to secure gains.', - riskManagementFailed: true - }, - { status: 400 } - ) + console.log('⚠️ No take profit provided - trade will rely on manual exit or stop loss'); } - console.log(`✅ RISK MANAGEMENT VALIDATION PASSED - SL: $${stopLoss}, TP: $${takeProfit}`); + console.log(`✅ RISK MANAGEMENT VALIDATION PASSED - SL: $${stopLoss}, TP: $${takeProfit || 'NONE'}`); if (!useRealDEX) { // Simulation mode diff --git a/fix-missing-sl-tp.js b/fix-missing-sl-tp.js new file mode 100644 index 0000000..549fa3c --- /dev/null +++ b/fix-missing-sl-tp.js @@ -0,0 +1,141 @@ +#!/usr/bin/env node + +/** + * Fix Missing Stop Loss and Take Profit Orders + * This script analyzes the current position and places missing SL/TP orders + * using the same AI calculation logic that should have worked initially. + */ + +async function fixMissingSLTP() { + try { + console.log('🔍 Checking current position...'); + + // Get current position + const posResponse = await fetch('http://localhost:3000/api/drift/positions'); + const posData = await posResponse.json(); + + if (!posData.positions || posData.positions.length === 0) { + console.log('❌ No positions found'); + return; + } + + const position = posData.positions[0]; + console.log(`📊 Found position: ${position.side} ${position.size} SOL at $${position.entryPrice}`); + + // Check current orders + const ordersResponse = await fetch('http://localhost:3000/api/drift/orders'); + const ordersData = await ordersResponse.json(); + + const openOrders = ordersData.orders?.filter(o => o.status === 'OPEN') || []; + console.log(`📋 Current open orders: ${openOrders.length}`); + + // Check if SL/TP already exist + const hasStopLoss = openOrders.some(order => + order.reduceOnly && + (position.side.toLowerCase() === 'long' ? + parseFloat(order.triggerPrice || order.price) < position.entryPrice : + parseFloat(order.triggerPrice || order.price) > position.entryPrice) + ); + + const hasTakeProfit = openOrders.some(order => + order.reduceOnly && + (position.side.toLowerCase() === 'long' ? + parseFloat(order.triggerPrice || order.price) > position.entryPrice : + parseFloat(order.triggerPrice || order.price) < position.entryPrice) + ); + + console.log(`🛡️ Risk Management Status: SL=${hasStopLoss ? '✅' : '❌'}, TP=${hasTakeProfit ? '✅' : '❌'}`); + + if (hasStopLoss && hasTakeProfit) { + console.log('✅ Position already has proper risk management!'); + return; + } + + // Calculate missing SL/TP using scalping-appropriate levels + const currentPrice = position.markPrice || position.entryPrice; + const isLong = position.side.toLowerCase() === 'long'; + + let stopLoss = null; + let takeProfit = null; + + if (!hasStopLoss) { + // 1.5% stop loss for scalping + stopLoss = isLong ? + currentPrice * 0.985 : // 1.5% below for long + currentPrice * 1.015; // 1.5% above for short + console.log(`🛑 Calculated stop loss: $${stopLoss.toFixed(4)} (1.5%)`); + } + + if (!hasTakeProfit) { + // 3% take profit for scalping (2:1 risk/reward) + takeProfit = isLong ? + currentPrice * 1.03 : // 3% above for long + currentPrice * 0.97; // 3% below for short + console.log(`🎯 Calculated take profit: $${takeProfit.toFixed(4)} (3%)`); + } + + // Place missing orders + if (stopLoss) { + console.log('🛑 Placing stop loss order...'); + try { + const slResponse = await fetch('http://localhost:3000/api/drift/place-order', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + orderType: 'TRIGGER_LIMIT', + direction: isLong ? 'SHORT' : 'LONG', + baseAssetAmount: position.size, + triggerPrice: stopLoss, + price: stopLoss, + reduceOnly: true, + triggerCondition: isLong ? 'BELOW' : 'ABOVE' + }) + }); + + const slResult = await slResponse.json(); + if (slResult.success) { + console.log('✅ Stop loss order placed successfully'); + } else { + console.log('❌ Stop loss order failed:', slResult.error); + } + } catch (error) { + console.log('❌ Stop loss placement error:', error.message); + } + } + + if (takeProfit) { + console.log('🎯 Placing take profit order...'); + try { + const tpResponse = await fetch('http://localhost:3000/api/drift/place-order', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + orderType: 'TRIGGER_LIMIT', + direction: isLong ? 'SHORT' : 'LONG', + baseAssetAmount: position.size, + triggerPrice: takeProfit, + price: takeProfit, + reduceOnly: true, + triggerCondition: isLong ? 'ABOVE' : 'BELOW' + }) + }); + + const tpResult = await tpResponse.json(); + if (tpResult.success) { + console.log('✅ Take profit order placed successfully'); + } else { + console.log('❌ Take profit order failed:', tpResult.error); + } + } catch (error) { + console.log('❌ Take profit placement error:', error.message); + } + } + + console.log('✅ Risk management fix complete!'); + + } catch (error) { + console.error('❌ Error fixing SL/TP:', error.message); + } +} + +fixMissingSLTP(); diff --git a/lib/simple-automation.js b/lib/simple-automation.js index e66fa1c..37efc2f 100644 --- a/lib/simple-automation.js +++ b/lib/simple-automation.js @@ -798,7 +798,33 @@ class SimpleAutomation { takeProfit = parseFloat(takeProfit.replace(/[^0-9.]/g, '')); } - console.log(`🎯 Trade levels - SL: ${stopLoss}, TP: ${takeProfit}`); + // 🛡️ FALLBACK RISK MANAGEMENT: Ensure SL/TP always exist + if (!stopLoss || !takeProfit) { + console.log('⚠️ Missing AI-calculated SL/TP, generating fallback values...'); + const currentPrice = analysis.entry?.price || analysis.currentPrice || 178; + + if (!stopLoss) { + // Fallback: 1.5% stop loss for scalping + if (side === 'BUY' || side === 'LONG') { + stopLoss = currentPrice * 0.985; // 1.5% below entry + } else { + stopLoss = currentPrice * 1.015; // 1.5% above entry + } + console.log(`🔧 Generated fallback stop loss: $${stopLoss.toFixed(4)} (1.5%)`); + } + + if (!takeProfit) { + // Fallback: 3% take profit for scalping (2:1 risk/reward) + if (side === 'BUY' || side === 'LONG') { + takeProfit = currentPrice * 1.03; // 3% above entry + } else { + takeProfit = currentPrice * 0.97; // 3% below entry + } + console.log(`🔧 Generated fallback take profit: $${takeProfit.toFixed(4)} (3%)`); + } + } + + console.log(`🎯 Final trade levels - SL: ${stopLoss}, TP: ${takeProfit}`); // Calculate optimal leverage using AI Leverage Calculator let optimalLeverage = 1; // Default fallback diff --git a/place-scalping-sltp.js b/place-scalping-sltp.js new file mode 100644 index 0000000..ae28c39 --- /dev/null +++ b/place-scalping-sltp.js @@ -0,0 +1,117 @@ +#!/usr/bin/env node + +// Quick script to place stop loss and take profit for scalping positions + +async function placeScalpingSLTP() { + try { + console.log('🎯 Setting up scalping risk management...'); + + // First, get current position + const posResponse = await fetch('http://localhost:9001/api/drift/positions'); + const posData = await posResponse.json(); + + if (!posData.positions || posData.positions.length === 0) { + console.log('❌ No active positions found'); + return; + } + + const position = posData.positions[0]; // Assuming SOL position + console.log('📊 Current position:', { + symbol: position.symbol, + size: position.size, + direction: position.direction, + entryPrice: position.entryPrice, + unrealizedPnl: position.unrealizedPnl + }); + + // Get current SOL price for calculations + const priceResponse = await fetch('http://localhost:9001/api/drift/balance'); + const priceData = await priceResponse.json(); + const currentPrice = parseFloat(position.markPrice || position.entryPrice); + + console.log('💰 Current SOL price:', currentPrice); + + // Scalping risk management (tight stops for quick profits) + const isLong = position.direction === 'LONG'; + const positionSize = Math.abs(parseFloat(position.size)); + + // Scalping parameters (adjust these based on your risk tolerance) + const stopLossPercent = 0.5; // 0.5% stop loss (tight for scalping) + const takeProfitPercent = 1.0; // 1% take profit (1:2 risk/reward) + + // Calculate SL and TP prices + let stopLossPrice, takeProfitPrice; + + if (isLong) { + stopLossPrice = currentPrice * (1 - stopLossPercent / 100); + takeProfitPrice = currentPrice * (1 + takeProfitPercent / 100); + } else { + stopLossPrice = currentPrice * (1 + stopLossPercent / 100); + takeProfitPrice = currentPrice * (1 - takeProfitPercent / 100); + } + + console.log('🎯 Calculated prices:', { + currentPrice: currentPrice.toFixed(3), + stopLoss: stopLossPrice.toFixed(3), + takeProfit: takeProfitPrice.toFixed(3), + slDistance: `${stopLossPercent}%`, + tpDistance: `${takeProfitPercent}%` + }); + + // Place Stop Loss order + console.log('🛑 Placing Stop Loss order...'); + const slResponse = await fetch('http://localhost:9001/api/drift/place-order', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + symbol: 'SOL-PERP', + orderType: 'STOP_MARKET', + direction: isLong ? 'SHORT' : 'LONG', // Opposite direction to close position + size: positionSize, + triggerPrice: stopLossPrice, + reduceOnly: true + }) + }); + + const slResult = await slResponse.json(); + console.log('🛑 Stop Loss result:', slResult.success ? '✅ Placed' : '❌ Failed', slResult); + + // Place Take Profit order + console.log('💰 Placing Take Profit order...'); + const tpResponse = await fetch('http://localhost:9001/api/drift/place-order', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + symbol: 'SOL-PERP', + orderType: 'LIMIT', + direction: isLong ? 'SHORT' : 'LONG', // Opposite direction to close position + size: positionSize, + price: takeProfitPrice, + reduceOnly: true + }) + }); + + const tpResult = await tpResponse.json(); + console.log('💰 Take Profit result:', tpResult.success ? '✅ Placed' : '❌ Failed', tpResult); + + // Verify orders were placed + console.log('📋 Checking placed orders...'); + const ordersResponse = await fetch('http://localhost:9001/api/drift/orders'); + const ordersData = await ordersResponse.json(); + + const reduceOnlyOrders = ordersData.orders?.filter(order => order.reduceOnly) || []; + console.log(`📊 Active reduce-only orders: ${reduceOnlyOrders.length}`); + + reduceOnlyOrders.forEach(order => { + console.log(` - ${order.orderType} ${order.direction} at ${order.triggerPrice || order.price}`); + }); + + console.log('🎯 Scalping risk management setup complete!'); + + } catch (error) { + console.error('❌ Error setting up scalping SL/TP:', error.message); + } +} + +// Run the function +placeScalpingSLTP(); diff --git a/prisma/prisma/dev.db b/prisma/prisma/dev.db index 0d26e58..30cb342 100644 Binary files a/prisma/prisma/dev.db and b/prisma/prisma/dev.db differ