UNPKG

maher-tradingview-api

Version:

Tradingview instant stocks API, indicator alerts, trading bot, and more !

536 lines (484 loc) 15.7 kB
/* 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 */ /** * additional-indicators.js * مؤشرات فنية إضافية لتطبيق TradingView API */ // رسم مؤشر ستوكاستيك function renderStochasticChart(chartId, data, kPeriod = 14, dPeriod = 3) { try { console.log(`renderStochasticChart: رسم مؤشر ستوكاستيك في العنصر ${chartId}`); if (!data || !Array.isArray(data) || data.length === 0) { console.error('renderStochasticChart: البيانات غير صالحة أو فارغة', data); return null; } const chartElement = document.getElementById(chartId); if (!chartElement) { console.error(`renderStochasticChart: لم يتم العثور على العنصر بالمعرف ${chartId}`); return null; } // حساب مؤشر ستوكاستيك const stochastic = calculateStochastic(data, kPeriod, dPeriod); // إنشاء الرسم البياني const ctx = chartElement.getContext('2d'); const chart = new Chart(ctx, { type: 'line', data: { labels: data.slice(kPeriod).map(candle => { if (typeof candle.time === 'string') { return candle.time.split(',')[0]; } return candle.time; }), datasets: [ { label: '%K', data: stochastic.k, borderColor: 'rgb(54, 162, 235)', backgroundColor: 'rgba(54, 162, 235, 0.1)', borderWidth: 1.5, tension: 0.1, pointRadius: 0 }, { label: '%D', data: stochastic.d, borderColor: 'rgb(255, 99, 132)', backgroundColor: 'rgba(255, 99, 132, 0.1)', borderWidth: 1.5, tension: 0.1, pointRadius: 0 } ] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: true, position: 'bottom' }, tooltip: { mode: 'index', intersect: false } }, scales: { y: { min: 0, max: 100, grid: { color: 'rgba(0, 0, 0, 0.05)' }, ticks: { font: { size: 10 } } }, x: { display: false } } } }); return chart; } catch (error) { console.error('خطأ في رسم مؤشر ستوكاستيك:', error); return null; } } // حساب مؤشر ستوكاستيك function calculateStochastic(data, kPeriod = 14, dPeriod = 3) { // التحقق من البيانات if (!data || data.length < kPeriod + dPeriod) { throw new Error('بيانات غير كافية لحساب مؤشر ستوكاستيك'); } const kValues = []; // حساب %K for (let i = kPeriod - 1; i < data.length; i++) { const periodData = data.slice(i - kPeriod + 1, i + 1); const highestHigh = Math.max(...periodData.map(candle => candle.high)); const lowestLow = Math.min(...periodData.map(candle => candle.low)); const currentClose = data[i].close; // معادلة حساب %K const k = ((currentClose - lowestLow) / (highestHigh - lowestLow)) * 100; kValues.push(isNaN(k) ? 50 : k); // استخدام 50 كقيمة افتراضية إذا كان الناتج NaN } // حساب %D (المتوسط المتحرك البسيط لـ %K) const dValues = []; for (let i = dPeriod - 1; i < kValues.length; i++) { const sum = kValues.slice(i - dPeriod + 1, i + 1).reduce((acc, val) => acc + val, 0); const d = sum / dPeriod; dValues.push(d); } // إرجاع قيم %K التي تتوافق مع طول قيم %D (يتم تجاهل القيم الأولى من %K) return { k: kValues.slice(dPeriod - 1), d: dValues }; } // رسم مؤشر حجم التوازن (OBV) function renderOBVChart(chartId, data) { try { console.log(`renderOBVChart: رسم مؤشر حجم التوازن في العنصر ${chartId}`); if (!data || !Array.isArray(data) || data.length === 0) { console.error('renderOBVChart: البيانات غير صالحة أو فارغة', data); return null; } const chartElement = document.getElementById(chartId); if (!chartElement) { console.error(`renderOBVChart: لم يتم العثور على العنصر بالمعرف ${chartId}`); return null; } // حساب OBV const obvValues = calculateOBV(data); // إنشاء الرسم البياني const ctx = chartElement.getContext('2d'); const chart = new Chart(ctx, { type: 'line', data: { labels: data.slice(1).map(candle => { if (typeof candle.time === 'string') { return candle.time.split(',')[0]; } return candle.time; }), datasets: [ { label: 'OBV', data: obvValues, borderColor: 'rgb(153, 102, 255)', backgroundColor: 'rgba(153, 102, 255, 0.1)', borderWidth: 2, tension: 0.1, fill: true, pointRadius: 0 } ] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: true, position: 'bottom' }, tooltip: { mode: 'index', intersect: false } }, scales: { y: { grid: { color: 'rgba(0, 0, 0, 0.05)' }, ticks: { font: { size: 10 } } }, x: { display: false } } } }); return chart; } catch (error) { console.error('خطأ في رسم مؤشر حجم التوازن:', error); return null; } } // حساب مؤشر حجم التوازن (OBV) function calculateOBV(data) { if (!data || data.length <= 1) { return []; } const obvValues = []; let obv = 0; for (let i = 1; i < data.length; i++) { const currentClose = data[i].close; const previousClose = data[i-1].close; const currentVolume = data[i].volume || 0; // حساب OBV if (currentClose > previousClose) { obv += currentVolume; // إضافة الحجم إذا كان الإغلاق صاعد } else if (currentClose < previousClose) { obv -= currentVolume; // طرح الحجم إذا كان الإغلاق هابط } // إذا كان السعر متساوي، لا يتم تعديل OBV obvValues.push(obv); } return obvValues; } // رسم مؤشر ADX (المؤشر المتقارب والمتباعد) function renderADXChart(chartId, data, period = 14) { try { console.log(`renderADXChart: رسم مؤشر ADX في العنصر ${chartId}`); if (!data || !Array.isArray(data) || data.length === 0) { console.error('renderADXChart: البيانات غير صالحة أو فارغة', data); return null; } const chartElement = document.getElementById(chartId); if (!chartElement) { console.error(`renderADXChart: لم يتم العثور على العنصر بالمعرف ${chartId}`); return null; } if (data.length < period * 2) { // إذا كانت البيانات غير كافية، عرض رسالة خطأ const ctx = chartElement.getContext('2d'); const chart = new Chart(ctx, { type: 'line', data: { labels: ['بيانات غير كافية'], datasets: [{ label: 'ADX', data: [], borderColor: 'rgb(153, 102, 255)', }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, title: { display: true, text: 'بيانات غير كافية لحساب مؤشر ADX' } } } }); return chart; } // حساب ADX try { const adxResult = calculateADX(data, period); // إنشاء الرسم البياني const ctx = chartElement.getContext('2d'); const chart = new Chart(ctx, { type: 'line', data: { labels: data.slice(period * 2).map(candle => { if (typeof candle.time === 'string') { return candle.time.split(',')[0]; } return candle.time; }), datasets: [ { label: 'ADX', data: adxResult.adx, borderColor: 'rgb(153, 102, 255)', backgroundColor: 'rgba(153, 102, 255, 0.1)', borderWidth: 2, tension: 0.1, pointRadius: 0 }, { label: '+DI', data: adxResult.plusDI, borderColor: 'rgb(75, 192, 192)', backgroundColor: 'rgba(75, 192, 192, 0.1)', borderWidth: 1, borderDash: [3, 3], tension: 0.1, pointRadius: 0 }, { label: '-DI', data: adxResult.minusDI, borderColor: 'rgb(255, 159, 64)', backgroundColor: 'rgba(255, 159, 64, 0.1)', borderWidth: 1, borderDash: [3, 3], tension: 0.1, pointRadius: 0 } ] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: true, position: 'bottom' }, tooltip: { mode: 'index', intersect: false } }, scales: { y: { min: 0, max: 100, grid: { color: 'rgba(0, 0, 0, 0.05)' }, ticks: { font: { size: 10 } } }, x: { display: false } } } }); return chart; } catch (calcError) { console.error('خطأ في حساب ADX:', calcError); // إذا فشل الحساب، عرض رسالة خطأ const ctx = chartElement.getContext('2d'); const chart = new Chart(ctx, { type: 'line', data: { labels: ['خطأ'], datasets: [{ label: 'ADX', data: [], borderColor: 'rgb(153, 102, 255)', }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, title: { display: true, text: 'حدث خطأ في حساب مؤشر ADX' } } } }); return chart; } } catch (error) { console.error('خطأ في رسم مؤشر ADX:', error); return null; } } // حساب مؤشر ADX function calculateADX(data, period = 14) { if (!data || data.length < period * 2) { throw new Error('بيانات غير كافية لحساب مؤشر ADX'); } // حساب +DM و -DM const plusDM = []; const minusDM = []; for (let i = 1; i < data.length; i++) { const highDiff = data[i].high - data[i-1].high; const lowDiff = data[i-1].low - data[i].low; // +DM if (highDiff > lowDiff && highDiff > 0) { plusDM.push(highDiff); } else { plusDM.push(0); } // -DM if (lowDiff > highDiff && lowDiff > 0) { minusDM.push(lowDiff); } else { minusDM.push(0); } } // حساب النطاق الحقيقي (TR) const trueRanges = []; for (let i = 1; i < data.length; i++) { const tr1 = Math.abs(data[i].high - data[i].low); const tr2 = Math.abs(data[i].high - data[i-1].close); const tr3 = Math.abs(data[i].low - data[i-1].close); const tr = Math.max(tr1, tr2, tr3); trueRanges.push(tr); } // حساب المؤشرات +DI و -DI const plusDI = []; const minusDI = []; const adxValues = []; // حساب المتوسط الأول let sumTR = 0; let sumPlusDM = 0; let sumMinusDM = 0; for (let i = 0; i < period; i++) { sumTR += trueRanges[i]; sumPlusDM += plusDM[i]; sumMinusDM += minusDM[i]; } let smoothedTR = sumTR; let smoothedPlusDM = sumPlusDM; let smoothedMinusDM = sumMinusDM; // حساب +DI و -DI for (let i = period; i < trueRanges.length; i++) { smoothedTR = smoothedTR - (smoothedTR / period) + trueRanges[i]; smoothedPlusDM = smoothedPlusDM - (smoothedPlusDM / period) + plusDM[i]; smoothedMinusDM = smoothedMinusDM - (smoothedMinusDM / period) + minusDM[i]; const plus_di = (smoothedPlusDM / smoothedTR) * 100; const minus_di = (smoothedMinusDM / smoothedTR) * 100; plusDI.push(plus_di); minusDI.push(minus_di); // حساب DX const dx = Math.abs(plus_di - minus_di) / (plus_di + minus_di) * 100; // حساب ADX (متوسط متحرك لـ DX) if (i >= period * 2 - 1) { let adx = 0; if (adxValues.length === 0) { // المتوسط الأولي let sumDX = 0; for (let j = i - period + 1; j <= i; j++) { const tempPlusDI = plusDI[j - period]; const tempMinusDI = minusDI[j - period]; sumDX += Math.abs(tempPlusDI - tempMinusDI) / (tempPlusDI + tempMinusDI) * 100; } adx = sumDX / period; } else { // المتوسط المتحرك الأسي adx = (adxValues[adxValues.length - 1] * (period - 1) + dx) / period; } adxValues.push(adx); } } return { adx: adxValues, plusDI: plusDI.slice(period - 1), minusDI: minusDI.slice(period - 1) }; } // تصدير الوظائف للاستخدام العالمي window.AdditionalIndicators = { renderStochasticChart, calculateStochastic, renderOBVChart, calculateOBV, renderADXChart, calculateADX };