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
This commit is contained in:
mindesbunister
2025-07-27 10:32:27 +02:00
parent e88561cea1
commit 4f68593682
8 changed files with 3282 additions and 199 deletions

View File

@@ -16,12 +16,74 @@ export async function POST(request) {
stopLossPrice: 178.06
};
// Calculate some metrics - handle missing stop loss
const hasStopLoss = position.stopLossPrice && position.stopLossPrice > 0;
const estimatedStopLoss = hasStopLoss ? position.stopLossPrice : (position.entryPrice * 0.95); // 5% default
const stopLossDistance = Math.abs(position.entryPrice - estimatedStopLoss);
// 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); // Estimate based on position
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
@@ -33,9 +95,10 @@ export async function POST(request) {
• Position size of ${position.size} SOL indicates moderate conviction
📊 Risk Management Assessment:
• Stop loss at $${estimatedStopLoss.toFixed(2)} (${stopLossPercent}% protection)${hasStopLoss ? '' : ' - ESTIMATED'}
Risk/reward setup suggests ${stopLossPercent}% stop with potential 2-3x reward
Position sizing appears conservative for risk tolerance
• 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)
@@ -44,14 +107,15 @@ export async function POST(request) {
🛡️ Current Status:
• Position currently ${position.currentPrice > position.entryPrice ? 'profitable' : 'underwater'}
• Distance to ${hasStopLoss ? 'stop loss' : 'estimated stop'}: ${((Math.abs(position.currentPrice - estimatedStopLoss) / position.currentPrice) * 100).toFixed(1)}%
• 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: 82, // Estimated confidence based on position size and setup
confidence: hasRealStopLoss && hasRealTakeProfit ? 92 : 82, // Higher confidence with real orders
minConfidenceRequired: 75,
reasoning: aiReasoning,
executed: true,
@@ -60,11 +124,16 @@ export async function POST(request) {
amount: Math.round(position.size * position.entryPrice),
leverage: estimatedLeverage,
currentPrice: position.entryPrice,
stopLoss: estimatedStopLoss,
takeProfit: position.entryPrice + (stopLossDistance * 2.5), // Estimate 2.5:1 RR
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.${hasStopLoss ? '' : ' Note: Stop loss estimated as not visible in position data.'}`,
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`
aiStopLossPercent: `${stopLossPercent}% protective stop`,
orderStatus: {
realStopLoss: hasRealStopLoss,
realTakeProfit: hasRealTakeProfit,
orderAnalysis: orderAnalysis
}
},
executionError: null,
isRetrospective: true // Flag to indicate this is retroactive analysis