UNPKG

@ldrick/trade-indicators

Version:
32 lines (31 loc) 2.08 kB
import { apply as AP, either as E, function as F, readonlyArray as RA, readonlyNonEmptyArray as RNEA, } from 'fp-ts'; import { PeriodSizeMissmatchError } from '../errors/PeriodSizeMissmatchError.js'; import * as array from '../utils/array.js'; import * as number_ from '../utils/number.js'; import { emaC } from './ema.js'; const validatePeriodSizes = (slowPeriod, fastPeriod) => slowPeriod > fastPeriod ? E.right(true) : E.left(new PeriodSizeMissmatchError('slowPeriod', 'fastPeriod')); const calculate = (fast, slow) => F.pipe(slow, RNEA.mapWithIndex((index, value) => { const shortened = RA.takeRight(slow.length)(fast); return shortened[index].sub(value); })); /** * The Moving Average Convergence Divergence (MACD) is the relationship of * two Exponential Moving Averages (EMA) with different periods. * It generates crosses with the generated signal EMA which can be used * to indicate uptrends or downtrends. * @public */ export const macd = (values, fastPeriod = 12, slowPeriod = 26, signalPeriod = 9) => F.pipe(AP.sequenceS(E.Applicative)({ fastPeriodV: number_.validatePositiveInteger(fastPeriod), slowPeriodV: number_.validatePositiveInteger(slowPeriod), // eslint-disable-next-line perfectionist/sort-objects signalPeriodV: number_.validatePositiveInteger(signalPeriod), // eslint-disable-next-line perfectionist/sort-objects periodSizes: validatePeriodSizes(slowPeriod, fastPeriod), valuesV: array.validateRequiredSize(slowPeriod + signalPeriod - 1)(values), }), E.bind('valuesB', ({ valuesV }) => array.toBig(valuesV)), E.bind('emaSlow', ({ slowPeriodV, valuesB }) => emaC(valuesB, slowPeriodV)), E.bind('emaFast', ({ fastPeriodV, valuesB }) => emaC(valuesB, fastPeriodV)), E.bind('macdResult', ({ emaFast, emaSlow }) => E.right(calculate(emaFast, emaSlow))), E.bind('signal', ({ macdResult, signalPeriodV }) => emaC(macdResult, signalPeriodV)), E.map(({ macdResult, signal }) => ({ macd: array.toNumber(macdResult), signal: F.pipe(signal, array.toNumber, array.fillLeftW(macdResult.length, null)), })));