maher-tradingview-api
Version:
Tradingview instant stocks API, indicator alerts, trading bot, and more !
566 lines (518 loc) • 16.4 kB
JavaScript
/* eslint-disable linebreak-style */
/* eslint-disable no-restricted-properties */
/* eslint-disable linebreak-style */
/* eslint-disable no-unused-vars */
/* eslint-disable prefer-const */
/* eslint-disable linebreak-style */
/* eslint-disable space-before-function-paren */
/* eslint-disable no-const-assign */
/* eslint-disable arrow-parens */
/* eslint-disable no-use-before-define */
/* eslint-disable comma-dangle */
/* eslint-disable no-plusplus */
/* eslint-disable no-trailing-spaces */
/* eslint-disable object-shorthand */
/* eslint-disable func-names */
/* eslint-disable linebreak-style */
/* eslint-disable no-undef */
/* eslint-disable linebreak-style */
/**
* technical-indicators.js
* ملف رسم المؤشرات الفنية لتطبيق TradingView API
*/
// التحقق من تحميل مكتبة Chart.js وإضافاتها
(function() {
if (typeof Chart === 'undefined') {
console.error('مكتبة Chart.js غير محملة');
return;
}
})();
// رسم مؤشر RSI (مؤشر القوة النسبية)
function renderRSIChart(chartId, data, period = 14) {
try {
if (!data || !Array.isArray(data) || data.length === 0) {
console.error('renderRSIChart: البيانات غير صالحة', data);
return;
}
const chartElement = document.getElementById(chartId);
if (!chartElement) {
console.error(`renderRSIChart: لم يتم العثور على العنصر ${chartId}`);
return;
}
const ctx = chartElement.getContext('2d');
const existingChart = Chart.getChart(ctx.canvas);
if (existingChart) {
existingChart.destroy();
}
const rsiValues = calculateRSI(data, period);
const labels = Array.from({ length: rsiValues.length }, (_, i) => i + 1);
return new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'RSI',
data: rsiValues,
borderColor: '#0088cc',
backgroundColor: 'rgba(0, 136, 204, 0.1)',
borderWidth: 2,
fill: true,
pointRadius: 0,
pointHoverRadius: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: 'index',
intersect: false
},
scales: {
x: {
display: false
},
y: {
min: 0,
max: 100,
grid: {
color: function(context) {
if (context.tick.value === 30 || context.tick.value === 70) {
return 'rgba(255, 0, 0, 0.1)';
}
return 'rgba(0, 0, 0, 0.05)';
}
},
ticks: {
callback: function(value) {
if (value === 0 || value === 30 || value === 70 || value === 100) {
return value;
}
return '';
}
}
}
},
plugins: {
tooltip: {
mode: 'index',
intersect: false,
callbacks: {
label: function(context) {
return `RSI: ${context.parsed.y.toFixed(2)}`;
}
}
},
annotation: {
annotations: {
line70: {
type: 'line',
yMin: 70,
yMax: 70,
borderColor: 'rgba(255, 82, 82, 0.7)',
borderWidth: 1,
borderDash: [3, 3],
label: {
enabled: true,
content: 'ذروة شراء',
position: 'end',
backgroundColor: 'rgba(255, 82, 82, 0.7)'
}
},
line30: {
type: 'line',
yMin: 30,
yMax: 30,
borderColor: 'rgba(75, 192, 192, 0.7)',
borderWidth: 1,
borderDash: [3, 3],
label: {
enabled: true,
content: 'ذروة بيع',
position: 'end',
backgroundColor: 'rgba(75, 192, 192, 0.7)'
}
}
}
}
}
}
});
} catch (error) {
console.error('renderRSIChart: خطأ في رسم المؤشر', error);
}
}
// رسم مؤشر MACD
function renderMACDChart(chartId, data, fastPeriod = 12, slowPeriod = 26, signalPeriod = 9) {
try {
if (!data || !Array.isArray(data) || data.length === 0) {
console.error('renderMACDChart: البيانات غير صالحة', data);
return;
}
const chartElement = document.getElementById(chartId);
if (!chartElement) {
console.error(`renderMACDChart: لم يتم العثور على العنصر ${chartId}`);
return;
}
const ctx = chartElement.getContext('2d');
const existingChart = Chart.getChart(ctx.canvas);
if (existingChart) {
existingChart.destroy();
}
const macdData = calculateMACD(data, fastPeriod, slowPeriod, signalPeriod);
const labels = Array.from({ length: macdData.macdLine.length }, (_, i) => i + 1);
return new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [
{
label: 'Histogram',
data: macdData.histogram,
type: 'bar',
backgroundColor: function(context) {
const value = context.dataset.data[context.dataIndex];
return value >= 0 ? 'rgba(75, 192, 192, 0.6)' : 'rgba(255, 99, 132, 0.6)';
},
order: 3
},
{
label: 'MACD Line',
data: macdData.macdLine,
borderColor: '#0088cc',
backgroundColor: 'transparent',
borderWidth: 2,
pointRadius: 0,
order: 1
},
{
label: 'Signal Line',
data: macdData.signalLine,
borderColor: '#ff6384',
backgroundColor: 'transparent',
borderWidth: 2,
pointRadius: 0,
order: 2
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: 'index',
intersect: false
},
scales: {
x: {
display: false
},
y: {
grid: {
color: 'rgba(0, 0, 0, 0.05)'
}
}
},
plugins: {
tooltip: {
mode: 'index',
intersect: false,
callbacks: {
label: function(context) {
const datasetLabel = context.dataset.label;
const value = context.parsed.y;
return `${datasetLabel}: ${value.toFixed(4)}`;
}
}
},
legend: {
display: true,
position: 'top',
labels: {
boxWidth: 12,
padding: 15
}
}
}
}
});
} catch (error) {
console.error('renderMACDChart: خطأ في رسم المؤشر', error);
}
}
// رسم مؤشر المتوسط المتحرك
function renderMAChart(chartId, data, periods = [20, 50, 200]) {
try {
if (!data || !Array.isArray(data) || data.length === 0) {
console.error('renderMAChart: البيانات غير صالحة', data);
return;
}
const chartElement = document.getElementById(chartId);
if (!chartElement) {
console.error(`renderMAChart: لم يتم العثور على العنصر ${chartId}`);
return;
}
const ctx = chartElement.getContext('2d');
const existingChart = Chart.getChart(ctx.canvas);
if (existingChart) {
existingChart.destroy();
}
const labels = Array.from({ length: data.length }, (_, i) => i + 1);
const datasets = [{
label: 'السعر',
data: data,
borderColor: '#0088cc',
backgroundColor: 'transparent',
borderWidth: 2,
pointRadius: 0,
order: 1
}];
const colors = ['#ff6384', '#36a2eb', '#4bc0c0'];
periods.forEach((period, index) => {
const maValues = calculateSMA(data, period);
const paddedMA = Array(period - 1).fill(null).concat(maValues);
datasets.push({
label: `MA${period}`,
data: paddedMA,
borderColor: colors[index % colors.length],
backgroundColor: 'transparent',
borderWidth: 1.5,
pointRadius: 0,
borderDash: [5, 5],
order: index + 2
});
});
return new Chart(ctx, {
type: 'line',
data: { labels, datasets },
options: {
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: 'index',
intersect: false
},
scales: {
x: {
display: false
},
y: {
grid: {
color: 'rgba(0, 0, 0, 0.05)'
}
}
},
plugins: {
tooltip: {
mode: 'index',
intersect: false
},
legend: {
display: true,
position: 'top'
}
}
}
});
} catch (error) {
console.error('renderMAChart: خطأ في رسم المؤشر', error);
}
}
// رسم مؤشر بولينجر باند
function renderBollingerBandsChart(chartId, data, period = 20, stdDev = 2) {
try {
if (!data || !Array.isArray(data) || data.length === 0) {
console.error('renderBollingerBandsChart: البيانات غير صالحة', data);
return;
}
const chartElement = document.getElementById(chartId);
if (!chartElement) {
console.error(`renderBollingerBandsChart: لم يتم العثور على العنصر ${chartId}`);
return;
}
const ctx = chartElement.getContext('2d');
const existingChart = Chart.getChart(ctx.canvas);
if (existingChart) {
existingChart.destroy();
}
const { middle, upper, lower } = calculateBollingerBands(data, period, stdDev);
const labels = Array.from({ length: data.length }, (_, i) => i + 1);
// Pad the arrays to align with price data
const padding = Array(period - 1).fill(null);
const paddedMiddle = [...padding, ...middle];
const paddedUpper = [...padding, ...upper];
const paddedLower = [...padding, ...lower];
return new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [
{
label: 'السعر',
data: data,
borderColor: '#0088cc',
backgroundColor: 'transparent',
borderWidth: 2,
pointRadius: 0,
fill: false,
order: 1
},
{
label: `النطاق العلوي (${period}, ${stdDev})`,
data: paddedUpper,
borderColor: 'rgba(231, 76, 60, 0.8)',
borderWidth: 1,
borderDash: [3, 3],
pointRadius: 0,
fill: false,
order: 2
},
{
label: `النطاق المتوسط (${period})`,
data: paddedMiddle,
borderColor: 'rgba(46, 204, 113, 0.8)',
borderWidth: 1,
pointRadius: 0,
fill: false,
order: 3
},
{
label: `النطاق السفلي (${period}, ${stdDev})`,
data: paddedLower,
borderColor: 'rgba(231, 76, 60, 0.8)',
borderWidth: 1,
borderDash: [3, 3],
pointRadius: 0,
fill: {
target: 'origin',
above: 'rgba(231, 76, 60, 0.05)',
below: 'rgba(46, 204, 113, 0.05)'
},
order: 4
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: 'index',
intersect: false
},
scales: {
x: {
display: false
},
y: {
grid: {
color: 'rgba(0, 0, 0, 0.05)'
}
}
},
plugins: {
tooltip: {
mode: 'index',
intersect: false
},
legend: {
display: true,
position: 'top',
labels: {
boxWidth: 10,
padding: 10
}
}
}
}
});
} catch (error) {
console.error('renderBollingerBandsChart: خطأ في رسم المؤشر', error);
}
}
// وظائف حساب المؤشرات الفنية
// حساب مؤشر القوة النسبية (RSI)
function calculateRSI(data, period = 14) {
const changes = [];
for (let i = 1; i < data.length; i++) {
changes.push(data[i] - data[i - 1]);
}
let gains = changes.map(change => change > 0 ? change : 0);
let losses = changes.map(change => change < 0 ? -change : 0);
const avgGain = gains.slice(0, period).reduce((sum, val) => sum + val, 0) / period;
const avgLoss = losses.slice(0, period).reduce((sum, val) => sum + val, 0) / period;
gains = gains.slice(period);
losses = losses.slice(period);
const rsi = [100 - (100 / (1 + avgGain / avgLoss))];
let lastAvgGain = avgGain;
let lastAvgLoss = avgLoss;
for (const [i, gain] of gains.entries()) {
const loss = losses[i];
lastAvgGain = (lastAvgGain * (period - 1) + gain) / period;
lastAvgLoss = (lastAvgLoss * (period - 1) + loss) / period;
rsi.push(100 - (100 / (1 + lastAvgGain / lastAvgLoss)));
}
return rsi;
}
// حساب مؤشر MACD
function calculateMACD(data, fastPeriod = 12, slowPeriod = 26, signalPeriod = 9) {
const fastEMA = calculateEMA(data, fastPeriod);
const slowEMA = calculateEMA(data, slowPeriod);
const macdLine = [];
for (let i = 0; i < data.length; i++) {
macdLine.push(fastEMA[i] - slowEMA[i]);
}
const signalLine = calculateEMA(macdLine, signalPeriod);
const histogram = macdLine.map((macd, i) => macd - signalLine[i]);
return {
macdLine,
signalLine,
histogram
};
}
// حساب المتوسط المتحرك البسيط (SMA)
function calculateSMA(data, period) {
const sma = [];
for (let i = period - 1; i < data.length; i++) {
const sum = data.slice(i - period + 1, i + 1).reduce((a, b) => a + b, 0);
sma.push(sum / period);
}
return sma;
}
// حساب المتوسط المتحرك الأسي (EMA)
function calculateEMA(data, period) {
const k = 2 / (period + 1);
const ema = [data[0]];
for (let i = 1; i < data.length; i++) {
ema.push(data[i] * k + ema[i - 1] * (1 - k));
}
return ema;
}
// حساب مؤشر بولينجر باندز
function calculateBollingerBands(data, period = 20, stdDev = 2) {
const middle = [];
const upper = [];
const lower = [];
for (let i = period - 1; i < data.length; i++) {
const slice = data.slice(i - period + 1, i + 1);
const avg = slice.reduce((sum, val) => sum + val, 0) / period;
const squareDiffs = slice.map(val => Math.pow(val - avg, 2));
const variance = squareDiffs.reduce((sum, val) => sum + val, 0) / period;
const std = Math.sqrt(variance);
middle.push(avg);
upper.push(avg + (std * stdDev));
lower.push(avg - (std * stdDev));
}
return { middle, upper, lower };
}
// تصدير الوظائف للاستخدام العالمي
window.TechnicalIndicators = {
renderRSIChart,
renderMACDChart,
renderMAChart,
renderBollingerBandsChart,
calculateRSI,
calculateMACD,
calculateSMA,
calculateEMA,
calculateBollingerBands
};