migrationt to websocket
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 1m15s

This commit is contained in:
dongho
2024-12-22 00:57:07 +09:00
parent 2d31dcfd0b
commit 82216daaf8
5 changed files with 808 additions and 155 deletions

View File

@ -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>