import { BaseIndicator } from './base.js'; export class RSIIndicator extends BaseIndicator { calculate(candles) { const period = this.params.period || 14; // 1. Calculate RSI using RMA (Wilder's Smoothing) let rsiValues = new Array(candles.length).fill(null); let upSum = 0; let downSum = 0; const rmaAlpha = 1 / period; for (let i = 1; i < candles.length; i++) { const diff = candles[i].close - candles[i-1].close; const up = diff > 0 ? diff : 0; const down = diff < 0 ? -diff : 0; if (i < period) { upSum += up; downSum += down; } else if (i === period) { upSum += up; downSum += down; const avgUp = upSum / period; const avgDown = downSum / period; rsiValues[i] = avgDown === 0 ? 100 : (avgUp === 0 ? 0 : 100 - (100 / (1 + avgUp / avgDown))); upSum = avgUp; // Store for next RMA step downSum = avgDown; } else { upSum = (up - upSum) * rmaAlpha + upSum; downSum = (down - downSum) * rmaAlpha + downSum; rsiValues[i] = downSum === 0 ? 100 : (upSum === 0 ? 0 : 100 - (100 / (1 + upSum / downSum))); } } // Combine results return rsiValues.map((rsi, i) => { return { paneBg: 100, // Background lightening trick rsi: rsi, upperBand: 70, lowerBand: 30 }; }); } getMetadata() { const plots = [ // Background lightness trick (spans from 0 to 100 constantly) // Making it darker by reducing opacity since the main background is dark. { id: 'paneBg', type: 'baseline', baseValue: 0, color: 'transparent', topLineColor: 'transparent', bottomLineColor: 'transparent', topFillColor1: 'rgba(255, 255, 255, 0.015)', topFillColor2: 'rgba(255, 255, 255, 0.015)', bottomFillColor1: 'transparent', bottomFillColor2: 'transparent', title: '', lastValueVisible: false, width: 0 }, // Overbought Gradient Fill (> 70) { id: 'rsi', type: 'baseline', baseValue: 70, color: 'transparent', topLineColor: 'transparent', bottomLineColor: 'transparent', topFillColor1: 'rgba(244, 67, 54, 0.8)', topFillColor2: 'rgba(244, 67, 54, 0.2)', bottomFillColor1: 'transparent', bottomFillColor2: 'transparent', title: '', lastValueVisible: false, width: 0 }, // Oversold Gradient Fill (< 30) { id: 'rsi', type: 'baseline', baseValue: 30, color: 'transparent', topLineColor: 'transparent', bottomLineColor: 'transparent', topFillColor1: 'transparent', topFillColor2: 'transparent', bottomFillColor1: 'rgba(76, 175, 80, 0.2)', bottomFillColor2: 'rgba(76, 175, 80, 0.8)', title: '', lastValueVisible: false, width: 0 }, // RSI Line { id: 'rsi', color: '#7E57C2', title: '', width: 1, lastValueVisible: true }, // Bands { id: 'upperBand', color: '#787B86', title: '', style: 'dashed', width: 1, lastValueVisible: false }, { id: 'lowerBand', color: '#787B86', title: '', style: 'dashed', width: 1, lastValueVisible: false } ]; return { name: 'RSI', description: 'Relative Strength Index', inputs: [ { name: 'period', label: 'RSI Length', type: 'number', default: 14, min: 1, max: 100 } ], plots: plots, displayMode: 'pane', paneMin: 0, paneMax: 100 }; } }