From bd49c658674c8e23a3f51b5ea08187e25d6f631b Mon Sep 17 00:00:00 2001 From: mindesbunister Date: Fri, 18 Jul 2025 13:33:34 +0200 Subject: [PATCH] feat: Fix position calculator visibility and add auto-detection - Fixed position calculator not showing when analysis entry price is 0 - Added auto-detection of Long/Short position type from AI analysis recommendation - Implemented independent price fetching from CoinGecko API - Added current market price display with AI recommendation - Enhanced position calculator with fallback prices for testing - Added API endpoint /api/price for real-time price data - Position calculator now works even when analysis lacks specific entry prices - Shows 'Auto-detected from analysis' label when position type is determined from AI The position calculator is now always visible and uses: 1. Current market price from CoinGecko API 2. Auto-detected position type from analysis (Long/Short) 3. Fallback prices for testing when API is unavailable 4. Default stop loss/take profit levels when not specified in analysis --- app/api/price/route.js | 75 +++++++++++++++++++++++++++++++ components/PositionCalculator.tsx | 68 +++++++++++++++++++++++++--- 2 files changed, 137 insertions(+), 6 deletions(-) create mode 100644 app/api/price/route.js diff --git a/app/api/price/route.js b/app/api/price/route.js new file mode 100644 index 0000000..ca9fa0f --- /dev/null +++ b/app/api/price/route.js @@ -0,0 +1,75 @@ +import { NextResponse } from 'next/server' + +export async function GET(request) { + const { searchParams } = new URL(request.url) + const symbol = searchParams.get('symbol') || 'BTCUSD' + + try { + // Map symbols to CoinGecko IDs + const symbolMap = { + 'BTCUSD': 'bitcoin', + 'ETHUSD': 'ethereum', + 'SOLUSD': 'solana', + 'SUIUSD': 'sui', + 'ADAUSD': 'cardano', + 'DOGEUSD': 'dogecoin', + 'XRPUSD': 'ripple', + 'AVAXUSD': 'avalanche-2', + 'LINKUSD': 'chainlink', + 'MATICUSD': 'matic-network' + } + + const coinId = symbolMap[symbol.toUpperCase()] || 'bitcoin' + + // Fetch from CoinGecko API + const response = await fetch( + `https://api.coingecko.com/api/v3/simple/price?ids=${coinId}&vs_currencies=usd`, + { + headers: { + 'Accept': 'application/json', + } + } + ) + + if (!response.ok) { + throw new Error(`CoinGecko API error: ${response.status}`) + } + + const data = await response.json() + const price = data[coinId]?.usd + + if (!price) { + throw new Error('Price not found') + } + + return NextResponse.json({ + symbol: symbol.toUpperCase(), + price: price, + source: 'coingecko' + }) + + } catch (error) { + console.error('Price fetch error:', error) + + // Return fallback prices for testing + const fallbackPrices = { + 'BTCUSD': 100000, + 'ETHUSD': 4000, + 'SOLUSD': 200, + 'SUIUSD': 4.5, + 'ADAUSD': 1.2, + 'DOGEUSD': 0.4, + 'XRPUSD': 2.5, + 'AVAXUSD': 45, + 'LINKUSD': 20, + 'MATICUSD': 1.1 + } + + return NextResponse.json({ + symbol: symbol.toUpperCase(), + price: fallbackPrices[symbol.toUpperCase()] || 100, + source: 'fallback', + error: error.message + }) + } +} diff --git a/components/PositionCalculator.tsx b/components/PositionCalculator.tsx index eaf14fa..b6d04d5 100644 --- a/components/PositionCalculator.tsx +++ b/components/PositionCalculator.tsx @@ -36,14 +36,52 @@ export default function PositionCalculator({ const [positionType, setPositionType] = useState<'long' | 'short'>('long') const [calculation, setCalculation] = useState(null) const [showAdvanced, setShowAdvanced] = useState(false) + const [marketPrice, setMarketPrice] = useState(currentPrice) // Trading parameters const [tradingFee, setTradingFee] = useState(0.1) // 0.1% fee const [maintenanceMargin, setMaintenanceMargin] = useState(0.5) // 0.5% maintenance margin + // Auto-detect position type from analysis + useEffect(() => { + if (analysis?.recommendation) { + const rec = analysis.recommendation.toLowerCase() + if (rec.includes('buy') || rec.includes('long') || rec.includes('bullish')) { + setPositionType('long') + } else if (rec.includes('sell') || rec.includes('short') || rec.includes('bearish')) { + setPositionType('short') + } + } + }, [analysis]) + + // Fetch current market price if not provided + useEffect(() => { + const fetchPrice = async () => { + if (currentPrice > 0) { + setMarketPrice(currentPrice) + return + } + + try { + const response = await fetch(`/api/price?symbol=${symbol}`) + const data = await response.json() + if (data.price) { + setMarketPrice(data.price) + } + } catch (error) { + console.error('Failed to fetch price:', error) + // Fallback to a reasonable default for testing + setMarketPrice(symbol.includes('BTC') ? 100000 : symbol.includes('ETH') ? 4000 : 100) + } + } + + fetchPrice() + }, [currentPrice, symbol]) + // Calculate position metrics const calculatePosition = () => { - if (!currentPrice || currentPrice <= 0) return null + const priceToUse = marketPrice || currentPrice + if (!priceToUse || priceToUse <= 0) return null const positionSize = investmentAmount * leverage const marginRequired = investmentAmount @@ -51,7 +89,7 @@ export default function PositionCalculator({ const netInvestment = investmentAmount + fee // Get AI analysis targets if available - let entryPrice = currentPrice + let entryPrice = priceToUse let stopLoss = 0 let takeProfit = 0 @@ -92,11 +130,11 @@ export default function PositionCalculator({ } else { // Default targets if no analysis stopLoss = positionType === 'long' - ? currentPrice * 0.95 - : currentPrice * 1.05 + ? priceToUse * 0.95 + : priceToUse * 1.05 takeProfit = positionType === 'long' - ? currentPrice * 1.10 - : currentPrice * 0.90 + ? priceToUse * 1.10 + : priceToUse * 0.90 } // Calculate liquidation price @@ -176,6 +214,21 @@ export default function PositionCalculator({ + {/* Current Price Display */} +
+
+
Current Market Price
+
+ {symbol}: ${formatPrice(marketPrice || currentPrice || 0)} +
+
+ {analysis?.recommendation && ( +
+ AI Recommendation: {analysis.recommendation} +
+ )} +
+ {/* Input Controls */}
{/* Investment Amount */} @@ -197,6 +250,9 @@ export default function PositionCalculator({