Spaces:
Running
Running
| // Global variables | |
| let trades = []; | |
| let currentMarketPrice = 0; | |
| let marketData = []; | |
| // Initialize the application | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Set default date to today | |
| const today = new Date().toISOString().split('T')[0]; | |
| document.getElementById('marketDate').value = today; | |
| // Add first trade | |
| addTrade(); | |
| // Set up event listeners | |
| document.getElementById('fetchDataBtn').addEventListener('click', fetchMarketData); | |
| document.getElementById('addTradeBtn').addEventListener('click', addTrade); | |
| // Price slider and input synchronization | |
| const priceSlider = document.getElementById('priceSlider'); | |
| const priceInput = document.getElementById('priceInput'); | |
| priceSlider.addEventListener('input', function() { | |
| currentMarketPrice = parseFloat(this.value); | |
| priceInput.value = currentMarketPrice.toFixed(2); | |
| updateAllCalculations(); | |
| }); | |
| priceInput.addEventListener('input', function() { | |
| currentMarketPrice = parseFloat(this.value) || 0; | |
| priceSlider.value = currentMarketPrice; | |
| updateAllCalculations(); | |
| }); | |
| }); | |
| // Fetch market data from API | |
| async function fetchMarketData() { | |
| const symbol = document.getElementById('stockSymbol').value.trim().toUpperCase() || 'RELIANCE'; | |
| const date = document.getElementById('marketDate').value; | |
| if (!date) { | |
| alert('Please select a date'); | |
| return; | |
| } | |
| // Show loading state | |
| const btn = document.getElementById('fetchDataBtn'); | |
| const originalText = btn.innerHTML; | |
| btn.innerHTML = '<span class="loading"></span> Loading...'; | |
| btn.disabled = true; | |
| try { | |
| // Convert date to timestamps | |
| const startDate = new Date(date + 'T00:01:00'); | |
| const endDate = new Date(date + 'T23:58:00'); | |
| const startTime = startDate.getTime(); | |
| const endTime = endDate.getTime(); | |
| // Construct API URL | |
| const url = `http://localhost:5000/chart?ticker=${symbol}&date=${date}`; | |
| const response = await fetch(url); | |
| const data = await response.json(); | |
| if (data && data.length > 0) { | |
| marketData = data; | |
| // Process data - we'll use the times as-is (assuming they're in proper format) | |
| const processedData = marketData.map(item => ({ | |
| price: item.price, | |
| time: item.time | |
| })); | |
| // Update UI | |
| updateMarketInfo(processedData); | |
| document.getElementById('marketInfo').classList.remove('hidden'); | |
| // Set initial price | |
| if (processedData.length > 0) { | |
| currentMarketPrice = processedData[processedData.length - 1].price; | |
| document.getElementById('priceSlider').value = currentMarketPrice; | |
| document.getElementById('priceInput').value = currentMarketPrice.toFixed(2); | |
| updateAllCalculations(); | |
| } | |
| } else { | |
| alert('No data available for the selected date'); | |
| } | |
| } catch (error) { | |
| console.error('Error fetching market data:', error); | |
| alert('Failed to fetch market data. Please try again.'); | |
| } finally { | |
| // Reset button state | |
| btn.innerHTML = originalText; | |
| btn.disabled = false; | |
| feather.replace(); | |
| } | |
| } | |
| // Update market info display | |
| function updateMarketInfo(data) { | |
| const currentPrice = data[data.length - 1].price; | |
| const lastUpdated = data[data.length - 1].time; | |
| document.getElementById('currentPrice').textContent = `₹${currentPrice.toFixed(2)}`; | |
| document.getElementById('lastUpdated').textContent = lastUpdated; | |
| // Update slider range based on data | |
| const prices = data.map(d => d.price); | |
| const minPrice = Math.min(...prices) * 0.9; | |
| const maxPrice = Math.max(...prices) * 1.1; | |
| const slider = document.getElementById('priceSlider'); | |
| slider.min = minPrice; | |
| slider.max = maxPrice; | |
| } | |
| // Add a new trade | |
| function addTrade() { | |
| const tradeId = 'trade_' + Date.now(); | |
| const trade = { | |
| id: tradeId, | |
| type: 'BUY', | |
| quantity: 0, | |
| price: 0 | |
| }; | |
| trades.push(trade); | |
| renderTrade(trade); | |
| } | |
| // Render trade UI | |
| function renderTrade(trade) { | |
| const container = document.getElementById('tradesContainer'); | |
| const tradeElement = document.createElement('div'); | |
| tradeElement.id = trade.id; | |
| tradeElement.className = 'bg-gray-700 rounded-lg p-4 border border-gray-600'; | |
| tradeElement.innerHTML = ` | |
| <div class="grid grid-cols-1 md:grid-cols-5 gap-4 items-end"> | |
| <div> | |
| <label class="block text-sm font-medium mb-2">Trade Type</label> | |
| <div class="flex bg-gray-600 rounded-lg p-1"> | |
| <button class="trade-type-btn flex-1 py-2 px-3 rounded-md text-sm font-medium transition-colors ${trade.type === 'BUY' ? 'bg-blue-600 text-white' : 'text-gray-300'}" data-type="BUY" data-trade-id="${trade.id}"> | |
| BUY | |
| </button> | |
| <button class="trade-type-btn flex-1 py-2 px-3 rounded-md text-sm font-medium transition-colors ${trade.type === 'SELL' ? 'bg-purple-600 text-white' : 'text-gray-300'}" data-type="SELL" data-trade-id="${trade.id}"> | |
| SELL | |
| </button> | |
| </div> | |
| </div> | |
| <div> | |
| <label class="block text-sm font-medium mb-2">Quantity</label> | |
| <input type="number" class="trade-quantity w-full px-3 py-2 bg-gray-600 border border-gray-500 rounded-lg focus:outline-none focus:border-blue-500 transition-colors" placeholder="0" min="0" step="1"> | |
| </div> | |
| <div> | |
| <label class="block text-sm font-medium mb-2">Trade Price (₹)</label> | |
| <input type="number" class="trade-price w-full px-3 py-2 bg-gray-600 border border-gray-500 rounded-lg focus:outline-none focus:border-blue-500 transition-colors" placeholder="0.00" min="0" step="0.01"> | |
| </div> | |
| <div> | |
| <label class="block text-sm font-medium mb-2">P&L (₹)</label> | |
| <div class="trade-pl text-lg font-semibold">₹0.00</div> | |
| </div> | |
| <div> | |
| <button class="remove-trade-btn bg-red-600 hover:bg-red-700 text-white py-2 px-3 rounded-lg transition-colors flex items-center justify-center"> | |
| <i data-feather="trash-2" class="w-4 h-4"></i> | |
| </button> | |
| </div> | |
| </div> | |
| `; | |
| container.appendChild(tradeElement); | |
| // Set up event listeners | |
| tradeElement.querySelector('.trade-type-btn[data-type="BUY"]').addEventListener('click', function() { | |
| updateTradeType(trade.id, 'BUY'); | |
| }); | |
| tradeElement.querySelector('.trade-type-btn[data-type="SELL"]').addEventListener('click', function() { | |
| updateTradeType(trade.id, 'SELL'); | |
| }); | |
| tradeElement.querySelector('.trade-quantity').addEventListener('input', function() { | |
| updateTradeQuantity(trade.id, parseFloat(this.value) || 0); | |
| }); | |
| tradeElement.querySelector('.trade-price').addEventListener('input', function() { | |
| updateTradePrice(trade.id, parseFloat(this.value) || 0); | |
| }); | |
| tradeElement.querySelector('.remove-trade-btn').addEventListener('click', function() { | |
| removeTrade(trade.id); | |
| }); | |
| feather.replace(); | |
| } | |
| // Update trade type | |
| function updateTradeType(tradeId, type) { | |
| const trade = trades.find(t => t.id === tradeId); | |
| if (trade) { | |
| trade.type = type; | |
| // Update UI | |
| const tradeElement = document.getElementById(tradeId); | |
| const buyBtn = tradeElement.querySelector('.trade-type-btn[data-type="BUY"]'); | |
| const sellBtn = tradeElement.querySelector('.trade-type-btn[data-type="SELL"]'); | |
| if (type === 'BUY') { | |
| buyBtn.className = 'trade-type-btn flex-1 py-2 px-3 rounded-md text-sm font-medium transition-colors bg-blue-600 text-white'; | |
| sellBtn.className = 'trade-type-btn flex-1 py-2 px-3 rounded-md text-sm font-medium transition-colors text-gray-300'; | |
| } else { | |
| buyBtn.className = 'trade-type-btn flex-1 py-2 px-3 rounded-md text-sm font-medium transition-colors text-gray-300'; | |
| sellBtn.className = 'trade-type-btn flex-1 py-2 px-3 rounded-md text-sm font-medium transition-colors bg-purple-600 text-white'; | |
| } | |
| updateCalculations(tradeId); | |
| } | |
| } | |
| // Update trade quantity | |
| function updateTradeQuantity(tradeId, quantity) { | |
| const trade = trades.find(t => t.id === tradeId); | |
| if (trade) { | |
| trade.quantity = quantity; | |
| updateCalculations(tradeId); | |
| } | |
| } | |
| // Update trade price | |
| function updateTradePrice(tradeId, price) { | |
| const trade = trades.find(t => t.id === tradeId); | |
| if (trade) { | |
| trade.price = price; | |
| updateCalculations(tradeId); | |
| } | |
| } | |
| // Remove trade | |
| function removeTrade(tradeId) { | |
| trades = trades.filter(t => t.id !== tradeId); | |
| const tradeElement = document.getElementById(tradeId); | |
| tradeElement.remove(); | |
| updateTotalPL(); | |
| } | |
| // Update calculations for a specific trade | |
| function updateCalculations(tradeId) { | |
| const trade = trades.find(t => t.id === tradeId); | |
| if (!trade) return; | |
| const pl = calculatePL(trade); | |
| const tradeElement = document.getElementById(tradeId); | |
| const plElement = tradeElement.querySelector('.trade-pl'); | |
| plElement.textContent = `₹${pl.toFixed(2)}`; | |
| // Apply color based on profit/loss | |
| plElement.classList.remove('text-green-400', 'text-red-400', 'profit-pulse', 'loss-pulse'); | |
| if (pl > 0) { | |
| plElement.classList.add('text-green-400', 'profit-pulse'); | |
| } else if (pl < 0) { | |
| plElement.classList.add('text-red-400', 'loss-pulse'); | |
| } | |
| updateTotalPL(); | |
| } | |
| // Calculate P&L for a single trade | |
| function calculatePL(trade) { | |
| if (trade.quantity === 0) return 0; | |
| let pl; | |
| if (trade.type === 'BUY') { | |
| pl = (currentMarketPrice - trade.price) * trade.quantity; | |
| } else { | |
| pl = (trade.price - currentMarketPrice) * trade.quantity; | |
| } | |
| return pl; | |
| } | |
| // Update total P&L | |
| function updateTotalPL() { | |
| const totalPL = trades.reduce((sum, trade) => sum + calculatePL(trade), 0); | |
| const totalPLElement = document.getElementById('totalPLValue'); | |
| totalPLElement.textContent = `₹${totalPL.toFixed(2)}`; | |
| totalPLElement.classList.remove('text-green-400', 'text-red-400'); | |
| if (totalPL > 0) { | |
| totalPLElement.classList.add('text-green-400'); | |
| } else if (totalPL < 0) { | |
| totalPLElement.classList.add('text-red-400'); | |
| } | |
| } | |
| // Update all calculations | |
| function updateAllCalculations() { | |
| trades.forEach(trade => updateCalculations(trade.id)); | |
| } |