@react-financial-charts/indicators
Version: 
Indicators for react-financial-charts
89 lines (68 loc) • 2.54 kB
text/typescript
import { sum } from "d3-array";
import { slidingWindow } from "../utils";
import { ATR as defaultOptions } from "./defaultOptionsForComputation";
export interface ATROptions {
    readonly windowSize: number;
}
export interface ATRSource {
    readonly close: number;
    readonly high: number;
    readonly low: number;
    readonly open: number;
}
export interface ATRCalculator {
    (data: any[]): any;
    undefinedLength(): number;
    options(): ATROptions;
    options(newOptions: ATROptions): ATRCalculator;
    source(): (d: any) => ATRSource;
    source(newSource: (d: any) => ATRSource): ATRCalculator;
}
export default function () {
    let options: ATROptions = defaultOptions;
    let source = (d: any) => ({ open: d.open, high: d.high, low: d.low, close: d.close });
    const calculator = (data: any[]) => {
        const { windowSize } = options;
        const trueRangeAlgorithm = slidingWindow()
            .windowSize(2)
            .source(source)
            .undefinedValue((d: any) => d.high - d.low) // the first TR value is simply the High minus the Low
            .accumulator((values: any) => {
                const prev = values[0];
                const d = values[1];
                return Math.max(d.high - d.low, d.high - prev.close, d.low - prev.close);
            });
        let prevATR: number | undefined;
        const atrAlgorithm = slidingWindow()
            .skipInitial(1) // trueRange starts from index 1 so ATR starts from 1
            .windowSize(windowSize)
            .accumulator((values: any[]) => {
                const tr = values[values.length - 1];
                const atr =
                    prevATR !== undefined ? (prevATR * (windowSize - 1) + tr) / windowSize : sum(values) / windowSize;
                prevATR = atr;
                return atr;
            });
        const newData = atrAlgorithm(trueRangeAlgorithm(data));
        return newData;
    };
    calculator.undefinedLength = () => {
        const { windowSize } = options;
        return windowSize - 1;
    };
    calculator.options = (newOptions?: ATROptions) => {
        if (newOptions === undefined) {
            return options;
        }
        options = { ...defaultOptions, ...newOptions };
        return calculator;
    };
    calculator.source = (newSource?: (d: any) => ATRSource) => {
        if (newSource === undefined) {
            return source;
        }
        source = newSource;
        return calculator;
    };
    return calculator as ATRCalculator;
}