deepsite-project / index.html
Barry8's picture
ok, now where are the pairs to choose from and also no buttons work
55dc5d7 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Binance Futures Dashboard</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/themes/classic.min.css">
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/lightweight-charts@3.8.0/dist/lightweight-charts.standalone.production.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/pickr.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<style>
.chart-container {
width: 500px;
height: 250px;
margin: 10px;
position: relative;
}
.chart-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(500px, 1fr));
gap: 10px;
padding: 20px;
}
#sidebar {
width: 300px;
position: fixed;
right: -300px;
top: 0;
height: 100%;
overflow-y: auto;
transition: right 0.5s ease;
background-color: #f8f9fa;
z-index: 1000;
padding: 20px;
box-shadow: -2px 0 5px rgba(0,0,0,0.1);
}
#sidebar.open {
right: 0;
}
#main {
transition: margin-left .5s;
}
.tooltip {
position: absolute;
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 5px;
border-radius: 3px;
pointer-events: none;
font-size: 12px;
}
.dark-mode {
background-color: #1a202c;
color: white;
}
.dark-mode .chart-container {
background-color: #2d3748;
}
</style>
</head>
<body class="bg-gray-100">
<div id="main">
<header class="bg-white shadow-sm p-4 flex justify-between items-center">
<h1 class="text-xl font-bold">Binance Futures Dashboard</h1>
<div class="flex space-x-4">
<select id="timeframe" class="p-2 border rounded">
<option value="1m">1m</option>
<option value="5m">5m</option>
<option value="15m">15m</option>
<option value="1h">1h</option>
<option value="4h">4h</option>
<option value="1d">1d</option>
<option value="1w">1w</option>
</select>
<button id="settingsBtn" class="p-2 bg-blue-500 text-white rounded">⚙️ Settings</button>
<button id="darkModeToggle" class="p-2 bg-gray-200 rounded">🌙</button>
</div>
</header>
<div class="p-4">
<div class="mb-2">
<label for="pairSelector" class="block font-medium mb-1">Select Trading Pairs:</label>
<select id="pairSelector" class="w-full p-2 border rounded" multiple="multiple"></select>
</div>
<div class="flex space-x-2">
<button id="addPairsBtn" class="flex-1 p-2 bg-green-500 text-white rounded hover:bg-green-600">Add Selected Pairs</button>
<button id="clearPairsBtn" class="flex-1 p-2 bg-red-500 text-white rounded hover:bg-red-600">Clear All</button>
</div>
</div>
<div id="chartGrid" class="chart-grid"></div>
</div>
<div id="sidebar" class="p-4">
<button id="closeSidebar" class="float-right"></button>
<h2 class="text-lg font-bold mb-4">Settings</h2>
<div class="mb-4">
<h3 class="font-bold mb-2">Display Options</h3>
<label class="flex items-center space-x-2">
<input type="checkbox" id="showPrice" class="form-checkbox">
<span>Show Price</span>
</label>
<label class="flex items-center space-x-2">
<input type="checkbox" id="showVolume" class="form-checkbox">
<span>Show 24h Volume</span>
</label>
<label class="flex items-center space-x-2">
<input type="checkbox" id="showOI" class="form-checkbox">
<span>Show Open Interest</span>
</label>
<label class="flex items-center space-x-2">
<input type="checkbox" id="showFunding" class="form-checkbox">
<span>Show Funding Rate</span>
</label>
<label class="flex items-center space-x-2">
<input type="checkbox" id="showFundingTimer" class="form-checkbox">
<span>Show Funding Timer</span>
</label>
</div>
<div class="mb-4">
<h3 class="font-bold mb-2">Chart Style</h3>
<label class="block mb-2">
<span class="block mb-1">Candle Up Color</span>
<div id="candleUpColor" class="w-full h-8 border"></div>
</label>
<label class="block mb-2">
<span class="block mb-1">Candle Down Color</span>
<div id="candleDownColor" class="w-full h-8 border"></div>
</label>
</div>
<button id="saveSettings" class="p-2 bg-blue-500 text-white rounded w-full">Save Settings</button>
</div>
<script>
// Global variables
let ws;
const charts = {};
const subscribedPairs = new Set();
let colorTheme = {
up: '#26a69a',
down: '#ef5350',
background: '#ffffff',
text: '#333333'
};
// DOM elements
const pairSelector = $('#pairSelector');
const chartGrid = document.getElementById('chartGrid');
const sidebar = document.getElementById('sidebar');
const settingsBtn = document.getElementById('settingsBtn');
const closeSidebar = document.getElementById('closeSidebar');
const darkModeToggle = document.getElementById('darkModeToggle');
const timeframeSelector = document.getElementById('timeframe');
// Initialize UI components
document.addEventListener('DOMContentLoaded', function() {
// Initialize Select2 for pair selection
$(pairSelector).select2({
placeholder: "Search and select trading pairs",
allowClear: true,
width: '100%',
closeOnSelect: false
});
// Load pairs immediately
fetchPairs();
// Initialize color pickers
const candleUpPicker = Pickr.create({
el: '#candleUpColor',
theme: 'classic',
default: colorTheme.up,
components: {
preview: true,
opacity: true,
hue: true,
interaction: {
hex: true,
rgba: true,
input: true
}
}
});
const candleDownPicker = Pickr.create({
el: '#candleDownColor',
theme: 'classic',
default: colorTheme.down,
components: {
preview: true,
opacity: true,
hue: true,
interaction: {
hex: true,
rgba: true,
input: true
}
}
});
// Event listeners
document.getElementById('addPairsBtn').addEventListener('click', function() {
console.log('Add pairs clicked');
addSelectedPairs();
});
document.getElementById('clearPairsBtn').addEventListener('click', function() {
console.log('Clear pairs clicked');
clearAllPairs();
});
settingsBtn.addEventListener('click', function() {
console.log('Settings clicked');
openSidebar();
});
closeSidebar.addEventListener('click', function() {
console.log('Close sidebar clicked');
closeSidebar();
});
document.getElementById('saveSettings').addEventListener('click', function() {
console.log('Save settings clicked');
saveSettings();
});
// Close sidebar when clicking outside
document.addEventListener('click', function(event) {
if (!sidebar.contains(event.target) && event.target !== settingsBtn) {
closeSidebar();
}
});
// Initialize WebSocket connection
initWebSocket();
// Load saved settings
loadSettings();
darkModeToggle.addEventListener('click', function() {
document.body.classList.toggle('dark-mode');
const isDarkMode = document.body.classList.contains('dark-mode');
// Update button text
darkModeToggle.textContent = isDarkMode ? '☀️' : '🌙';
// Update all charts
Object.keys(charts).forEach(pair => {
updateChartTheme(pair, isDarkMode);
});
// Save dark mode state
const settings = JSON.parse(localStorage.getItem('binanceDashboardSettings') || '{}');
settings.darkMode = isDarkMode;
localStorage.setItem('binanceDashboardSettings', JSON.stringify(settings));
});
document.getElementById('saveSettings').addEventListener('click', saveSettings);
timeframeSelector.addEventListener('change', changeTimeframe);
});
function initWebSocket() {
ws = new WebSocket('wss://fstream.binance.com/ws');
ws.onopen = () => {
console.log('WebSocket connected');
// Resubscribe to any previously subscribed pairs
subscribedPairs.forEach(pair => {
subscribeToPair(pair);
});
};
ws.onclose = () => {
console.log('WebSocket disconnected, attempting to reconnect...');
setTimeout(initWebSocket, 1000);
};
ws.onerror = (error) => {
console.error('WebSocket error:', error);
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
processWebSocketMessage(message);
};
}
function fetchPairs() {
console.log('Fetching available pairs...');
fetch('https://fapi.binance.com/fapi/v1/exchangeInfo')
.then(response => response.json())
.then(data => {
const pairs = data.symbols
.filter(symbol => symbol.status === 'TRADING')
.map(symbol => ({
id: symbol.symbol,
text: symbol.symbol
}));
console.log(`Loaded ${pairs.length} trading pairs`);
$(pairSelector).select2({
data: pairs,
placeholder: "Search and select trading pairs",
allowClear: true,
width: '100%',
closeOnSelect: false
});
})
.catch(error => {
console.error('Error fetching pairs:', error);
// Retry after 5 seconds if failed
setTimeout(fetchPairs, 5000);
});
}
function addSelectedPairs() {
const selectedPairs = pairSelector.val();
if (!selectedPairs) return;
selectedPairs.forEach(pair => {
if (!subscribedPairs.has(pair)) {
subscribedPairs.add(pair);
subscribeToPair(pair);
createChart(pair);
}
});
// Save selected pairs
const settings = JSON.parse(localStorage.getItem('binanceDashboardSettings') || '{}');
settings.selectedPairs = Array.from(subscribedPairs);
localStorage.setItem('binanceDashboardSettings', JSON.stringify(settings));
}
function clearAllPairs() {
subscribedPairs.forEach(pair => {
if (ws && ws.readyState === WebSocket.OPEN) {
const unsubscribe = {
method: "UNSUBSCRIBE",
params: [
`${pair.toLowerCase()}@kline_${timeframeSelector.value}`,
`${pair.toLowerCase()}@markPrice@1s`,
`${pair.toLowerCase()}@bookTicker`
],
id: Date.now()
};
ws.send(JSON.stringify(unsubscribe));
}
const chartElement = document.getElementById(`chart-${pair}`);
if (chartElement) {
chartElement.remove();
}
});
subscribedPairs.clear();
Object.keys(charts).forEach(pair => delete charts[pair]);
// Clear saved pairs
const settings = JSON.parse(localStorage.getItem('binanceDashboardSettings') || '{}');
settings.selectedPairs = [];
localStorage.setItem('binanceDashboardSettings', JSON.stringify(settings));
}
function subscribeToPair(pair) {
if (ws && ws.readyState === WebSocket.OPEN) {
const timeframe = timeframeSelector.value;
const subscription = {
method: "SUBSCRIBE",
params: [
`${pair.toLowerCase()}@kline_${timeframe}`,
`${pair.toLowerCase()}@markPrice@1s`,
`${pair.toLowerCase()}@bookTicker`
],
id: Date.now()
};
ws.send(JSON.stringify(subscription));
}
}
function createChart(pair) {
const container = document.createElement('div');
container.className = 'chart-container';
container.id = `chart-${pair}`;
const title = document.createElement('div');
title.className = 'font-bold mb-2';
title.id = `title-${pair}`;
title.textContent = pair;
const chartElement = document.createElement('div');
chartElement.style.width = '100%';
chartElement.style.height = '100%';
container.appendChild(title);
container.appendChild(chartElement);
chartGrid.appendChild(container);
const chart = LightweightCharts.createChart(chartElement, {
width: 500,
height: 250,
layout: {
backgroundColor: colorTheme.background,
textColor: colorTheme.text
},
grid: {
vertLines: { color: '#eee' },
horzLines: { color: '#eee' }
},
crosshair: {
mode: LightweightCharts.CrosshairMode.Normal
},
timeScale: {
timeVisible: true,
secondsVisible: false
}
});
const candleSeries = chart.addCandlestickSeries({
upColor: colorTheme.up,
downColor: colorTheme.down,
borderVisible: false,
wickUpColor: colorTheme.up,
wickDownColor: colorTheme.down
});
const volumeSeries = chart.addHistogramSeries({
color: '#26a69a',
priceFormat: {
type: 'volume'
},
priceScaleId: '',
scaleMargins: {
top: 0.8,
bottom: 0
}
});
charts[pair] = {
chart,
candleSeries,
volumeSeries,
lastUpdate: null,
data: []
};
// Fetch initial historical data
fetchInitialData(pair);
}
function fetchInitialData(pair) {
const timeframe = timeframeSelector.value;
const limit = 100;
fetch(`https://fapi.binance.com/fapi/v1/klines?symbol=${pair}&interval=${timeframe}&limit=${limit}`)
.then(response => response.json())
.then(data => {
const formattedData = data.map(item => ({
time: item[0] / 1000,
open: parseFloat(item[1]),
high: parseFloat(item[2]),
low: parseFloat(item[3]),
close: parseFloat(item[4]),
volume: parseFloat(item[5])
}));
const volumes = data.map(item => ({
time: item[0] / 1000,
value: parseFloat(item[5]),
color: parseFloat(item[4]) >= parseFloat(item[1]) ? colorTheme.up : colorTheme.down
}));
if (charts[pair]) {
charts[pair].candleSeries.setData(formattedData);
charts[pair].volumeSeries.setData(volumes);
charts[pair].data = formattedData;
}
})
.catch(error => console.error(`Error fetching initial data for ${pair}:`, error));
}
function processWebSocketMessage(message) {
if (message.e === 'kline') {
const pair = message.s;
const kline = message.k;
if (charts[pair]) {
const newCandle = {
time: kline.t / 1000,
open: parseFloat(kline.o),
high: parseFloat(kline.h),
low: parseFloat(kline.l),
close: parseFloat(kline.c),
volume: parseFloat(kline.v)
};
// Update or add candle
if (kline.x) {
// Closed candle
charts[pair].data.push(newCandle);
if (charts[pair].data.length > 100) {
charts[pair].data.shift();
}
charts[pair].candleSeries.update(newCandle);
} else {
// Update current candle
charts[pair].candleSeries.update(newCandle);
}
// Update volume
const newVolume = {
time: kline.t / 1000,
value: parseFloat(kline.v),
color: parseFloat(kline.c) >= parseFloat(kline.o) ? colorTheme.up : colorTheme.down
};
charts[pair].volumeSeries.update(newVolume);
}
}
// Handle other message types (mark price, book ticker, etc.)
}
function changeTimeframe() {
const timeframe = timeframeSelector.value;
subscribedPairs.forEach(pair => {
// Unsubscribe from old streams
if (ws && ws.readyState === WebSocket.OPEN) {
const unsubscribe = {
method: "UNSUBSCRIBE",
params: [
`${pair.toLowerCase()}@kline_${timeframe}`,
`${pair.toLowerCase()}@markPrice@1s`,
`${pair.toLowerCase()}@bookTicker`
],
id: Date.now()
};
ws.send(JSON.stringify(unsubscribe));
}
// Subscribe to new streams
subscribeToPair(pair);
// Refresh chart data
if (charts[pair]) {
fetchInitialData(pair);
}
});
}
function openSidebar() {
sidebar.classList.add('open');
}
function closeSidebar() {
sidebar.classList.remove('open');
}
function updateChartTheme(pair, isDarkMode) {
charts[pair].chart.applyOptions({
layout: {
backgroundColor: isDarkMode ? '#2d3748' : '#ffffff',
textColor: isDarkMode ? '#ffffff' : '#333333'
},
grid: {
vertLines: { color: isDarkMode ? '#4a5568' : '#eee' },
horzLines: { color: isDarkMode ? '#4a5568' : '#eee' }
}
});
}
function saveSettings() {
try {
const settings = {
showPrice: document.getElementById('showPrice').checked,
showVolume: document.getElementById('showVolume').checked,
showOI: document.getElementById('showOI').checked,
showFunding: document.getElementById('showFunding').checked,
showFundingTimer: document.getElementById('showFundingTimer').checked,
darkMode: document.body.classList.contains('dark-mode'),
selectedPairs: Array.from(subscribedPairs),
timeframe: document.getElementById('timeframe').value
};
localStorage.setItem('binanceDashboardSettings', JSON.stringify(settings));
console.log('Settings saved successfully');
closeSidebar();
} catch (error) {
console.error('Error saving settings:', error);
}
}
function loadSettings() {
const savedSettings = localStorage.getItem('binanceDashboardSettings');
if (savedSettings) {
const settings = JSON.parse(savedSettings);
document.getElementById('showPrice').checked = settings.showPrice;
document.getElementById('showVolume').checked = settings.showVolume;
document.getElementById('showOI').checked = settings.showOI;
document.getElementById('showFunding').checked = settings.showFunding;
document.getElementById('showFundingTimer').checked = settings.showFundingTimer;
if (settings.darkMode) {
document.body.classList.add('dark-mode');
}
if (settings.selectedPairs && settings.selectedPairs.length > 0) {
settings.selectedPairs.forEach(pair => {
subscribedPairs.add(pair);
createChart(pair);
});
}
if (settings.timeframe) {
timeframeSelector.value = settings.timeframe;
}
}
}
</script>
</body>
</html>