Индикатор разворота

mail@pastecode.io avatar
unknown
javascript
2 years ago
3.5 kB
9
Indexable
Never
// Класс индикатора
class ReverseMeter {

    constructor(period = 400, area = 0.01) {
        this.period = period;
        // погрешность для расчетов (если будем считать по коэфициентам линий K)
        this.area = area;
        this.dataset = new Extremums(Math.floor(period) / 4, 'max'); // Детектор экстремумов
        this.hExtremums = new CircularBuffer(period); // Коллекция только экстремумов
    }
    nextValue(o, h, l, c) {
        let result = null;

        // Если экстремумы заполнены
        if (this.hExtremums.filled()) {
            result = this.calculate(o, h, l, c);
        }

        // Возвращает либо новый максимальный экстремум либо null
        const extremum = this.dataset.push(h);

        if (extremum) {
            this.hExtremums.push(extremum);
        }

        return result;
    }
    calculate(o, h, l, c) {
        let score = 0;
        // Массив коэфициентов K всех линий между текущей точкой цены и всеми предыдущими экстремумами
        const kList = [];
        // Изза подобия треугольников подберем числа в координатах чтобы tan(Alpha) = K был примерно такой же
        // как если бы мы считали x координаты почестному
        const x1 = 0.01;
        const y1 = h;

        this.hExtremums.forEach((y0) => {
            // x0 - всегда 0
            const x0 = 0;

            // Из уравнения канонической прямой, чтобы вычислить K - угловой коэфициент
            // воспользуемся формулой (где 1 = x в формуле), если подставим вместо x = 1 то получим K
            const k = ((1 - x0) * (y1 - y0)) / (x1 - x0);
            kList.push(k);
        });

        // Карта кластирезаций
        // Для расчета сколько примерно одинаковых угловых коэфициентов есть
        const clustering = new Map();
        let score = 0;


        kList.forEach((k) => {
            // Округляем все k до точности 0.01
            const fixation = 10 ** 2;
            k = Math.round((k + Number.EPSILON) * fixation) / fixation;

            // Сохраняем k в Map, и првоеряем было ли такое же значение
            // Если было увеличиваем счетчик в кол-ве прямых с таким коэффициентом
            const next = (clustering.get(k) || 0) + 1;

            // Если очков больше 1, запишем максимальное значение в очки
            // Так получится на выходе самый большой кластер с одинаковыми коэфициантами k
            if (next > 1 && next > score) {
                score = next;
            }
            clustering.set(k, next);
        });

        // Нормализуем выходное значение
        return 1 - 1 / (1 + score);
        // return score;
    }
}