fast-technical-indicators
Version:
High-performance technical indicators with zero dependencies - compatible with technicalindicators package
76 lines (75 loc) • 2.68 kB
JavaScript
function trueRange(high, low, previousClose) {
const highLow = high - low;
const highPrevClose = Math.abs(high - previousClose);
const lowPrevClose = Math.abs(low - previousClose);
return Math.max(highLow, highPrevClose, lowPrevClose);
}
export function atr(input) {
const { period = 14, high, low, close } = input;
if (high.length !== low.length || low.length !== close.length || close.length < period + 1) {
return [];
}
const result = [];
const trueRanges = [];
// Calculate true ranges (skip first value since we need previous close)
for (let i = 1; i < close.length; i++) {
const tr = trueRange(high[i], low[i], close[i - 1]);
trueRanges.push(tr);
}
// Calculate initial ATR using simple average
let sum = 0;
for (let i = 0; i < period; i++) {
sum += trueRanges[i];
}
let currentATR = sum / period;
result.push(currentATR);
// Calculate subsequent ATR using Wilder's smoothing
for (let i = period; i < trueRanges.length; i++) {
currentATR = ((currentATR * (period - 1)) + trueRanges[i]) / period;
result.push(currentATR);
}
return result;
}
export class ATR {
constructor(input) {
this.highValues = [];
this.lowValues = [];
this.closeValues = [];
this.trueRanges = [];
this.initialized = false;
this.period = input.period || 14;
}
nextValue(high, low, close) {
this.highValues.push(high);
this.lowValues.push(low);
this.closeValues.push(close);
// Need at least 2 closes to calculate true range
if (this.closeValues.length < 2) {
return undefined;
}
// Calculate true range
const previousClose = this.closeValues[this.closeValues.length - 2];
const tr = trueRange(high, low, previousClose);
this.trueRanges.push(tr);
if (!this.initialized) {
if (this.trueRanges.length === this.period) {
// Calculate initial ATR using simple average
const sum = this.trueRanges.reduce((acc, tr) => acc + tr, 0);
this.currentATR = sum / this.period;
this.initialized = true;
return this.currentATR;
}
return undefined;
}
// Calculate ATR using Wilder's smoothing
this.currentATR = ((this.currentATR * (this.period - 1)) + tr) / this.period;
return this.currentATR;
}
getResult() {
if (!this.initialized || this.currentATR === undefined) {
return [];
}
return [this.currentATR];
}
}
ATR.calculate = atr;