127 lines
5.3 KiB
JavaScript
127 lines
5.3 KiB
JavaScript
document.addEventListener('DOMContentLoaded', function () {
|
|
const POLLING_INTERVAL = 3000; // 3 seconds
|
|
|
|
const liveTickers = [
|
|
{ symbol: 'BTCUSDT', elementId: 'live-crypto-row-btc', lastPrice: 0 },
|
|
{ symbol: 'ETHUSDT', elementId: 'live-crypto-row-eth', lastPrice: 0 }
|
|
];
|
|
|
|
async function fetchAndupdate(ticker, rowElement) {
|
|
try {
|
|
const response = await fetch(`api/ticker.php?symbol=${ticker.symbol}`);
|
|
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
|
|
const data = await response.json();
|
|
if (data.error) throw new Error(`API Error: ${data.error}`);
|
|
updateRow(data, ticker, rowElement);
|
|
} catch (error) {
|
|
console.error(`Failed to fetch live price for ${ticker.symbol}:`, error);
|
|
const priceCell = rowElement.querySelector('.price');
|
|
if (priceCell) priceCell.textContent = 'Error';
|
|
}
|
|
}
|
|
|
|
function updateRow(data, ticker, rowElement) {
|
|
const priceCell = rowElement.querySelector('.price');
|
|
const symbolCell = rowElement.querySelector('.symbol');
|
|
const exchangeCell = rowElement.querySelector('.exchange');
|
|
|
|
if (!priceCell || !symbolCell || !exchangeCell) {
|
|
console.error(`One or more required elements not found in row for ${ticker.symbol}`);
|
|
return;
|
|
}
|
|
|
|
const currentPrice = parseFloat(data.price);
|
|
priceCell.textContent = `${currentPrice.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
symbolCell.textContent = data.symbol.replace('_SPBL', '');
|
|
exchangeCell.textContent = data.exchange;
|
|
|
|
if (ticker.lastPrice !== 0 && currentPrice !== ticker.lastPrice) {
|
|
const flashClass = currentPrice > ticker.lastPrice ? 'flash-success' : 'flash-danger';
|
|
priceCell.classList.add(flashClass);
|
|
setTimeout(() => priceCell.classList.remove(flashClass), 750);
|
|
}
|
|
|
|
ticker.lastPrice = currentPrice;
|
|
}
|
|
|
|
async function fetchAnalysis(ticker, rowElement) {
|
|
try {
|
|
const response = await fetch(`api/analysis.php?symbol=${ticker.symbol}&period=20`);
|
|
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
|
|
const data = await response.json();
|
|
if (data.error) throw new Error(`API Error: ${data.error}`);
|
|
updateAnalysis(data, rowElement, ticker.lastPrice);
|
|
} catch (error) {
|
|
console.error(`Failed to fetch analysis for ${ticker.symbol}:`, error);
|
|
const smaCell = rowElement.querySelector('.sma');
|
|
if (smaCell) smaCell.textContent = 'Error';
|
|
}
|
|
}
|
|
|
|
function updateAnalysis(data, rowElement, currentPrice) {
|
|
const smaCell = rowElement.querySelector('.sma');
|
|
const signalCell = rowElement.querySelector('.signal');
|
|
if (!smaCell || !signalCell) return;
|
|
|
|
const sma = parseFloat(data.sma);
|
|
smaCell.textContent = sma.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
|
|
if (currentPrice > sma) {
|
|
signalCell.innerHTML = '<span class="badge bg-success-subtle text-success-emphasis">Above SMA</span>';
|
|
} else if (currentPrice < sma) {
|
|
signalCell.innerHTML = '<span class="badge bg-danger-subtle text-danger-emphasis">Below SMA</span>';
|
|
} else {
|
|
signalCell.innerHTML = '<span class="badge bg-secondary-subtle text-secondary-emphasis">At SMA</span>';
|
|
}
|
|
}
|
|
|
|
async function fetchAlert(ticker, rowElement) {
|
|
try {
|
|
const response = await fetch(`api/alerts.php?symbol=${ticker.symbol}`);
|
|
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
|
|
const data = await response.json();
|
|
updateAlertStatus(data.status, rowElement);
|
|
} catch (error) {
|
|
console.error(`Failed to fetch alert for ${ticker.symbol}:`, error);
|
|
}
|
|
}
|
|
|
|
function updateAlertStatus(status, rowElement) {
|
|
const statusCell = rowElement.querySelector('.status');
|
|
if (!statusCell) return;
|
|
|
|
rowElement.classList.remove('flash-alert');
|
|
statusCell.innerHTML = '-';
|
|
|
|
if (status === 'Crash Alert') {
|
|
statusCell.innerHTML = '<span class="badge bg-danger-subtle text-danger-emphasis">Crash Alert</span>';
|
|
rowElement.classList.add('flash-alert');
|
|
} else if (status === 'Pump Alert') {
|
|
statusCell.innerHTML = '<span class="badge bg-success-subtle text-success-emphasis">Pump Alert</span>';
|
|
rowElement.classList.add('flash-alert');
|
|
}
|
|
}
|
|
|
|
function initializeLiveTickers() {
|
|
liveTickers.forEach(ticker => {
|
|
const rowElement = document.getElementById(ticker.elementId);
|
|
if (!rowElement) {
|
|
console.error(`Element with ID #${ticker.elementId} not found for symbol ${ticker.symbol}.`);
|
|
return;
|
|
}
|
|
|
|
const fetchAll = () => {
|
|
fetchAndupdate(ticker, rowElement).then(() => {
|
|
fetchAnalysis(ticker, rowElement);
|
|
});
|
|
fetchAlert(ticker, rowElement);
|
|
};
|
|
|
|
fetchAll();
|
|
setInterval(fetchAll, POLLING_INTERVAL);
|
|
});
|
|
}
|
|
|
|
initializeLiveTickers();
|
|
});
|