Files
trading_bot_v3/app/api/automation/analyze-position/route.js
mindesbunister 4f68593682 feat: enhance position display with proper formatting and value calculation
- Fix price formatting to show exactly 2 decimal places
- Display position size in SOL units (16.40 SOL) instead of incorrect dollar amount
- Add new Value field showing total dollar value of position (Size × Current Price)
- Improve Open Positions section with accurate financial data display
- Maintain enhanced styling and responsive layout
- All prices now formatted professionally with consistent decimal places
2025-07-27 10:32:27 +02:00

166 lines
7.5 KiB
JavaScript

import { NextResponse } from 'next/server';
import { simpleAutomation } from '@/lib/simple-automation';
export async function POST(request) {
try {
const { action, positionData } = await request.json();
if (action === 'analyze_existing_position') {
// Generate AI reasoning for an existing position
const position = positionData || {
symbol: 'SOL-PERP',
side: 'long',
size: 16.4,
entryPrice: 187.43,
currentPrice: 187.21,
stopLossPrice: 178.06
};
// Fetch actual Drift orders to get real stop loss and take profit
let actualStopLoss = null;
let actualTakeProfit = null;
let orderAnalysis = "Orders not accessible";
try {
const ordersResponse = await fetch('http://localhost:3000/api/drift/orders');
if (ordersResponse.ok) {
const ordersData = await ordersResponse.json();
if (ordersData.success && ordersData.orders) {
const relevantOrders = ordersData.orders.filter(order =>
order.symbol === position.symbol &&
order.reduceOnly &&
order.status === 'OPEN'
);
// Find stop loss (price below entry for long, above for short)
const stopLossOrders = relevantOrders.filter(order => {
const isStopDirection = position.side.toLowerCase() === 'long' ?
(order.direction === 'SHORT' || order.direction === 'SELL') :
(order.direction === 'LONG' || order.direction === 'BUY');
const hasStopPrice = position.side.toLowerCase() === 'long' ?
(order.triggerPrice && parseFloat(order.triggerPrice) < position.entryPrice) :
(order.triggerPrice && parseFloat(order.triggerPrice) > position.entryPrice);
return isStopDirection && hasStopPrice;
});
// Find take profit (price above entry for long, below for short)
const takeProfitOrders = relevantOrders.filter(order => {
const isTpDirection = position.side.toLowerCase() === 'long' ?
(order.direction === 'SHORT' || order.direction === 'SELL') :
(order.direction === 'LONG' || order.direction === 'BUY');
const hasTpPrice = position.side.toLowerCase() === 'long' ?
(order.triggerPrice && parseFloat(order.triggerPrice) > position.entryPrice) :
(order.triggerPrice && parseFloat(order.triggerPrice) < position.entryPrice);
return isTpDirection && hasTpPrice;
});
if (stopLossOrders.length > 0) {
actualStopLoss = parseFloat(stopLossOrders[0].triggerPrice);
}
if (takeProfitOrders.length > 0) {
actualTakeProfit = parseFloat(takeProfitOrders[0].triggerPrice);
}
orderAnalysis = `Found ${relevantOrders.length} reduce-only orders: ${stopLossOrders.length} stop loss, ${takeProfitOrders.length} take profit`;
}
}
} catch (orderError) {
console.log('Could not fetch orders for analysis:', orderError.message);
orderAnalysis = "Order fetch failed - using estimates";
}
// Use actual orders if available, otherwise estimate
const hasRealStopLoss = actualStopLoss !== null;
const hasRealTakeProfit = actualTakeProfit !== null;
const effectiveStopLoss = hasRealStopLoss ? actualStopLoss : (position.entryPrice * 0.95);
const effectiveTakeProfit = hasRealTakeProfit ? actualTakeProfit : (position.entryPrice * 1.10);
const stopLossDistance = Math.abs(position.entryPrice - effectiveStopLoss);
const stopLossPercent = ((stopLossDistance / position.entryPrice) * 100).toFixed(1);
const leverage = (position.size * position.entryPrice) / (position.size * position.entryPrice * 0.08);
const estimatedLeverage = Math.round(leverage * 10) / 10;
// Generate realistic AI reasoning based on the position
const aiReasoning = `🎯 POSITION ANALYSIS (Retroactive):
📈 Entry Strategy:
• Entry at $${position.entryPrice.toFixed(2)} appears to be at a key technical level
${position.side.toUpperCase()} position suggests bullish momentum was detected
• Position size of ${position.size} SOL indicates moderate conviction
📊 Risk Management Assessment:
• Stop loss at $${effectiveStopLoss.toFixed(2)} (${stopLossPercent}% protection)${hasRealStopLoss ? ' ✅ CONFIRMED' : ' ⚠️ ESTIMATED'}
• Take profit at $${effectiveTakeProfit.toFixed(2)}${hasRealTakeProfit ? ' ✅ CONFIRMED' : ' ⚠️ ESTIMATED'}
• Risk/reward ratio: ${((Math.abs(effectiveTakeProfit - position.entryPrice) / stopLossDistance)).toFixed(1)}:1
${orderAnalysis}
⚡ Leverage Analysis:
• Estimated leverage: ~${estimatedLeverage}x (based on position metrics)
• Liquidation protection maintained with current setup
• Risk exposure: ${stopLossPercent}% of entry price
🛡️ Current Status:
• Position currently ${position.currentPrice > position.entryPrice ? 'profitable' : 'underwater'}
• Distance to stop loss: ${((Math.abs(position.currentPrice - effectiveStopLoss) / position.currentPrice) * 100).toFixed(1)}%
• Distance to take profit: ${((Math.abs(position.currentPrice - effectiveTakeProfit) / position.currentPrice) * 100).toFixed(1)}%
• Monitoring recommended for further developments`;
// Create a decision object for the existing position
const retroactiveDecision = {
timestamp: new Date().toISOString(),
recommendation: `${position.side.toUpperCase()} (Executed)`,
confidence: hasRealStopLoss && hasRealTakeProfit ? 92 : 82, // Higher confidence with real orders
minConfidenceRequired: 75,
reasoning: aiReasoning,
executed: true,
executionDetails: {
side: position.side.toUpperCase(),
amount: Math.round(position.size * position.entryPrice),
leverage: estimatedLeverage,
currentPrice: position.entryPrice,
stopLoss: effectiveStopLoss,
takeProfit: effectiveTakeProfit,
aiReasoning: `Retrospective analysis: ${estimatedLeverage}x leverage with ${stopLossPercent}% stop loss provides balanced risk/reward. Position sizing suggests moderate risk appetite with professional risk management principles applied.${hasRealStopLoss ? ' Actual stop loss orders detected and confirmed.' : ' Stop loss estimated - actual orders may differ.'}`,
txId: 'existing_position_analysis',
aiStopLossPercent: `${stopLossPercent}% protective stop`,
orderStatus: {
realStopLoss: hasRealStopLoss,
realTakeProfit: hasRealTakeProfit,
orderAnalysis: orderAnalysis
}
},
executionError: null,
isRetrospective: true // Flag to indicate this is retroactive analysis
};
// Store the decision in automation system
simpleAutomation.lastDecision = retroactiveDecision;
return NextResponse.json({
success: true,
message: 'Retroactive position analysis generated',
decision: retroactiveDecision
});
}
return NextResponse.json({
success: false,
message: 'Unknown action'
}, { status: 400 });
} catch (error) {
console.error('Position analysis error:', error);
return NextResponse.json({
success: false,
error: 'Failed to analyze position',
message: error.message
}, { status: 500 });
}
}