45 lines
1.7 KiB
TypeScript
45 lines
1.7 KiB
TypeScript
import type { Candle } from '../types';
|
||
|
||
/** Wilder ADX: +DM/−DM → Wilder-geglättet → DI± → DX → ADX. NaN vor Index 2×period−1. */
|
||
export function adx(candles: Candle[], period: number): number[] {
|
||
const n = candles.length;
|
||
const out = new Array<number>(n).fill(NaN);
|
||
if (n < 2 * period) return out;
|
||
const plusDM = [0];
|
||
const minusDM = [0];
|
||
const tr = [candles[0].high - candles[0].low];
|
||
for (let i = 1; i < n; i++) {
|
||
const up = candles[i].high - candles[i - 1].high;
|
||
const down = candles[i - 1].low - candles[i].low;
|
||
plusDM.push(up > down && up > 0 ? up : 0);
|
||
minusDM.push(down > up && down > 0 ? down : 0);
|
||
tr.push(Math.max(
|
||
candles[i].high - candles[i].low,
|
||
Math.abs(candles[i].high - candles[i - 1].close),
|
||
Math.abs(candles[i].low - candles[i - 1].close),
|
||
));
|
||
}
|
||
let sTR = 0, sPlus = 0, sMinus = 0;
|
||
for (let i = 1; i <= period; i++) { sTR += tr[i]; sPlus += plusDM[i]; sMinus += minusDM[i]; }
|
||
const dx = new Array<number>(n).fill(NaN);
|
||
const computeDx = () => {
|
||
if (sTR === 0) return 0; // völlig flacher Markt
|
||
const plusDI = (100 * sPlus) / sTR;
|
||
const minusDI = (100 * sMinus) / sTR;
|
||
const sum = plusDI + minusDI;
|
||
return sum === 0 ? 0 : (100 * Math.abs(plusDI - minusDI)) / sum;
|
||
};
|
||
dx[period] = computeDx();
|
||
for (let i = period + 1; i < n; i++) {
|
||
sTR = sTR - sTR / period + tr[i];
|
||
sPlus = sPlus - sPlus / period + plusDM[i];
|
||
sMinus = sMinus - sMinus / period + minusDM[i];
|
||
dx[i] = computeDx();
|
||
}
|
||
let sum = 0;
|
||
for (let i = period; i < 2 * period; i++) sum += dx[i];
|
||
out[2 * period - 1] = sum / period;
|
||
for (let i = 2 * period; i < n; i++) out[i] = (out[i - 1] * (period - 1) + dx[i]) / period;
|
||
return out;
|
||
}
|