Bitcoin Live Price
\nCreate a single HTML file that displays a live, auto-updating Bitcoin (BTC/USDT) price chart. Requirements: - **Single file**: All HTML, CSS, and JavaScript in one file (CDN links are fine) - **Data source**: Binance WebSocket API (`wss://stream.binance.com:9443/ws/btcusdt@trade`) for real-time price data - **Charting**: Use Chart.js (or similar lightweight library via CDN) to render a clean line chart - **Live updates**: Chart should update in real-time as new trades come in (throttle updates to ~1 per second to keep it smooth) - **Minimal design**: Dark theme, clean typography, show current price prominently above the chart - **Time window**: Display the last 5 minutes of price data, with old points rolling off - **Responsive**: Should look good on both desktop and mobile - Keep it simple, elegant, and under 200 lines if possible
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Live Bitcoin Price Chart</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', -apple-system, sans-serif;
}
body {
background: #0f172a;
color: #f1f5f9;
min-height: 100vh;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.container {
max-width: 1000px;
width: 100%;
padding: 20px;
}
header {
text-align: center;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 1px solid #334155;
}
h1 {
font-size: 2.5rem;
font-weight: 700;
background: linear-gradient(90deg, #60a5fa, #3b82f6);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 10px;
}
.subtitle {
color: #94a3b8;
font-size: 1rem;
margin-bottom: 20px;
}
.price-container {
background: linear-gradient(135deg, #1e293b, #0f172a);
border: 1px solid #334155;
border-radius: 16px;
padding: 24px;
margin-bottom: 30px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
text-align: center;
}
.price-label {
color: #94a3b8;
font-size: 1.1rem;
margin-bottom: 8px;
}
.price {
font-size: 3.5rem;
font-weight: 800;
letter-spacing: -0.5px;
color: #f1f5f9;
}
.price-change {
margin-top: 8px;
font-size: 1rem;
padding: 4px 12px;
border-radius: 20px;
display: inline-block;
}
.positive {
background: rgba(34, 197, 94, 0.15);
color: #4ade80;
}
.negative {
background: rgba(239, 68, 68, 0.15);
color: #f87171;
}
.neutral {
background: rgba(100, 116, 139, 0.15);
color: #94a3b8;
}
.chart-container {
background: #1e293b;
border: 1px solid #334155;
border-radius: 16px;
padding: 20px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
position: relative;
height: 400px;
}
.status {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20px;
color: #94a3b8;
font-size: 0.9rem;
}
.status-item {
display: flex;
align-items: center;
gap: 8px;
}
.status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
}
.connected {
background: #10b981;
}
.disconnected {
background: #ef4444;
}
footer {
margin-top: 30px;
text-align: center;
color: #64748b;
font-size: 0.9rem;
padding-top: 20px;
border-top: 1px solid #334155;
width: 100%;
}
@media (max-width: 768px) {
.container {
padding: 10px;
}
h1 {
font-size: 2rem;
}
.price {
font-size: 2.5rem;
}
.chart-container {
height: 300px;
padding: 15px;
}
}
@media (max-width: 480px) {
body {
padding: 10px;
}
.price {
font-size: 2rem;
}
.chart-container {
height: 250px;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>Bitcoin Live Price</h1>
<div class="subtitle">BTC/USDT • Updates every second via Binance WebSocket</div>
</header>
<div class="price-container">
<div class="price-label">CURRENT PRICE</div>
<div class="price" id="currentPrice">Loading...</div>
<div class="price-change neutral" id="priceChange">-</div>
</div>
<div class="chart-container">
<canvas id="priceChart"></canvas>
</div>
<div class="status">
<div class="status-item">
<div class="status-dot disconnected" id="statusDot"></div>
<span id="statusText">Connecting to Binance...</span>
</div>
<div class="status-item">
<span id="lastUpdate">Last update: -</span>
</div>
</div>
</div>
<footer>
<p>Data from Binance WebSocket • Updates throttle to 1 per second • Showing last 5 minutes</p>
</footer>
<script>
// Configuration
const MAX_DATA_POINTS = 300; // 5 minutes at 1 update per second
const UPDATE_INTERVAL = 1000; // Throttle to 1 update per second
// State
let priceData = [];
let timeData = [];
let lastPrice = null;
let lastUpdateTime = null;
let chart = null;
let ws = null;
let updateThrottle = null;
let lastProcessedTradeTime = 0;
// DOM Elements
const currentPriceEl = document.getElementById('currentPrice');
const priceChangeEl = document.getElementById('priceChange');
const statusDotEl = document.getElementById('statusDot');
const statusTextEl = document.getElementById('statusText');
const lastUpdateEl = document.getElementById('lastUpdate');
// Initialize Chart.js
function initializeChart() {
const ctx = document.getElementById('priceChart').getContext('2d');
chart = new Chart(ctx, {
type: 'line',
data: {
labels: timeData,
datasets: [{
label: 'BTC/USDT',
data: priceData,
borderColor: '#3b82f6',
backgroundColor: 'rgba(59, 130, 246, 0.1)',
borderWidth: 2,
fill: true,
tension: 0.3,
pointRadius: 0,
pointHoverRadius: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
tooltip: {
mode: 'index',
intersect: false,
backgroundColor: 'rgba(15, 23, 42, 0.9)',
titleColor: '#94a3b8',
bodyColor: '#f1f5f9',
borderColor: '#334155',
borderWidth: 1,
callbacks: {
label: function(context) {
return `Price: $${context.parsed.y.toFixed(2)}`;
}
}
}
},
scales: {
x: {
grid: {
color: 'rgba(51, 65, 85, 0.5)'
},
ticks: {
color: '#94a3b8',
maxTicksLimit: 8
}
},
y: {
position: 'right',
grid: {
color: 'rgba(51, 65, 85, 0.5)'
},
ticks: {
color: '#94a3b8',
callback: function(value) {
return '$' + value.toLocaleString();
}
}
}
},
interaction: {
intersect: false,
mode: 'index'
}
}
});
}
// Update chart with new data
function updateChart(price, timestamp) {
const now = new Date(timestamp);
const timeLabel = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
// Add new data
priceData.push(price);
timeData.push(timeLabel);
// Remove old data if exceeding limit
if (priceData.length > MAX_DATA_POINTS) {
priceData.shift();
timeData.shift();
}
// Update chart
chart.data.datasets[0].data = priceData;
chart.data.labels = timeData;
chart.update('none');
// Update UI
currentPriceEl
Comments