Spaces:
Runtime error
Runtime error
Update index.html
Browse files- index.html +43 -42
index.html
CHANGED
@@ -267,39 +267,39 @@
|
|
267 |
|
268 |
// Generate Signature
|
269 |
function generateSignature(params) {
|
270 |
-
|
271 |
-
|
272 |
-
params.recvWindow = 5000; // Optional, check BingX docs
|
273 |
-
const queryString = new URLSearchParams(params).toString();
|
274 |
return CryptoJS.HmacSHA256(queryString, API_SECRET).toString(CryptoJS.enc.Hex);
|
275 |
}
|
276 |
|
277 |
// Fetch from API
|
278 |
async function fetchFromAPI(endpoint, params = {}) {
|
279 |
-
params.timestamp = Date.now();
|
280 |
-
params.
|
281 |
-
|
282 |
-
|
283 |
-
const
|
284 |
-
|
285 |
-
|
|
|
|
|
286 |
return response.json();
|
287 |
}
|
288 |
|
289 |
// Fetch Specific Data
|
290 |
async function fetchBalance() {
|
291 |
-
const data = await fetchFromAPI('/openApi/
|
292 |
-
return data.data.
|
293 |
}
|
294 |
|
295 |
async function fetchOpenPositions() {
|
296 |
-
const data = await fetchFromAPI('/openApi/
|
297 |
-
return data.data; // Adjust based on actual response structure
|
298 |
}
|
299 |
|
300 |
async function fetchTradeHistory() {
|
301 |
-
const data = await fetchFromAPI('/openApi/
|
302 |
-
return data.data; // Adjust based on actual response structure
|
303 |
}
|
304 |
|
305 |
// Helper Functions
|
@@ -336,12 +336,12 @@
|
|
336 |
positions.forEach(pos => {
|
337 |
tbody.innerHTML += `
|
338 |
<tr class="border-b border-gray-200 dark:border-gray-700">
|
339 |
-
<td class="py-4">${pos.symbol}</td>
|
340 |
-
<td class="py-4"><span class="${pos.side === '
|
341 |
-
<td class="py-4">${pos.quantity}</td>
|
342 |
-
<td class="py-4">$${pos.entryPrice.toFixed(2)}</td>
|
343 |
-
<td class="py-4 font-medium">$${pos.markPrice.toFixed(2)}</td>
|
344 |
-
<td class="py-4 font-bold ${pos.unrealizedProfit > 0 ? 'text-green-500' : 'text-red-500'}">$${pos.unrealizedProfit.toFixed(2)}</td>
|
345 |
<td class="py-4"><span class="px-2 py-1 rounded bg-blue-100 text-blue-800">Open</span></td>
|
346 |
<td class="py-4 text-right"><button class="text-gray-400 hover:text-primary"><i class="fas fa-ellipsis-v"></i></button></td>
|
347 |
</tr>`;
|
@@ -349,12 +349,12 @@
|
|
349 |
trades.slice(0, 5).forEach(trade => {
|
350 |
tbody.innerHTML += `
|
351 |
<tr class="border-b border-gray-200 dark:border-gray-700">
|
352 |
-
<td class="py-4">${trade.symbol}</td>
|
353 |
-
<td class="py-4"><span class="${trade.side === '
|
354 |
-
<td class="py-4">${trade.quantity}</td>
|
355 |
-
<td class="py-4">$${trade.entryPrice.toFixed(2)}</td>
|
356 |
-
<td class="py-4 font-medium">$${trade.exitPrice.toFixed(2)}</td>
|
357 |
-
<td class="py-4 font-bold ${trade.realizedProfit > 0 ? 'text-green-500' : 'text-red-500'}">$${trade.realizedProfit.toFixed(2)}</td>
|
358 |
<td class="py-4"><span class="px-2 py-1 rounded bg-gray-100 text-gray-800">Closed</span></td>
|
359 |
<td class="py-4 text-right"><button class="text-gray-400 hover:text-primary"><i class="fas fa-ellipsis-v"></i></button></td>
|
360 |
</tr>`;
|
@@ -375,7 +375,7 @@
|
|
375 |
|
376 |
function updatePerformanceChart(trades) {
|
377 |
const monthlyPL = trades.reduce((acc, trade) => {
|
378 |
-
const month = new Date(trade.closeTime).toLocaleString('default', { month: 'short' });
|
379 |
acc[month] = (acc[month] || 0) + (trade.realizedProfit || 0);
|
380 |
return acc;
|
381 |
}, {});
|
@@ -385,21 +385,21 @@
|
|
385 |
}
|
386 |
|
387 |
function updateAllocationChart(allocation) {
|
388 |
-
allocationChart.data.labels = allocation.labels;
|
389 |
-
allocationChart.data.datasets[0].data = allocation.data;
|
390 |
allocationChart.update();
|
391 |
const legend = document.getElementById('allocation-legend');
|
392 |
legend.innerHTML = allocation.labels.map((label, i) => `
|
393 |
<div class="mb-3">
|
394 |
<div class="flex justify-between mb-1">
|
395 |
<span class="text-gray-500 dark:text-gray-400 flex items-center">
|
396 |
-
<span class="h-3 w-3 bg-[${allocationChart.data.datasets[0].backgroundColor[i]}] rounded-full mr-2"></span>
|
397 |
-
${label}
|
398 |
</span>
|
399 |
-
<span class="font-medium dark:text-white">${allocation.data[i].toFixed(1)}%</span>
|
400 |
</div>
|
401 |
<div class="w-full bg-gray-200 rounded-full h-2 dark:bg-gray-700">
|
402 |
-
<div class="bg-[${allocationChart.data.datasets[0].backgroundColor[i]}] h-2 rounded-full" style="width: ${allocation.data[i]}%"></div>
|
403 |
</div>
|
404 |
</div>`).join('');
|
405 |
}
|
@@ -416,9 +416,9 @@
|
|
416 |
fetchTradeHistory()
|
417 |
]);
|
418 |
|
419 |
-
document.getElementById('total-balance').textContent = `$${balance.toFixed(2)}`;
|
420 |
document.getElementById('open-trades').textContent = positions.length;
|
421 |
-
const longCount = positions.filter(p => p.side === '
|
422 |
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>`;
|
423 |
const todayProfit = calculateTodayProfit(trades);
|
424 |
document.getElementById('today-profit').textContent = `$${todayProfit.toFixed(2)}`;
|
@@ -433,11 +433,12 @@
|
|
433 |
const allocation = calculatePortfolioAllocation(positions);
|
434 |
updateAllocationChart(allocation);
|
435 |
|
436 |
-
|
437 |
-
document.getElementById('
|
|
|
438 |
} catch (error) {
|
439 |
console.error('Error fetching data:', error);
|
440 |
-
alert(
|
441 |
}
|
442 |
}
|
443 |
|
@@ -445,7 +446,7 @@
|
|
445 |
document.getElementById('refresh-btn').addEventListener('click', fetchData);
|
446 |
document.getElementById('sync-now').addEventListener('click', fetchData);
|
447 |
window.addEventListener('load', fetchData);
|
448 |
-
setInterval(fetchData, 120000); //
|
449 |
</script>
|
450 |
<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>
|
451 |
</body>
|
|
|
267 |
|
268 |
// Generate Signature
|
269 |
function generateSignature(params) {
|
270 |
+
const sortedParams = Object.fromEntries(Object.entries(params).sort());
|
271 |
+
const queryString = new URLSearchParams(sortedParams).toString();
|
|
|
|
|
272 |
return CryptoJS.HmacSHA256(queryString, API_SECRET).toString(CryptoJS.enc.Hex);
|
273 |
}
|
274 |
|
275 |
// Fetch from API
|
276 |
async function fetchFromAPI(endpoint, params = {}) {
|
277 |
+
params.timestamp = Date.now().toString();
|
278 |
+
params.recvWindow = '5000'; // 5-second window, per BingX requirements
|
279 |
+
const signature = generateSignature(params);
|
280 |
+
const url = `${API_BASE_URL}${endpoint}?${new URLSearchParams({ ...params, signature })}`;
|
281 |
+
const response = await fetch(url, {
|
282 |
+
method: 'GET',
|
283 |
+
headers: { 'X-BX-APIKEY': API_KEY }
|
284 |
+
});
|
285 |
+
if (!response.ok) throw new Error(`API Error: ${response.status} - ${await response.text()}`);
|
286 |
return response.json();
|
287 |
}
|
288 |
|
289 |
// Fetch Specific Data
|
290 |
async function fetchBalance() {
|
291 |
+
const data = await fetchFromAPI('/openApi/swap/v2/account/balance');
|
292 |
+
return data.data.find(b => b.asset === 'USDT')?.balance || 0; // Adjust based on actual response
|
293 |
}
|
294 |
|
295 |
async function fetchOpenPositions() {
|
296 |
+
const data = await fetchFromAPI('/openApi/swap/v2/position');
|
297 |
+
return data.data || []; // Adjust based on actual response structure
|
298 |
}
|
299 |
|
300 |
async function fetchTradeHistory() {
|
301 |
+
const data = await fetchFromAPI('/openApi/swap/v2/trade/history', { limit: 100 });
|
302 |
+
return data.data || []; // Adjust based on actual response structure
|
303 |
}
|
304 |
|
305 |
// Helper Functions
|
|
|
336 |
positions.forEach(pos => {
|
337 |
tbody.innerHTML += `
|
338 |
<tr class="border-b border-gray-200 dark:border-gray-700">
|
339 |
+
<td class="py-4">${pos.symbol || 'N/A'}</td>
|
340 |
+
<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 || 'N/A'}</span></td>
|
341 |
+
<td class="py-4">${pos.quantity || 0}</td>
|
342 |
+
<td class="py-4">$${parseFloat(pos.entryPrice || 0).toFixed(2)}</td>
|
343 |
+
<td class="py-4 font-medium">$${parseFloat(pos.markPrice || 0).toFixed(2)}</td>
|
344 |
+
<td class="py-4 font-bold ${parseFloat(pos.unrealizedProfit || 0) > 0 ? 'text-green-500' : 'text-red-500'}">$${parseFloat(pos.unrealizedProfit || 0).toFixed(2)}</td>
|
345 |
<td class="py-4"><span class="px-2 py-1 rounded bg-blue-100 text-blue-800">Open</span></td>
|
346 |
<td class="py-4 text-right"><button class="text-gray-400 hover:text-primary"><i class="fas fa-ellipsis-v"></i></button></td>
|
347 |
</tr>`;
|
|
|
349 |
trades.slice(0, 5).forEach(trade => {
|
350 |
tbody.innerHTML += `
|
351 |
<tr class="border-b border-gray-200 dark:border-gray-700">
|
352 |
+
<td class="py-4">${trade.symbol || 'N/A'}</td>
|
353 |
+
<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 || 'N/A'}</span></td>
|
354 |
+
<td class="py-4">${trade.quantity || 0}</td>
|
355 |
+
<td class="py-4">$${parseFloat(trade.entryPrice || 0).toFixed(2)}</td>
|
356 |
+
<td class="py-4 font-medium">$${parseFloat(trade.exitPrice || 0).toFixed(2)}</td>
|
357 |
+
<td class="py-4 font-bold ${parseFloat(trade.realizedProfit || 0) > 0 ? 'text-green-500' : 'text-red-500'}">$${parseFloat(trade.realizedProfit || 0).toFixed(2)}</td>
|
358 |
<td class="py-4"><span class="px-2 py-1 rounded bg-gray-100 text-gray-800">Closed</span></td>
|
359 |
<td class="py-4 text-right"><button class="text-gray-400 hover:text-primary"><i class="fas fa-ellipsis-v"></i></button></td>
|
360 |
</tr>`;
|
|
|
375 |
|
376 |
function updatePerformanceChart(trades) {
|
377 |
const monthlyPL = trades.reduce((acc, trade) => {
|
378 |
+
const month = new Date(trade.closeTime || Date.now()).toLocaleString('default', { month: 'short' });
|
379 |
acc[month] = (acc[month] || 0) + (trade.realizedProfit || 0);
|
380 |
return acc;
|
381 |
}, {});
|
|
|
385 |
}
|
386 |
|
387 |
function updateAllocationChart(allocation) {
|
388 |
+
allocationChart.data.labels = allocation.labels.length ? allocation.labels : ['No Data'];
|
389 |
+
allocationChart.data.datasets[0].data = allocation.data.length ? allocation.data : [100];
|
390 |
allocationChart.update();
|
391 |
const legend = document.getElementById('allocation-legend');
|
392 |
legend.innerHTML = allocation.labels.map((label, i) => `
|
393 |
<div class="mb-3">
|
394 |
<div class="flex justify-between mb-1">
|
395 |
<span class="text-gray-500 dark:text-gray-400 flex items-center">
|
396 |
+
<span class="h-3 w-3 bg-[${allocationChart.data.datasets[0].backgroundColor[i % 4]}] rounded-full mr-2"></span>
|
397 |
+
${label || 'N/A'}
|
398 |
</span>
|
399 |
+
<span class="font-medium dark:text-white">${allocation.data[i] ? allocation.data[i].toFixed(1) : 0}%</span>
|
400 |
</div>
|
401 |
<div class="w-full bg-gray-200 rounded-full h-2 dark:bg-gray-700">
|
402 |
+
<div class="bg-[${allocationChart.data.datasets[0].backgroundColor[i % 4]}] h-2 rounded-full" style="width: ${allocation.data[i] || 0}%"></div>
|
403 |
</div>
|
404 |
</div>`).join('');
|
405 |
}
|
|
|
416 |
fetchTradeHistory()
|
417 |
]);
|
418 |
|
419 |
+
document.getElementById('total-balance').textContent = `$${parseFloat(balance).toFixed(2)}`;
|
420 |
document.getElementById('open-trades').textContent = positions.length;
|
421 |
+
const longCount = positions.filter(p => p.side === 'LONG').length;
|
422 |
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>`;
|
423 |
const todayProfit = calculateTodayProfit(trades);
|
424 |
document.getElementById('today-profit').textContent = `$${todayProfit.toFixed(2)}`;
|
|
|
433 |
const allocation = calculatePortfolioAllocation(positions);
|
434 |
updateAllocationChart(allocation);
|
435 |
|
436 |
+
const now = new Date().toLocaleString('en-US', { timeZone: 'Asia/Singapore', hour12: false });
|
437 |
+
document.getElementById('last-sync').textContent = `Last synced: ${now}`;
|
438 |
+
document.getElementById('allocation-update').textContent = `Last updated: ${now}`;
|
439 |
} catch (error) {
|
440 |
console.error('Error fetching data:', error);
|
441 |
+
alert(`Failed to sync with BingX API. Please check your API credentials, IP whitelisting, or network. Details: ${error.message}`);
|
442 |
}
|
443 |
}
|
444 |
|
|
|
446 |
document.getElementById('refresh-btn').addEventListener('click', fetchData);
|
447 |
document.getElementById('sync-now').addEventListener('click', fetchData);
|
448 |
window.addEventListener('load', fetchData);
|
449 |
+
setInterval(fetchData, 120000); // Refresh every 2 minutes to avoid rate limiting
|
450 |
</script>
|
451 |
<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>
|
452 |
</body>
|