|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Trading Agent Dashboard</title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"></script> |
|
<style> |
|
.gradient-bg { |
|
background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%); |
|
} |
|
.signal-buy { |
|
background-color: rgba(74, 222, 128, 0.2); |
|
border-left: 4px solid rgba(74, 222, 128, 1); |
|
} |
|
.signal-sell { |
|
background-color: rgba(248, 113, 113, 0.2); |
|
border-left: 4px solid rgba(248, 113, 113, 1); |
|
} |
|
.fade-in { |
|
animation: fadeIn 0.5s ease-in-out; |
|
} |
|
@keyframes fadeIn { |
|
from { opacity: 0; transform: translateY(10px); } |
|
to { opacity: 1; transform: translateY(0); } |
|
} |
|
.loading-spinner { |
|
border: 4px solid rgba(0, 0, 0, 0.1); |
|
border-radius: 50%; |
|
border-top: 4px solid #3b82f6; |
|
width: 40px; |
|
height: 40px; |
|
animation: spin 1s linear infinite; |
|
} |
|
@keyframes spin { |
|
0% { transform: rotate(0deg); } |
|
100% { transform: rotate(360deg); } |
|
} |
|
</style> |
|
</head> |
|
<body class="bg-gray-100 font-sans"> |
|
<div class="min-h-screen"> |
|
|
|
<header class="gradient-bg text-white shadow-lg"> |
|
<div class="container mx-auto px-4 py-6"> |
|
<div class="flex justify-between items-center"> |
|
<div> |
|
<h1 class="text-3xl font-bold">Trading Agent Dashboard</h1> |
|
<p class="text-blue-200">Analyze any stock with different trading strategies</p> |
|
</div> |
|
<div class="flex items-center space-x-4"> |
|
<div class="bg-blue-800 px-4 py-2 rounded-lg"> |
|
<span class="text-blue-200">Last updated:</span> |
|
<span id="current-date" class="font-medium"></span> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</header> |
|
|
|
|
|
<main class="container mx-auto px-4 py-8"> |
|
|
|
<div class="bg-white rounded-xl shadow-md p-6 mb-8 fade-in"> |
|
<h2 class="text-2xl font-semibold text-gray-800 mb-4">Search for a Stock</h2> |
|
<div class="flex flex-col md:flex-row gap-4"> |
|
<div class="flex-1"> |
|
<label for="stock-symbol" class="block text-sm font-medium text-gray-700 mb-1">Stock Symbol</label> |
|
<div class="relative"> |
|
<input type="text" id="stock-symbol" placeholder="e.g. AAPL, MSFT, JPM" |
|
class="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500"> |
|
<div id="symbol-error" class="hidden absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none"> |
|
<i class="fas fa-exclamation-circle text-red-500"></i> |
|
</div> |
|
</div> |
|
<p id="symbol-error-text" class="mt-1 text-sm text-red-600 hidden">Please enter a valid stock symbol</p> |
|
</div> |
|
<div class="flex-1"> |
|
<label for="time-period" class="block text-sm font-medium text-gray-700 mb-1">Time Period</label> |
|
<select id="time-period" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500"> |
|
<option value="1mo">1 Month</option> |
|
<option value="3mo">3 Months</option> |
|
<option value="6mo">6 Months</option> |
|
<option value="1y" selected>1 Year</option> |
|
<option value="2y">2 Years</option> |
|
<option value="5y">5 Years</option> |
|
<option value="max">Max Available</option> |
|
</select> |
|
</div> |
|
<div class="flex items-end"> |
|
<button id="search-stock" class="px-6 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors"> |
|
<i class="fas fa-search mr-2"></i> Analyze |
|
</button> |
|
</div> |
|
</div> |
|
<div id="stock-info" class="mt-4 hidden"> |
|
<div class="flex items-center"> |
|
<div class="mr-4"> |
|
<h3 id="stock-name" class="text-xl font-semibold"></h3> |
|
<p id="stock-symbol-display" class="text-gray-600"></p> |
|
</div> |
|
<div class="ml-auto"> |
|
<span id="current-price" class="text-2xl font-bold"></span> |
|
<span id="price-change" class="ml-2 px-2 py-1 rounded-full text-sm"></span> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div id="loading-indicator" class="hidden flex flex-col items-center justify-center py-12"> |
|
<div class="loading-spinner mb-4"></div> |
|
<p class="text-gray-600">Fetching stock data and analyzing strategies...</p> |
|
</div> |
|
|
|
|
|
<div id="strategy-selector" class="bg-white rounded-xl shadow-md p-6 mb-8 fade-in hidden"> |
|
<h2 class="text-2xl font-semibold text-gray-800 mb-4">Select Trading Strategy</h2> |
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4"> |
|
<div class="strategy-card bg-white border border-gray-200 rounded-lg p-4 hover:shadow-lg transition-shadow cursor-pointer" data-strategy="turtle"> |
|
<div class="flex items-center mb-2"> |
|
<div class="bg-green-100 p-2 rounded-full mr-3"> |
|
<i class="fas fa-turtle text-green-600"></i> |
|
</div> |
|
<h3 class="text-lg font-medium">Turtle Trading</h3> |
|
</div> |
|
<p class="text-gray-600 text-sm">Based on 20-day highs and lows for entry/exit signals</p> |
|
</div> |
|
<div class="strategy-card bg-white border border-gray-200 rounded-lg p-4 hover:shadow-lg transition-shadow cursor-pointer" data-strategy="moving-average"> |
|
<div class="flex items-center mb-2"> |
|
<div class="bg-blue-100 p-2 rounded-full mr-3"> |
|
<i class="fas fa-chart-line text-blue-600"></i> |
|
</div> |
|
<h3 class="text-lg font-medium">Moving Average</h3> |
|
</div> |
|
<p class="text-gray-600 text-sm">Uses short (2.5%) and long (5%) moving average crossovers</p> |
|
</div> |
|
<div class="strategy-card bg-white border border-gray-200 rounded-lg p-4 hover:shadow-lg transition-shadow cursor-pointer" data-strategy="comparison"> |
|
<div class="flex items-center mb-2"> |
|
<div class="bg-purple-100 p-2 rounded-full mr-3"> |
|
<i class="fas fa-balance-scale text-purple-600"></i> |
|
</div> |
|
<h3 class="text-lg font-medium">Strategy Comparison</h3> |
|
</div> |
|
<p class="text-gray-600 text-sm">Compare performance of all available strategies</p> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div id="dashboard-content"> |
|
|
|
<div class="strategy-view" id="turtle-view"> |
|
|
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-8"> |
|
<div class="bg-white rounded-lg shadow p-4"> |
|
<div class="flex items-center"> |
|
<div class="bg-green-100 p-3 rounded-full mr-3"> |
|
<i class="fas fa-dollar-sign text-green-600"></i> |
|
</div> |
|
<div> |
|
<p class="text-gray-500 text-sm">Initial Capital</p> |
|
<h3 class="text-xl font-semibold">$10,000</h3> |
|
</div> |
|
</div> |
|
</div> |
|
<div class="bg-white rounded-lg shadow p-4"> |
|
<div class="flex items-center"> |
|
<div class="bg-blue-100 p-3 rounded-full mr-3"> |
|
<i class="fas fa-chart-bar text-blue-600"></i> |
|
</div> |
|
<div> |
|
<p class="text-gray-500 text-sm">Final Balance</p> |
|
<h3 class="text-xl font-semibold" id="turtle-final-balance">$12,450</h3> |
|
</div> |
|
</div> |
|
</div> |
|
<div class="bg-white rounded-lg shadow p-4"> |
|
<div class="flex items-center"> |
|
<div class="bg-purple-100 p-3 rounded-full mr-3"> |
|
<i class="fas fa-percentage text-purple-600"></i> |
|
</div> |
|
<div> |
|
<p class="text-gray-500 text-sm">Return</p> |
|
<h3 class="text-xl font-semibold" id="turtle-return">24.5%</h3> |
|
</div> |
|
</div> |
|
</div> |
|
<div class="bg-white rounded-lg shadow p-4"> |
|
<div class="flex items-center"> |
|
<div class="bg-yellow-100 p-3 rounded-full mr-3"> |
|
<i class="fas fa-exchange-alt text-yellow-600"></i> |
|
</div> |
|
<div> |
|
<p class="text-gray-500 text-sm">Total Trades</p> |
|
<h3 class="text-xl font-semibold" id="turtle-trades">18</h3> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="bg-white rounded-xl shadow-md p-6 mb-8"> |
|
<div class="flex justify-between items-center mb-4"> |
|
<h2 class="text-2xl font-semibold text-gray-800" id="turtle-chart-title">Stock Price with Turtle Trading Signals</h2> |
|
<div class="flex space-x-2"> |
|
<button class="time-period-btn px-3 py-1 bg-blue-100 text-blue-700 rounded-md text-sm" data-period="1m">1M</button> |
|
<button class="time-period-btn px-3 py-1 bg-blue-600 text-white rounded-md text-sm" data-period="6m">6M</button> |
|
<button class="time-period-btn px-3 py-1 bg-blue-100 text-blue-700 rounded-md text-sm" data-period="1y">1Y</button> |
|
<button class="time-period-btn px-3 py-1 bg-blue-100 text-blue-700 rounded-md text-sm" data-period="all">All</button> |
|
</div> |
|
</div> |
|
<div class="h-96"> |
|
<canvas id="turtleChart"></canvas> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="bg-white rounded-xl shadow-md p-6"> |
|
<h2 class="text-2xl font-semibold text-gray-800 mb-4">Trade Execution Log</h2> |
|
<div class="overflow-x-auto"> |
|
<table class="min-w-full divide-y divide-gray-200"> |
|
<thead class="bg-gray-50"> |
|
<tr> |
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th> |
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Action</th> |
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Units</th> |
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Price</th> |
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Value</th> |
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Return</th> |
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Balance</th> |
|
</tr> |
|
</thead> |
|
<tbody id="turtle-trades-body" class="bg-white divide-y divide-gray-200"> |
|
|
|
</tbody> |
|
</table> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="strategy-view hidden" id="moving-average-view"> |
|
|
|
</div> |
|
|
|
|
|
<div class="strategy-view hidden" id="comparison-view"> |
|
|
|
</div> |
|
</div> |
|
</main> |
|
|
|
|
|
<footer class="gradient-bg text-white py-6"> |
|
<div class="container mx-auto px-4"> |
|
<div class="flex flex-col md:flex-row justify-between items-center"> |
|
<div class="mb-4 md:mb-0"> |
|
<h2 class="text-xl font-bold">Trading Agent Dashboard</h2> |
|
<p class="text-blue-200">Machine Learning in Asset Management</p> |
|
</div> |
|
<div class="flex space-x-4"> |
|
<a href="#" class="text-blue-200 hover:text-white"><i class="fab fa-github fa-lg"></i></a> |
|
<a href="#" class="text-blue-200 hover:text-white"><i class="fab fa-linkedin fa-lg"></i></a> |
|
<a href="#" class="text-blue-200 hover:text-white"><i class="fab fa-twitter fa-lg"></i></a> |
|
</div> |
|
</div> |
|
<div class="border-t border-blue-800 mt-6 pt-6 text-center text-blue-200 text-sm"> |
|
<p>© 2023 Trading Agent Dashboard. Stock data provided by Yahoo Finance.</p> |
|
</div> |
|
</div> |
|
</footer> |
|
</div> |
|
|
|
<script> |
|
|
|
document.getElementById('current-date').textContent = new Date().toLocaleDateString('en-US', { |
|
year: 'numeric', |
|
month: 'long', |
|
day: 'numeric' |
|
}); |
|
|
|
|
|
const strategyCards = document.querySelectorAll('.strategy-card'); |
|
const strategyViews = document.querySelectorAll('.strategy-view'); |
|
|
|
strategyCards.forEach(card => { |
|
card.addEventListener('click', function() { |
|
|
|
strategyCards.forEach(c => c.classList.remove('border-blue-500', 'ring-2', 'ring-blue-300')); |
|
|
|
|
|
this.classList.add('border-blue-500', 'ring-2', 'ring-blue-300'); |
|
|
|
|
|
strategyViews.forEach(view => view.classList.add('hidden')); |
|
|
|
|
|
const strategy = this.getAttribute('data-strategy'); |
|
document.getElementById(`${strategy}-view`).classList.remove('hidden'); |
|
}); |
|
}); |
|
|
|
|
|
document.getElementById('search-stock').addEventListener('click', function() { |
|
const symbol = document.getElementById('stock-symbol').value.trim().toUpperCase(); |
|
const period = document.getElementById('time-period').value; |
|
|
|
if (!symbol) { |
|
document.getElementById('symbol-error').classList.remove('hidden'); |
|
document.getElementById('symbol-error-text').classList.remove('hidden'); |
|
return; |
|
} |
|
|
|
document.getElementById('symbol-error').classList.add('hidden'); |
|
document.getElementById('symbol-error-text').classList.add('hidden'); |
|
|
|
|
|
document.getElementById('loading-indicator').classList.remove('hidden'); |
|
document.getElementById('strategy-selector').classList.add('hidden'); |
|
document.getElementById('dashboard-content').classList.add('hidden'); |
|
|
|
|
|
setTimeout(() => { |
|
|
|
document.getElementById('loading-indicator').classList.add('hidden'); |
|
|
|
|
|
document.getElementById('stock-info').classList.remove('hidden'); |
|
document.getElementById('stock-name').textContent = `${symbol} Company Name`; |
|
document.getElementById('stock-symbol-display').textContent = `${symbol} | NYSE`; |
|
document.getElementById('current-price').textContent = `$152.75`; |
|
|
|
|
|
const changePercent = (Math.random() * 4 - 2).toFixed(2); |
|
const changeElement = document.getElementById('price-change'); |
|
changeElement.textContent = `${changePercent}%`; |
|
if (changePercent >= 0) { |
|
changeElement.classList.add('bg-green-100', 'text-green-800'); |
|
} else { |
|
changeElement.classList.add('bg-red-100', 'text-red-800'); |
|
} |
|
|
|
|
|
document.getElementById('strategy-selector').classList.remove('hidden'); |
|
document.getElementById('dashboard-content').classList.remove('hidden'); |
|
|
|
|
|
document.getElementById('turtle-chart-title').textContent = `${symbol} Price with Turtle Trading Signals`; |
|
|
|
|
|
const finalBalance = (10000 + Math.random() * 5000).toFixed(2); |
|
const returnPercent = ((finalBalance - 10000) / 10000 * 100).toFixed(2); |
|
const tradeCount = Math.floor(Math.random() * 15) + 5; |
|
|
|
document.getElementById('turtle-final-balance').textContent = `$${finalBalance}`; |
|
document.getElementById('turtle-return').textContent = `${returnPercent}%`; |
|
document.getElementById('turtle-trades').textContent = tradeCount; |
|
|
|
|
|
const tradesBody = document.getElementById('turtle-trades-body'); |
|
tradesBody.innerHTML = ''; |
|
|
|
const startPrice = 100 + Math.random() * 50; |
|
let currentBalance = 10000; |
|
let sharesOwned = 0; |
|
|
|
for (let i = 0; i < tradeCount; i++) { |
|
const isBuy = i % 2 === 0; |
|
const date = new Date(); |
|
date.setDate(date.getDate() - (tradeCount - i) * 3); |
|
|
|
const price = (startPrice + (i * 2) + (Math.random() * 5 - 2.5)).toFixed(2); |
|
const shares = Math.floor(Math.random() * 10) + 1; |
|
const value = (shares * price).toFixed(2); |
|
|
|
let returnPercent = ''; |
|
let rowClass = ''; |
|
|
|
if (isBuy) { |
|
rowClass = 'signal-buy'; |
|
sharesOwned += shares; |
|
currentBalance -= shares * price; |
|
} else { |
|
rowClass = 'signal-sell'; |
|
const buyPrice = (price - 5 - Math.random() * 5).toFixed(2); |
|
returnPercent = (((price - buyPrice) / buyPrice) * 100).toFixed(2); |
|
sharesOwned -= shares; |
|
currentBalance += shares * price; |
|
} |
|
|
|
const row = document.createElement('tr'); |
|
row.className = rowClass; |
|
row.innerHTML = ` |
|
<td class="px-6 py-4 whitespace-nowrap">${date.toLocaleDateString()}</td> |
|
<td class="px-6 py-4 whitespace-nowrap"> |
|
<span class="px-2 py-1 ${isBuy ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'} rounded-full text-xs"> |
|
${isBuy ? 'BUY' : 'SELL'} |
|
</span> |
|
</td> |
|
<td class="px-6 py-4 whitespace-nowrap">${shares}</td> |
|
<td class="px-6 py-4 whitespace-nowrap">$${price}</td> |
|
<td class="px-6 py-4 whitespace-nowrap">$${value}</td> |
|
<td class="px-6 py-4 whitespace-nowrap">${returnPercent || '-'}${returnPercent ? '%' : ''}</td> |
|
<td class="px-6 py-4 whitespace-nowrap">$${currentBalance.toFixed(2)}</td> |
|
`; |
|
|
|
tradesBody.appendChild(row); |
|
} |
|
|
|
|
|
updateCharts(symbol, period); |
|
|
|
}, 1500); |
|
}); |
|
|
|
function updateCharts(symbol, period) { |
|
|
|
let labels = []; |
|
let prices = []; |
|
let buySignals = []; |
|
let sellSignals = []; |
|
|
|
const now = new Date(); |
|
let pointCount = 20; |
|
|
|
if (period === '1m') pointCount = 20; |
|
else if (period === '3m') pointCount = 60; |
|
else if (period === '6m') pointCount = 120; |
|
else if (period === '1y') pointCount = 240; |
|
else pointCount = 500; |
|
|
|
let basePrice = 100 + Math.random() * 50; |
|
|
|
for (let i = 0; i < pointCount; i++) { |
|
const date = new Date(now); |
|
date.setDate(date.getDate() - (pointCount - i)); |
|
|
|
labels.push(date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })); |
|
|
|
|
|
basePrice += Math.random() * 2 - 1; |
|
prices.push(basePrice); |
|
|
|
|
|
if (i > 0 && i % 5 === 0) { |
|
buySignals.push({ x: i, y: basePrice - 2 }); |
|
sellSignals.push({ x: i + 3, y: basePrice + 2 }); |
|
} else { |
|
buySignals.push(null); |
|
sellSignals.push(null); |
|
} |
|
} |
|
|
|
|
|
const turtleCtx = document.getElementById('turtleChart').getContext('2d'); |
|
|
|
|
|
if (window.turtleChart) { |
|
window.turtleChart.destroy(); |
|
} |
|
|
|
window.turtleChart = new Chart(turtleCtx, { |
|
type: 'line', |
|
data: { |
|
labels: labels, |
|
datasets: [ |
|
{ |
|
label: `${symbol} Close Price`, |
|
data: prices, |
|
borderColor: '#3b82f6', |
|
backgroundColor: 'rgba(59, 130, 246, 0.1)', |
|
borderWidth: 2, |
|
fill: true, |
|
tension: 0.1 |
|
}, |
|
{ |
|
label: 'Buy Signals', |
|
data: buySignals, |
|
borderColor: '#10b981', |
|
backgroundColor: '#10b981', |
|
borderWidth: 2, |
|
pointRadius: 6, |
|
pointHoverRadius: 8, |
|
showLine: false |
|
}, |
|
{ |
|
label: 'Sell Signals', |
|
data: sellSignals, |
|
borderColor: '#ef4444', |
|
backgroundColor: '#ef4444', |
|
borderWidth: 2, |
|
pointRadius: 6, |
|
pointHoverRadius: 8, |
|
showLine: false |
|
} |
|
] |
|
}, |
|
options: { |
|
responsive: true, |
|
maintainAspectRatio: false, |
|
plugins: { |
|
legend: { |
|
position: 'top', |
|
}, |
|
tooltip: { |
|
mode: 'index', |
|
intersect: false, |
|
} |
|
}, |
|
scales: { |
|
y: { |
|
beginAtZero: false, |
|
grid: { |
|
drawBorder: false |
|
} |
|
}, |
|
x: { |
|
grid: { |
|
display: false |
|
} |
|
} |
|
} |
|
} |
|
}); |
|
} |
|
|
|
|
|
document.querySelectorAll('.time-period-btn').forEach(btn => { |
|
btn.addEventListener('click', function() { |
|
|
|
document.querySelectorAll('.time-period-btn').forEach(b => { |
|
b.classList.remove('bg-blue-600', 'text-white'); |
|
b.classList.add('bg-blue-100', 'text-blue-700'); |
|
}); |
|
|
|
this.classList.remove('bg-blue-100', 'text-blue-700'); |
|
this.classList.add('bg-blue-600', 'text-white'); |
|
|
|
|
|
const symbol = document.getElementById('stock-symbol').value.trim().toUpperCase(); |
|
const period = this.getAttribute('data-period'); |
|
|
|
if (symbol) { |
|
updateCharts(symbol, period); |
|
} |
|
}); |
|
}); |
|
</script> |
|
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=MarcRyan/tad" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
</html> |