Datasourceforcryptocurrency / static /js /tradingview-charts.js
Really-amin's picture
Upload 1460 files
96af7c9 verified
/**
* ═══════════════════════════════════════════════════════════════════
* TRADINGVIEW STYLE CHARTS
* Professional Trading Charts with Advanced Features
* ═══════════════════════════════════════════════════════════════════
*/
// Chart instances storage
const tradingViewCharts = {};
/**
* Create TradingView-style candlestick chart
*/
export function createCandlestickChart(canvasId, data, options = {}) {
const ctx = document.getElementById(canvasId);
if (!ctx) return null;
// Destroy existing chart
if (tradingViewCharts[canvasId]) {
tradingViewCharts[canvasId].destroy();
}
const {
symbol = 'BTC',
timeframe = '1D',
showVolume = true,
showIndicators = true
} = options;
// Process candlestick data
const labels = data.map(d => new Date(d.time).toLocaleDateString());
const opens = data.map(d => d.open);
const highs = data.map(d => d.high);
const lows = data.map(d => d.low);
const closes = data.map(d => d.close);
const volumes = data.map(d => d.volume || 0);
// Determine colors based on price movement
const colors = data.map((d, i) => {
if (i === 0) return closes[i] >= opens[i] ? '#10B981' : '#EF4444';
return closes[i] >= closes[i - 1] ? '#10B981' : '#EF4444';
});
const datasets = [
{
label: 'Price',
data: closes,
borderColor: '#00D4FF',
backgroundColor: 'rgba(0, 212, 255, 0.1)',
borderWidth: 2,
fill: true,
tension: 0.1,
pointRadius: 0,
pointHoverRadius: 6,
pointHoverBackgroundColor: '#00D4FF',
pointHoverBorderColor: '#fff',
pointHoverBorderWidth: 2,
yAxisID: 'y'
}
];
if (showVolume) {
datasets.push({
label: 'Volume',
data: volumes,
type: 'bar',
backgroundColor: colors.map(c => c + '40'),
borderColor: colors,
borderWidth: 1,
yAxisID: 'y1',
order: 2
});
}
tradingViewCharts[canvasId] = new Chart(ctx, {
type: 'line',
data: { labels, datasets },
options: {
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: 'index',
intersect: false
},
plugins: {
legend: {
display: true,
position: 'top',
align: 'end',
labels: {
usePointStyle: true,
padding: 15,
font: {
size: 12,
weight: 600,
family: "'Manrope', sans-serif"
},
color: '#E2E8F0'
}
},
tooltip: {
enabled: true,
backgroundColor: 'rgba(15, 23, 42, 0.98)',
titleColor: '#00D4FF',
bodyColor: '#E2E8F0',
borderColor: 'rgba(0, 212, 255, 0.5)',
borderWidth: 1,
padding: 16,
displayColors: true,
boxPadding: 8,
usePointStyle: true,
callbacks: {
title: function(context) {
return context[0].label;
},
label: function(context) {
if (context.datasetIndex === 0) {
return `Price: $${context.parsed.y.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
} else {
return `Volume: ${context.parsed.y.toLocaleString()}`;
}
}
}
}
},
scales: {
x: {
grid: {
display: false,
color: 'rgba(255, 255, 255, 0.05)'
},
ticks: {
color: '#94A3B8',
font: {
size: 11,
family: "'Manrope', sans-serif"
},
maxRotation: 0,
autoSkip: true,
maxTicksLimit: 12
},
border: {
display: false
}
},
y: {
type: 'linear',
position: 'left',
grid: {
color: 'rgba(255, 255, 255, 0.05)',
drawBorder: false
},
ticks: {
color: '#94A3B8',
font: {
size: 11,
family: "'Manrope', sans-serif"
},
callback: function(value) {
return '$' + value.toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: 0 });
}
}
},
y1: showVolume ? {
type: 'linear',
position: 'right',
grid: {
display: false,
drawBorder: false
},
ticks: {
display: false
}
} : undefined
}
}
});
return tradingViewCharts[canvasId];
}
/**
* Create advanced line chart with indicators
*/
export function createAdvancedLineChart(canvasId, priceData, indicators = {}) {
const ctx = document.getElementById(canvasId);
if (!ctx) return null;
if (tradingViewCharts[canvasId]) {
tradingViewCharts[canvasId].destroy();
}
const labels = priceData.map(d => new Date(d.time || d.timestamp).toLocaleDateString());
const prices = priceData.map(d => d.price || d.value);
// Calculate indicators
const ma20 = indicators.ma20 || calculateMA(prices, 20);
const ma50 = indicators.ma50 || calculateMA(prices, 50);
const rsi = indicators.rsi || calculateRSI(prices, 14);
const datasets = [
{
label: 'Price',
data: prices,
borderColor: '#00D4FF',
backgroundColor: 'rgba(0, 212, 255, 0.1)',
borderWidth: 2.5,
fill: true,
tension: 0.1,
pointRadius: 0,
pointHoverRadius: 6,
yAxisID: 'y',
order: 1
}
];
if (indicators.showMA20) {
datasets.push({
label: 'MA 20',
data: ma20,
borderColor: '#8B5CF6',
backgroundColor: 'transparent',
borderWidth: 1.5,
borderDash: [5, 5],
fill: false,
tension: 0.1,
pointRadius: 0,
yAxisID: 'y',
order: 2
});
}
if (indicators.showMA50) {
datasets.push({
label: 'MA 50',
data: ma50,
borderColor: '#EC4899',
backgroundColor: 'transparent',
borderWidth: 1.5,
borderDash: [5, 5],
fill: false,
tension: 0.1,
pointRadius: 0,
yAxisID: 'y',
order: 3
});
}
tradingViewCharts[canvasId] = new Chart(ctx, {
type: 'line',
data: { labels, datasets },
options: {
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: 'index',
intersect: false
},
plugins: {
legend: {
display: true,
position: 'top',
align: 'end',
labels: {
usePointStyle: true,
padding: 15,
font: {
size: 12,
weight: 600,
family: "'Manrope', sans-serif"
},
color: '#E2E8F0'
}
},
tooltip: {
enabled: true,
backgroundColor: 'rgba(15, 23, 42, 0.98)',
titleColor: '#00D4FF',
bodyColor: '#E2E8F0',
borderColor: 'rgba(0, 212, 255, 0.5)',
borderWidth: 1,
padding: 16,
displayColors: true,
boxPadding: 8
}
},
scales: {
x: {
grid: {
display: false
},
ticks: {
color: '#94A3B8',
font: {
size: 11,
family: "'Manrope', sans-serif"
},
maxRotation: 0,
autoSkip: true
},
border: {
display: false
}
},
y: {
grid: {
color: 'rgba(255, 255, 255, 0.05)',
drawBorder: false
},
ticks: {
color: '#94A3B8',
font: {
size: 11,
family: "'Manrope', sans-serif"
},
callback: function(value) {
return '$' + value.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
}
}
}
}
}
});
return tradingViewCharts[canvasId];
}
/**
* Calculate Moving Average
*/
function calculateMA(data, period) {
const result = [];
for (let i = 0; i < data.length; i++) {
if (i < period - 1) {
result.push(null);
} else {
const sum = data.slice(i - period + 1, i + 1).reduce((a, b) => a + b, 0);
result.push(sum / period);
}
}
return result;
}
/**
* Calculate RSI (Relative Strength Index)
*/
function calculateRSI(data, period = 14) {
const result = [];
const gains = [];
const losses = [];
for (let i = 1; i < data.length; i++) {
const change = data[i] - data[i - 1];
gains.push(change > 0 ? change : 0);
losses.push(change < 0 ? Math.abs(change) : 0);
}
for (let i = 0; i < data.length; i++) {
if (i < period) {
result.push(null);
} else {
const avgGain = gains.slice(i - period, i).reduce((a, b) => a + b, 0) / period;
const avgLoss = losses.slice(i - period, i).reduce((a, b) => a + b, 0) / period;
const rs = avgLoss === 0 ? 100 : avgGain / avgLoss;
const rsi = 100 - (100 / (1 + rs));
result.push(rsi);
}
}
return result;
}
/**
* Create volume chart
*/
export function createVolumeChart(canvasId, volumeData) {
const ctx = document.getElementById(canvasId);
if (!ctx) return null;
if (tradingViewCharts[canvasId]) {
tradingViewCharts[canvasId].destroy();
}
const labels = volumeData.map(d => new Date(d.time).toLocaleDateString());
const volumes = volumeData.map(d => d.volume);
const colors = volumeData.map((d, i) => {
if (i === 0) return '#10B981';
return volumes[i] >= volumes[i - 1] ? '#10B981' : '#EF4444';
});
tradingViewCharts[canvasId] = new Chart(ctx, {
type: 'bar',
data: {
labels,
datasets: [{
label: 'Volume',
data: volumes,
backgroundColor: colors.map(c => c + '60'),
borderColor: colors,
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
tooltip: {
backgroundColor: 'rgba(15, 23, 42, 0.98)',
titleColor: '#00D4FF',
bodyColor: '#E2E8F0',
borderColor: 'rgba(0, 212, 255, 0.5)',
borderWidth: 1,
padding: 12
}
},
scales: {
x: {
grid: {
display: false
},
ticks: {
color: '#94A3B8',
font: {
size: 10,
family: "'Manrope', sans-serif"
}
},
border: {
display: false
}
},
y: {
grid: {
color: 'rgba(255, 255, 255, 0.05)',
drawBorder: false
},
ticks: {
color: '#94A3B8',
font: {
size: 10,
family: "'Manrope', sans-serif"
},
callback: function(value) {
if (value >= 1e9) return (value / 1e9).toFixed(2) + 'B';
if (value >= 1e6) return (value / 1e6).toFixed(2) + 'M';
if (value >= 1e3) return (value / 1e3).toFixed(2) + 'K';
return value;
}
}
}
}
}
});
return tradingViewCharts[canvasId];
}
/**
* Destroy chart
*/
export function destroyChart(canvasId) {
if (tradingViewCharts[canvasId]) {
tradingViewCharts[canvasId].destroy();
delete tradingViewCharts[canvasId];
}
}
/**
* Update chart data
*/
export function updateChart(canvasId, newData) {
if (tradingViewCharts[canvasId]) {
tradingViewCharts[canvasId].data = newData;
tradingViewCharts[canvasId].update();
}
}