bingx-monitoring / index.html
EricSam's picture
Update index.html
a711575 verified
raw
history blame
27.5 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nakhoda4X Pro - Portfolio Dashboard</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
primary: '#2563eb',
secondary: '#8b5cf6',
darkBg: '#111827',
darkCard: '#1f2937',
}
}
}
}
</script>
<style>
.trading-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
}
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.coin-animation {
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
100% { transform: translateY(0px); }
}
</style>
</head>
<body class="bg-gray-100 dark:bg-darkBg transition-colors duration-300">
<!-- Header -->
<header class="bg-white dark:bg-darkCard shadow-sm">
<div class="container mx-auto px-4 py-4 flex justify-between items-center">
<div class="flex items-center">
<div class="bg-primary w-10 h-10 rounded-xl flex items-center justify-center mr-3 coin-animation">
<i class="fas fa-chart-line text-white text-xl"></i>
</div>
<h1 class="text-2xl font-bold text-gray-800 dark:text-white">Nakhoda4X <span class="text-primary">Pro</span></h1>
</div>
<div class="flex items-center space-x-6">
<button id="theme-toggle" class="text-gray-600 dark:text-gray-300">
<i class="fas fa-moon dark:hidden"></i>
<i class="fas fa-sun hidden dark:block"></i>
</button>
<div class="relative">
<i class="fas fa-bell text-gray-600 dark:text-gray-300 text-xl"></i>
<span class="absolute -top-2 -right-2 bg-red-500 text-white text-xs rounded-full h-5 w-5 flex items-center justify-center">3</span>
</div>
<div class="flex items-center">
<div class="mr-3 text-right">
<p class="font-semibold text-gray-800 dark:text-white">SahabatPipHijau</p>
<p class="text-sm text-gray-500">Premium Account</p>
</div>
<div class="h-10 w-10 rounded-full bg-gradient-to-r from-primary to-secondary flex items-center justify-center text-white font-bold">
J
</div>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<main class="container mx-auto px-4 py-8">
<!-- Dashboard Header -->
<div class="flex justify-between items-center mb-8">
<div>
<h2 class="text-3xl font-bold text-gray-800 dark:text-white">Trading Dashboard</h2>
<p class="text-gray-500 mt-1 dark:text-gray-400">Connected to BingX via API</p>
</div>
<div class="flex space-x-4">
<button id="refresh-btn" class="px-4 py-2 bg-white dark:bg-darkCard rounded-lg border border-gray-200 dark:border-gray-700 text-gray-700 dark:text-gray-300 flex items-center">
<i class="fas fa-sync mr-2"></i> Refresh
</button>
<button class="px-4 py-2 bg-primary text-white rounded-lg flex items-center">
<i class="fas fa-plus mr-2"></i> New Trade
</button>
</div>
</div>
<!-- Stats Cards -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<div class="trading-card bg-white dark:bg-darkCard rounded-2xl shadow-md p-6 transition-all duration-300">
<div class="flex justify-between">
<div>
<p class="text-gray-500 dark:text-gray-400">Total Balance</p>
<h3 id="total-balance" class="text-2xl font-bold mt-2 dark:text-white">$0.00</h3>
</div>
<div class="w-12 h-12 rounded-xl bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center">
<i class="fas fa-wallet text-blue-500 text-xl"></i>
</div>
</div>
<div id="balance-change" class="mt-4 flex items-center text-green-500">
<i class="fas fa-caret-up mr-1"></i>
<span class="font-medium">0.0%</span>
<span class="text-gray-500 ml-2 dark:text-gray-400">last 24h</span>
</div>
</div>
<div class="trading-card bg-white dark:bg-darkCard rounded-2xl shadow-md p-6 transition-all duration-300">
<div class="flex justify-between">
<div>
<p class="text-gray-500 dark:text-gray-400">Open Trades</p>
<h3 id="open-trades" class="text-2xl font-bold mt-2 dark:text-white">0</h3>
</div>
<div class="w-12 h-12 rounded-xl bg-purple-100 dark:bg-purple-900/30 flex items-center justify-center">
<i class="fas fa-exchange-alt text-purple-500 text-xl"></i>
</div>
</div>
<div id="trade-types" class="mt-4 flex items-center text-blue-500">
<span class="font-medium">0 Long</span>
<span class="text-gray-500 mx-2 dark:text-gray-400">β€’</span>
<span class="font-medium">0 Short</span>
</div>
</div>
<div class="trading-card bg-white dark:bg-darkCard rounded-2xl shadow-md p-6 transition-all duration-300">
<div class="flex justify-between">
<div>
<p class="text-gray-500 dark:text-gray-400">Today's Profit</p>
<h3 id="today-profit" class="text-2xl font-bold mt-2 dark:text-white">$0.00</h3>
</div>
<div class="w-12 h-12 rounded-xl bg-green-100 dark:bg-green-900/30 flex items-center justify-center">
<i class="fas fa-chart-bar text-green-500 text-xl"></i>
</div>
</div>
<div id="profit-change" class="mt-4 flex items-center text-green-500">
<i class="fas fa-caret-up mr-1"></i>
<span class="font-medium">0.0%</span>
<span class="text-gray-500 ml-2 dark:text-gray-400">vs yesterday</span>
</div>
</div>
<div class="trading-card bg-white dark:bg-darkCard rounded-2xl shadow-md p-6 transition-all duration-300">
<div class="flex justify-between">
<div>
<p class="text-gray-500 dark:text-gray-400">Risk Exposure</p>
<h3 id="risk-exposure" class="text-2xl font-bold mt-2 dark:text-white">Low</h3>
</div>
<div class="w-12 h-12 rounded-xl bg-yellow-100 dark:bg-yellow-900/30 flex items-center justify-center">
<i class="fas fa-exclamation-triangle text-yellow-500 text-xl"></i>
</div>
</div>
<div id="exposure-percent" class="mt-4 flex items-center text-gray-500 dark:text-gray-400">
<span class="font-medium">0%</span>
<span class="ml-2">of balance</span>
</div>
</div>
</div>
<!-- Charts and Statistics Section -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8">
<div class="lg:col-span-2 bg-white dark:bg-darkCard rounded-2xl shadow-md p-6">
<div class="flex justify-between items-center mb-6">
<h3 class="text-lg font-bold text-gray-800 dark:text-white">Monthly Performance</h3>
<div class="flex space-x-3">
<button class="px-3 py-1 rounded-lg text-sm bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-white">1M</button>
<button class="px-3 py-1 rounded-lg text-sm bg-primary text-white">3M</button>
<button class="px-3 py-1 rounded-lg text-sm bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-white">6M</button>
<button class="px-3 py-1 rounded-lg text-sm bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-white">1Y</button>
</div>
</div>
<canvas id="performanceChart"></canvas>
</div>
<div class="bg-white dark:bg-darkCard rounded-2xl shadow-md p-6">
<h3 class="text-lg font-bold text-gray-800 dark:text-white mb-6">Advanced Statistics</h3>
<div id="advanced-stats" class="space-y-5">
<!-- Dynamically populated -->
</div>
</div>
</div>
<!-- Trading Activity -->
<div class="bg-white dark:bg-darkCard rounded-2xl shadow-md p-6 mb-8">
<div class="flex justify-between items-center mb-6">
<h3 class="text-lg font-bold text-gray-800 dark:text-white">Trading Activity</h3>
<div class="flex space-x-3">
<button class="px-3 py-1 rounded-lg text-sm bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-white">All</button>
<button class="px-3 py-1 rounded-lg text-sm bg-primary text-white">Open</button>
<button class="px-3 py-1 rounded-lg text-sm bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-white">Closed</button>
</div>
</div>
<div class="overflow-x-auto">
<table class="w-full">
<thead>
<tr class="text-left text-gray-500 dark:text-gray-400 text-sm">
<th class="pb-4">Symbol</th>
<th class="pb-4">Type</th>
<th class="pb-4">Size</th>
<th class="pb-4">Entry Price</th>
<th class="pb-4">Current Price</th>
<th class="pb-4">Profit/Loss</th>
<th class="pb-4">Status</th>
<th class="pb-4"></th>
</tr>
</thead>
<tbody id="trading-table-body" class="text-sm">
<!-- Dynamically populated -->
</tbody>
</table>
</div>
</div>
<!-- API Connection Section -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div class="bg-gradient-to-r from-primary to-secondary rounded-2xl p-6">
<div class="flex items-center">
<div class="mr-4">
<div class="h-12 w-12 rounded-xl bg-white/30 flex items-center justify-center">
<i class="fas fa-plug text-white text-xl"></i>
</div>
</div>
<div>
<h3 class="text-lg font-bold text-white">BingX API Connected</h3>
<p id="last-sync" class="text-blue-100">Last synced: Just now</p>
</div>
</div>
<button id="sync-now" class="mt-6 w-full py-3 bg-white rounded-xl text-primary font-bold flex items-center justify-center">
<i class="fas fa-sync mr-2"></i> Sync Now
</button>
</div>
<div class="lg:col-span-2 bg-white dark:bg-darkCard rounded-2xl shadow-md p-6">
<div class="flex justify-between items-center mb-6">
<h3 class="text-lg font-bold text-gray-800 dark:text-white">Portfolio Allocation</h3>
<div>
<span id="allocation-update" class="text-gray-500 dark:text-gray-400 text-sm">Last updated: Just now</span>
</div>
</div>
<div class="flex items-center">
<div class="w-40 h-40 mr-8">
<canvas id="allocationChart"></canvas>
</div>
<div id="allocation-legend" class="flex-grow">
<!-- Dynamically populated -->
</div>
</div>
</div>
</div>
</main>
<script>
// Dark Mode Toggle
const themeToggle = document.getElementById('theme-toggle');
themeToggle.addEventListener('click', () => {
document.documentElement.classList.toggle('dark');
});
// Chart Initialization
const performanceCtx = document.getElementById('performanceChart').getContext('2d');
const performanceChart = new Chart(performanceCtx, {
type: 'line',
data: {
labels: [],
datasets: [{
label: 'Profit/Loss',
data: [],
borderColor: '#3b82f6',
backgroundColor: 'rgba(59, 130, 246, 0.1)',
tension: 0.4,
fill: true
}]
},
options: {
responsive: true,
plugins: { legend: { display: false } },
scales: {
y: { grid: { color: 'rgba(0, 0, 0, 0 βŽ›05)', borderDash: [5] }, ticks: { callback: value => '$' + value } },
x: { grid: { display: false } }
}
}
});
const allocationCtx = document.getElementById('allocationChart').getContext('2d');
const allocationChart = new Chart(allocationCtx, {
type: 'doughnut',
data: {
labels: [],
datasets: [{
data: [],
backgroundColor: ['#3b82f6', '#10b981', '#8b5cf6', '#f59e0b'],
borderWidth: 0
}]
},
options: {
responsive: true,
cutout: '65%',
plugins: { legend: { display: false }, tooltip: { callbacks: { label: context => `${context.label}: ${context.parsed}%` } } }
}
});
// API Configuration (Replace with your actual keys in a secure manner)
const API_KEY = 'EXW9448ytbIhsoaEIqomKqVziRmWCAZ88OhLKmyMoPb7jFTtDnWjO1DFATt3sizsKi2hgn7SxQ06ALTDmU9w';
const API_SECRET = 'PCEzaYObtvi1DB3fmQy3XfFGl9ybRlFI6eVjpjSWykE1mJQ5mEDYlPsuJJ9mXfr2wjaxprMKzBCeitcY7xGdKQ';
const API_BASE_URL = 'https://api.bingx.com';
// Generate Signature for Authentication
function generateSignature(params) {
const queryString = new URLSearchParams(params).toString();
return CryptoJS.HmacSHA256(queryString, API_SECRET).toString(CryptoJS.enc.Hex);
}
// Generic API Fetch Function
async function fetchFromAPI(endpoint, params = {}) {
params.timestamp = Date.now();
params.signature = generateSignature(params);
const url = `${API_BASE_URL}${endpoint}?${new URLSearchParams(params)}`;
const response = await fetch(url, {
method: 'GET',
headers: { 'X-BX-APIKEY': API_KEY }
});
if (!response.ok) throw new Error(`API Error: ${response.statusText}`);
return response.json();
}
// Fetch Specific Data
async function fetchBalance() {
const data = await fetchFromAPI('/api/v1/account/balance');
return data.data.balance; // Adjust based on actual API response structure
}
async function fetchOpenPositions() {
const data = await fetchFromAPI('/api/v1/positions');
return data.data.positions; // Adjust based on actual API response structure
}
async function fetchTradeHistory() {
const data = await fetchFromAPI('/api/v1/trades', { limit: 100 });
return data.data.trades; // Adjust based on actual API response structure
}
// Helper Functions
function calculateTodayProfit(trades) {
const today = new Date().toDateString();
return trades
.filter(trade => new Date(trade.closeTime).toDateString() === today)
.reduce((sum, trade) => sum + (trade.realizedProfit || 0), 0);
}
function calculateAdvancedStats(trades) {
let totalProfit = 0, totalLoss = 0, wins = 0;
trades.forEach(trade => {
const pl = trade.realizedProfit || 0;
if (pl > 0) { totalProfit += pl; wins++; }
else { totalLoss += Math.abs(pl); }
});
const profitFactor = totalLoss ? (totalProfit / totalLoss) : 0;
const winRate = trades.length ? (wins / trades.length * 100) : 0;
return { profitFactor: profitFactor.toFixed(2), winRate: winRate.toFixed(1) };
}
function calculatePortfolioAllocation(positions) {
const totalValue = positions.reduce((sum, pos) => sum + (pos.value || 0), 0);
const bySymbol = positions.reduce((acc, pos) => {
acc[pos.symbol] = (acc[pos.symbol] || 0) + (pos.value || 0);
return acc;
}, {});
return {
labels: Object.keys(bySymbol),
data: Object.values(bySymbol).map(val => totalValue ? (val / totalValue * 100) : 0)
};
}
// Update UI Functions
function updateTradingTable(positions, trades) {
const tbody = document.getElementById('trading-table-body');
tbody.innerHTML = '';
positions.forEach(pos => {
tbody.innerHTML += `
<tr class="border-b border-gray-200 dark:border-gray-700">
<td class="py-4">${pos.symbol}</td>
<td class="py-4"><span class="${pos.side === 'Long' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'} px-2 py-1 rounded">${pos.side}</span></td>
<td class="py-4">${pos.size}</td>
<td class="py-4">$${pos.entryPrice.toFixed(2)}</td>
<td class="py-4 font-medium">$${pos.currentPrice.toFixed(2)}</td>
<td class="py-4 font-bold ${pos.unrealizedPL > 0 ? 'text-green-500' : 'text-red-500'}">$${pos.unrealizedPL.toFixed(2)}</td>
<td class="py-4"><span class="px-2 py-1 rounded bg-blue-100 text-blue-800">Open</span></td>
<td class="py-4 text-right"><button class="text-gray-400 hover:text-primary"><i class="fas fa-ellipsis-v"></i></button></td>
</tr>`;
});
trades.slice(0, 5).forEach(trade => {
tbody.innerHTML += `
<tr class="border-b border-gray-200 dark:border-gray-700">
<td class="py-4">${trade.symbol}</td>
<td class="py-4"><span class="${trade.side === 'Long' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'} px-2 py-1 rounded">${trade.side}</span></td>
<td class="py-4">${trade.size}</td>
<td class="py-4">$${trade.entryPrice.toFixed(2)}</td>
<td class="py-4 font-medium">$${trade.exitPrice.toFixed(2)}</td>
<td class="py-4 font-bold ${trade.realizedProfit > 0 ? 'text-green-500' : 'text-red-500'}">$${trade.realizedProfit.toFixed(2)}</td>
<td class="py-4"><span class="px-2 py-1 rounded bg-gray-100 text-gray-800">Closed</span></td>
<td class="py-4 text-right"><button class="text-gray-400 hover:text-primary"><i class="fas fa-ellipsis-v"></i></button></td>
</tr>`;
});
}
function updateAdvancedStats(stats) {
document.getElementById('advanced-stats').innerHTML = `
<div>
<div class="flex justify-between mb-1">
<span class="text-gray-500 dark:text-gray-400">Profit Factor</span>
<span class="font-bold text-green-500">${stats.profitFactor}</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2 dark:bg-gray-700">
<div class="bg-green-600 h-2 rounded-full" style="width: ${Math.min(stats.profitFactor * 25, 100)}%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span class="text-gray-500 dark:text-gray-400">Win Rate</span>
<span class="font-bold text-purple-500">${stats.winRate}%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2 dark:bg-gray-700">
<div class="bg-purple-600 h-2 rounded-full" style="width: ${stats.winRate}%"></div>
</div>
</div>`;
}
function updatePerformanceChart(trades) {
const monthlyPL = trades.reduce((acc, trade) => {
const month = new Date(trade.closeTime).toLocaleString('default', { month: 'short' });
acc[month] = (acc[month] || 0) + (trade.realizedProfit || 0);
return acc;
}, {});
performanceChart.data.labels = Object.keys(monthlyPL);
performanceChart.data.datasets[0].data = Object.values(monthlyPL);
performanceChart.update();
}
function updateAllocationChart(allocation) {
allocationChart.data.labels = allocation.labels;
allocationChart.data.datasets[0].data = allocation.data;
allocationChart.update();
const legend = document.getElementById('allocation-legend');
legend.innerHTML = allocation.labels.map((label, i) => `
<div class="mb-3">
<div class="flex justify-between mb-1">
<span class="text-gray-500 dark:text-gray-400 flex items-center">
<span class="h-3 w-3 bg-[${allocationChart.data.datasets[0].backgroundColor[i]}] rounded-full mr-2"></span>
${label}
</span>
<span class="font-medium dark:text-white">${allocation.data[i].toFixed(1)}%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2 dark:bg-gray-700">
<div class="bg-[${allocationChart.data.datasets[0].backgroundColor[i]}] h-2 rounded-full" style="width: ${allocation.data[i]}%"></div>
</div>
</div>`).join('');
}
// Main Data Fetch Function
async function fetchData() {
try {
// Show loading state
document.querySelectorAll('.trading-card h3').forEach(el => el.textContent = 'Loading...');
document.getElementById('trading-table-body').innerHTML = '<tr><td colspan="8" class="py-4 text-center">Loading...</td></tr>';
const [balance, positions, trades] = await Promise.all([
fetchBalance(),
fetchOpenPositions(),
fetchTradeHistory()
]);
// Update Stats Cards
document.getElementById('total-balance').textContent = `$${balance.toFixed(2)}`;
document.getElementById('open-trades').textContent = positions.length;
const longCount = positions.filter(p => p.side === 'Long').length;
document.getElementById('trade-types').innerHTML = `<span class="font-medium">${longCount} Long</span><span class="text-gray-500 mx-2 dark:text-gray-400">β€’</span><span class="font-medium">${positions.length - longCount} Short</span>`;
const todayProfit = calculateTodayProfit(trades);
document.getElementById('today-profit').textContent = `$${todayProfit.toFixed(2)}`;
const riskPercent = balance ? (positions.reduce((sum, p) => sum + (p.value || 0), 0) / balance * 100) : 0;
document.getElementById('risk-exposure').textContent = riskPercent < 20 ? 'Low' : riskPercent < 50 ? 'Medium' : 'High';
document.getElementById('exposure-percent').innerHTML = `<span class="font-medium">${riskPercent.toFixed(1)}%</span><span class="ml-2">of balance</span>`;
// Update Other Sections
updateTradingTable(positions, trades);
const stats = calculateAdvancedStats(trades);
updateAdvancedStats(stats);
updatePerformanceChart(trades);
const allocation = calculatePortfolioAllocation(positions);
updateAllocationChart(allocation);
// Update sync time
document.getElementById('last-sync').textContent = 'Last synced: Just now';
document.getElementById('allocation-update').textContent = 'Last updated: Just now';
} catch (error) {
console.error('Error fetching data:', error);
alert('Failed to sync with BingX API. Please check your API credentials.');
}
}
// Event Listeners
document.getElementById('refresh-btn').addEventListener('click', fetchData);
document.getElementById('sync-now').addEventListener('click', fetchData);
window.addEventListener('load', fetchData);
setInterval(fetchData, 60000); // Refresh every 60 seconds
</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=EricSam/bingx-monitoring" style="color: #fff; text-decoration: underline;" target="_blank">Remix</a></p>
</body>
</html>