migrationt to websocket
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 1m15s
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 1m15s
This commit is contained in:
@ -1,183 +1,207 @@
|
||||
<!-- templates/index.html -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>XRP Candlestick Chart</title>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/2.0.2/luxon.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-adapter-luxon/1.1.0/chartjs-adapter-luxon.min.js"></script>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
background-color: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.chart-container {
|
||||
position: relative;
|
||||
height: 60vh;
|
||||
width: 100%;
|
||||
}
|
||||
.info-container {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-top: 20px;
|
||||
padding: 10px;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.info-item {
|
||||
text-align: center;
|
||||
}
|
||||
.info-label {
|
||||
font-size: 0.9em;
|
||||
color: #666;
|
||||
}
|
||||
.info-value {
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
margin-top: 5px;
|
||||
}
|
||||
</style>
|
||||
<title>Realtime Candlestick Chart</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/luxon@3.4.4"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.3.1"></script>
|
||||
<script src="{{ url_for('static', path='js/chartjs-chart-financial.js') }}"></script>
|
||||
<link href="https://cdn.jsdelivr.net/npm/flowbite@2.5.2/dist/flowbite.min.css" rel="stylesheet" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/flowbite@2.5.2/dist/flowbite.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>XRP Candlestick Chart</h1>
|
||||
<div class="chart-container">
|
||||
<canvas id="candlestickChart"></canvas>
|
||||
</div>
|
||||
<div class="info-container">
|
||||
<div class="info-item">
|
||||
<div class="info-label">Open</div>
|
||||
<div class="info-value" id="openPrice">-</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">High</div>
|
||||
<div class="info-value" id="highPrice">-</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">Low</div>
|
||||
<div class="info-value" id="lowPrice">-</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">Close</div>
|
||||
<div class="info-value" id="closePrice">-</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex w-full mt-8">
|
||||
<canvas id="chart"></canvas>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let chart;
|
||||
var barCount = 100;
|
||||
var barData = [];
|
||||
var lineData = [];
|
||||
|
||||
var ctx = document.getElementById('chart').getContext('2d');
|
||||
ctx.canvas.width = 1000;
|
||||
ctx.canvas.height = 250;
|
||||
|
||||
async function fetchCandlestickData() {
|
||||
var chart = new Chart(ctx, {
|
||||
type: 'candlestick',
|
||||
data: {
|
||||
datasets: [{
|
||||
label: '{{coin}}',
|
||||
data: barData
|
||||
}, {
|
||||
label: 'Close price',
|
||||
type: 'line',
|
||||
data: lineData,
|
||||
hidden: true
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
unit: 'minute',
|
||||
displayFormats: {
|
||||
minute: 'HH:mm'
|
||||
}
|
||||
},
|
||||
adapters: {
|
||||
date: {
|
||||
zone: 'UTC'
|
||||
}
|
||||
}
|
||||
},
|
||||
y: {
|
||||
type: 'linear',
|
||||
position: 'right'
|
||||
}
|
||||
},
|
||||
animation: false
|
||||
}
|
||||
});
|
||||
|
||||
async function fetchHistoricalData() {
|
||||
try {
|
||||
const response = await fetch('/data/{{coin}}/candlestick');
|
||||
const response = await fetch('/data/{{coin}}/get-candle/all');
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching candlestick data:', error);
|
||||
console.error('Error fetching historical data:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function updateInfoDisplay(candlestick) {
|
||||
document.getElementById('openPrice').textContent = `$${candlestick.o.toFixed(4)}`;
|
||||
document.getElementById('highPrice').textContent = `$${candlestick.h.toFixed(4)}`;
|
||||
document.getElementById('lowPrice').textContent = `$${candlestick.l.toFixed(4)}`;
|
||||
document.getElementById('closePrice').textContent = `$${candlestick.c.toFixed(4)}`;
|
||||
async function fetchLatestData() {
|
||||
try {
|
||||
const response = await fetch('/data/{{coin}}/get-candle');
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching latest data:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function initializeChart() {
|
||||
// Fetch historical data first
|
||||
const historicalData = await fetchHistoricalData();
|
||||
if (!historicalData) return;
|
||||
|
||||
// Process historical data
|
||||
historicalData.forEach(data => {
|
||||
const candleData = {
|
||||
x: data.time,
|
||||
o: data.open,
|
||||
h: data.high,
|
||||
l: data.low,
|
||||
c: data.close,
|
||||
v: data.volume,
|
||||
vwap: data.vwap,
|
||||
trades: data.trades
|
||||
};
|
||||
|
||||
barData.push(candleData);
|
||||
lineData.push({
|
||||
x: data.time,
|
||||
y: data.close
|
||||
});
|
||||
});
|
||||
|
||||
chart.update();
|
||||
|
||||
// Start real-time updates
|
||||
setInterval(updateChart, 5000);
|
||||
}
|
||||
|
||||
async function updateChart() {
|
||||
const data = await fetchCandlestickData();
|
||||
if (!data) return;
|
||||
const newData = await fetchLatestData();
|
||||
if (!newData) return;
|
||||
|
||||
if (data.length > 0) {
|
||||
updateInfoDisplay(data[data.length - 1]);
|
||||
if (barData.length >= barCount) {
|
||||
barData.shift();
|
||||
lineData.shift();
|
||||
}
|
||||
|
||||
if (chart) {
|
||||
chart.data.datasets[0].data = data;
|
||||
chart.update();
|
||||
const newBarData = {
|
||||
x: newData.time,
|
||||
o: newData.open,
|
||||
h: newData.high,
|
||||
l: newData.low,
|
||||
c: newData.close,
|
||||
v: newData.volume,
|
||||
vwap: newData.vwap,
|
||||
trades: newData.trades
|
||||
};
|
||||
|
||||
// Check if the last candle's timestamp matches the new data
|
||||
const lastCandle = barData[barData.length - 1];
|
||||
if (lastCandle && lastCandle.x === newData.time) {
|
||||
// Update the existing candle
|
||||
Object.assign(lastCandle, newBarData);
|
||||
lineData[lineData.length - 1].y = newData.close;
|
||||
} else {
|
||||
const ctx = document.getElementById('candlestickChart').getContext('2d');
|
||||
chart = new Chart(ctx, {
|
||||
type: 'candlestick',
|
||||
data: {
|
||||
datasets: [{
|
||||
label: 'XRP Price',
|
||||
data: data,
|
||||
color: {
|
||||
up: 'rgb(75, 192, 75)',
|
||||
down: 'rgb(192, 75, 75)',
|
||||
unchanged: 'rgb(90, 90, 90)',
|
||||
}
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'XRP Price Movements'
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
const d = context.raw;
|
||||
return [
|
||||
`Open: $${d.o.toFixed(4)}`,
|
||||
`High: $${d.h.toFixed(4)}`,
|
||||
`Low: $${d.l.toFixed(4)}`,
|
||||
`Close: $${d.c.toFixed(4)}`
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
ticks: {
|
||||
callback: function(value) {
|
||||
return '$' + value.toFixed(4);
|
||||
}
|
||||
}
|
||||
},
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
unit: 'hour',
|
||||
tooltipFormat: 'yyyy-MM-dd HH:mm'
|
||||
},
|
||||
ticks: {
|
||||
maxTicksLimit: 10,
|
||||
maxRotation: 45,
|
||||
minRotation: 45
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add new candle
|
||||
barData.push(newBarData);
|
||||
lineData.push({
|
||||
x: newData.time,
|
||||
y: newData.close
|
||||
});
|
||||
}
|
||||
|
||||
chart.update();
|
||||
}
|
||||
|
||||
// Update every 5 seconds
|
||||
updateChart();
|
||||
setInterval(updateChart, 5000);
|
||||
// Initialize the chart when the page loads
|
||||
initializeChart();
|
||||
|
||||
var update = function () {
|
||||
var dataset = chart.config.data.datasets[0];
|
||||
|
||||
// candlestick vs ohlc
|
||||
var type = document.getElementById('type').value;
|
||||
chart.config.type = type;
|
||||
|
||||
// linear vs log
|
||||
var scaleType = document.getElementById('scale-type').value;
|
||||
chart.config.options.scales.y.type = scaleType;
|
||||
|
||||
// color
|
||||
var colorScheme = document.getElementById('color-scheme').value;
|
||||
if (colorScheme === 'neon') {
|
||||
chart.config.data.datasets[0].backgroundColors = {
|
||||
up: '#01ff01',
|
||||
down: '#fe0000',
|
||||
unchanged: '#999',
|
||||
};
|
||||
} else {
|
||||
delete chart.config.data.datasets[0].backgroundColors;
|
||||
}
|
||||
|
||||
// border
|
||||
var border = document.getElementById('border').value;
|
||||
if (border === 'false') {
|
||||
dataset.borderColors = 'rgba(0, 0, 0, 0)';
|
||||
} else {
|
||||
delete dataset.borderColors;
|
||||
}
|
||||
|
||||
// mixed charts
|
||||
var mixed = document.getElementById('mixed').value;
|
||||
if (mixed === 'true') {
|
||||
chart.config.data.datasets[1].hidden = false;
|
||||
} else {
|
||||
chart.config.data.datasets[1].hidden = true;
|
||||
}
|
||||
|
||||
chart.update();
|
||||
};
|
||||
|
||||
[...document.getElementsByTagName('select')].forEach(element => element.addEventListener('change', update));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</html>
|
Reference in New Issue
Block a user