import { LineData, SeriesDataItemTypeMap, Time } from 'lightweight-charts';
import { SerieData } from '@core/Series/BaseSeries';
import { LineCandle } from '../../types';
import { IndicatorDataFormatter } from './index';
type MaSource = 'open' | 'high' | 'low' | 'close';
export function emaIndicator({
mainSeriesData,
selfData,
candle,
settings,
}: IndicatorDataFormatter<'Line'>): SeriesDataItemTypeMap<Time>['Line'][] {
const maLength = Number(settings?.length ?? 25);
const source = (settings?.source ?? 'close') as MaSource;
const offset = Number(settings?.offset ?? 0);
const mainSeriesDataConverted = mainSeriesData.map((c) => ({
time: c.customValues.time,
value: Number(c.customValues[source] ?? c.customValues.close),
}));
if (!candle) {
return calculateEMASeriesData(mainSeriesDataConverted, maLength);
}
if (!selfData) {
return [{ time: candle.time as Time, value: 0 }];
}
return [calculatePreciseEMASeriesData(mainSeriesDataConverted, selfData, candle, maLength)];
}
export function calculatePreciseEMASeriesData(
candleData: LineCandle[],
currentIndicatorData: LineCandle[],
candle: SerieData,
maLength: number,
): SeriesDataItemTypeMap<Time>['Line'] {
const candleIndexToCalculate = candleData.findIndex((c) => c.time === candle.time);
if (candleIndexToCalculate === -1) {
console.error('[Indicators]: нет подходящей свечи в массиве');
return {
time: candle.time as Time,
value: 0,
};
}
const prevCandleIndex = currentIndicatorData.length - 2;
const prevCandle = currentIndicatorData[prevCandleIndex];
const smoothing = 2;
const k = smoothing / (maLength + 1);
const prevEma = prevCandle?.value ?? 0;
const ema = k * candleData[candleIndexToCalculate].value + prevEma * (1 - k);
return {
time: candle.time as Time,
value: ema,
};
}
export function calculateEMASeriesData(
candleData: LineCandle[],
maLength: number,
): SeriesDataItemTypeMap<Time>['Line'][] {
const maData: LineData<Time>[] = [];
const smoothing = 2;
const k = smoothing / (maLength + 1);
for (let i = 0; i < candleData.length; i++) {
if (i < maLength - 1) {
maData.push({ time: candleData[i].time as Time, value: 0 });
} else if (i === maLength - 1) {
let sum = 0;
for (let j = 0; j < maLength; j++) {
sum += candleData[i - j].value;
}
const maValue = sum / maLength;
maData.push({
time: candleData[i].time as Time,
value: maValue,
});
} else {
const prevEma = maData[maData.length - 1]?.value ?? 0;
const ema = k * candleData[i].value + prevEma * (1 - k);
maData.push({
time: candleData[i].time as Time,
value: ema,
});
}
}
return maData;
}