92 lines
3.8 KiB
JavaScript
92 lines
3.8 KiB
JavaScript
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
|
|
};
|
|
}
|
|
}
|