export function calculateSMA(prices: number[], period: number = 20): number { if (prices.length < period) return 0; const slice = prices.slice(-period); const sum = slice.reduce((a, b) => a + b, 0); return sum / period; } export function calculateEMA(prices: number[], period: number = 20): number { if (prices.length < period) return 0; const multiplier = 2 / (period + 1); let ema = prices.slice(0, period).reduce((a, b) => a + b, 0) / period; for (let i = period; i < prices.length; i++) { ema = prices[i] * multiplier + ema * (1 - multiplier); } return ema; } export function calculateRSI(prices: number[], period: number = 14): number { if (prices.length < period + 1) return 50; let gains = 0; let losses = 0; for (let i = prices.length - period; i < prices.length; i++) { const diff = prices[i] - prices[i - 1]; if (diff > 0) gains += diff; else losses -= diff; } const avgGain = gains / period; const avgLoss = losses / period; if (avgLoss === 0) return 100; const rs = avgGain / avgLoss; return 100 - (100 / (1 + rs)); } export function calculateMACD( prices: number[], fastPeriod: number = 12, slowPeriod: number = 26, signalPeriod: number = 9 ): { macdLine: number; signal: number; histogram: number } { if (prices.length < slowPeriod + signalPeriod) return { macdLine: 0, signal: 0, histogram: 0 }; const emaFast = calculateEMA(prices, fastPeriod); const emaSlow = calculateEMA(prices, slowPeriod); const macdLine = emaFast - emaSlow; // Simplified signal: use recent MACD values approximation const signal = macdLine * 0.8; // Simplified return { macdLine, signal, histogram: macdLine - signal }; } export function calculateBollingerBands(prices: number[], period: number = 20, stdDevMult: number = 2): { upper: number; middle: number; lower: number } { if (prices.length < period) return { upper: 0, middle: 0, lower: 0 }; const slice = prices.slice(-period); const sma = slice.reduce((a, b) => a + b, 0) / period; const variance = slice.reduce((sum, p) => sum + Math.pow(p - sma, 2), 0) / period; const stdDev = Math.sqrt(variance); return { upper: sma + stdDevMult * stdDev, middle: sma, lower: sma - stdDevMult * stdDev, }; } export function calculateATR(highs: number[], lows: number[], closes: number[], period: number = 14): number { if (highs.length < period || lows.length < period || closes.length < period) return 0; const len = Math.min(highs.length, lows.length, closes.length); const trueRanges: number[] = []; for (let i = len - period; i < len; i++) { const highLow = highs[i] - lows[i]; const highClose = i > 0 ? Math.abs(highs[i] - closes[i - 1]) : 0; const lowClose = i > 0 ? Math.abs(lows[i] - closes[i - 1]) : 0; trueRanges.push(Math.max(highLow, highClose, lowClose)); } return trueRanges.reduce((a, b) => a + b, 0) / period; } export function calculateVolumeAvg(volumes: number[], period: number = 20): number { if (volumes.length < period) return 0; const slice = volumes.slice(-period); return slice.reduce((a, b) => a + b, 0) / period; }