export class Indicators { static calculateEMA(data: number[], period: number): number { if (data.length === 0) return 0; const k = 2 / (period + 1); let ema = data[0] || 0; for (let i = 1; i < data.length; i++) { const current = data[i] || 0; ema = current * k + ema * (1 - k); } return ema; } static calculateRSI(data: number[], period: number): number { if (data.length <= period) return 50; // Default if not enough data let gains = 0; let losses = 0; // First average for (let i = 1; i <= period; i++) { const diff = data[i] - data[i - 1]; if (diff >= 0) gains += diff; else losses -= diff; } let avgGain = gains / period; let avgLoss = losses / period; // Smoothing for (let i = period + 1; i < data.length; i++) { const diff = data[i] - data[i - 1]; if (diff >= 0) { avgGain = (avgGain * (period - 1) + diff) / period; avgLoss = (avgLoss * (period - 1)) / period; } else { avgGain = (avgGain * (period - 1)) / period; avgLoss = (avgLoss * (period - 1) - diff) / period; } } if (avgLoss === 0) return 100; const rs = avgGain / avgLoss; return 100 - (100 / (1 + rs)); } static calculateATR(candles: any[], period: number): number { if (candles.length <= period) return 0; let trs: number[] = []; for (let i = 1; i < candles.length; i++) { const h = candles[i].high; const l = candles[i].low; const pc = candles[i - 1].close; const tr = Math.max(h - l, Math.abs(h - pc), Math.abs(l - pc)); trs.push(tr); } // Return SMA of TR const recentTrs = trs.slice(-period); return recentTrs.reduce((a, b) => a + b, 0) / period; } }