JavaScript вычисление индикатора DMI, в чем ошибка

298
13 марта 2019, 16:00

Написал индикатор DMI по инструкции отсюда

Сам индикатор:

var DMI = function(period){
    this.period = period||14;
    this.upm = [];
    this.dwm = [];
    this.lastquote = null;
    this.PDI = [];
    this.MDI = [];
    this.EMA = new EMA(this.period);
    this.ATR = [];
}
DMI.prototype = {
    reset: function(){
        this.upm = [];
        this.dwm = [];
        this.lastquote = null;
        this.PDI = [];
        this.MDI = [];
        this.EMA = new EMA(this.period);
        this.TR = [];
        this.ATR = [];
    },
    append: function(quote){//Добавление очередной котировки с последующими вычислениями
        if (this.lastquote){
            var um = quote.high - this.lastquote.high; 
            var dm = this.lastquote.low - quote.low;
            //Вычисление истинного диапазона и среднего истинного диапазона ([url]http://berg.com.ua/indicators-overlays/atr/[/url])
            this.TR.push(Math.max((quote.high - quote.low),(quote.high - this.lastquote.close),(this.lastquote.close - quote.low)));
            if (this.TR.length >= this.period){
                if (this.ATR.length == 0){
                    this.ATR.push(this.EMA.average(this.TR))
                }else{
                    this.ATR.push((this.ATR[this.ATR.length - 1]*(this.period - 1) + this.TR[this.TR.length - 1])/this.period)
                }
            }

            //Вычисление +DI (PDI) и -DI (MDI)
            if (um > dm && um > 0){
                this.upm.push(um);
            }else{
                this.upm.push(0);
            }
            if (dm > um && dm > 0){
                this.dwm.push(dm);
            }else{
                this.dwm.push(0);
            }
            if (this.upm.length >= this.period){
                this.PDI.push(100*this.EMA.getFromPrices(this.upm)[this.upm.length - this.period]/this.ATR[this.ATR.length - 1]);
                this.MDI.push(100*this.EMA.getFromPrices(this.dwm)[this.dwm.length - this.period]/this.ATR[this.ATR.length - 1]);
            }

            // Вычисление ADX
            var vals = [];
            for (var i = 0; i < this.PDI.length; i++){
                vals.push(100*Math.abs(this.PDI[i]-this.MDI[i])/(this.PDI[i]+this.MDI[i]))
            }
            var ADX = null;
            if (vals.length >= this.period){
                ADX = this.EMA.getFromPrices(vals)[vals.length - this.period];
            }
            this.lastquote = quote;
            return {"PDI":this.PDI[this.PDI.length - 1]||null, "MDI":this.MDI[this.MDI.length - 1]||null, "ADX":ADX};
        }else{
            this.lastquote = quote;
            return null;
        }
    }, 

    // Вывод значений индикатора на конкретных котировках
    getFromQuotes: function(quotes,outtype){
        var DMI = [];
        this.reset();
        for (var i = 0; i<quotes.length; i++){
            var tmp = (this.append(quotes[i]));
            if (tmp){
                DMI.push(tmp);
            }
        }
        if (outtype){
            return DMI;
        }else{
            var PDI = [];
            var MDI = [];
            var ADX = [];
            for (var i = 0; i < DMI.length; i++){
                PDI.push(DMI[i].PDI);
                MDI.push(DMI[i].MDI);
                ADX.push(DMI[i].ADX);
            }
            return {"PDI":PDI, "MDI":MDI, "ADX":ADX};
        }
    } 
}

Вспомогательный индикатор EMA:

var EMA = function (period) {
    this.period = period || 10;
}
EMA.prototype = {
    getFromDeltas: function (deltas, initialprice) {
        if (deltas.length <= this.period) {
            throw ReferenceError('The number of deltas is not enough for such a period: ' + this.period.toString())
        }
        var price = initialprice || 0;
        var prices = [price];
        for (var i = 0; i < deltas.length; i++) {
            price += deltas[i].value || deltas[i];
            prices.push(price);
        }
        return this.getFromPrices(prices);
    },
    getFromQuotes: function (quotes) {
        if (quotes.length <= this.period) {
            throw ReferenceError('The number of quotes is not enough for such a period: ' + this.period.toString())
        }
        var initialprice = quotes[0].open;
        var deltas = [];
        for (var i = 0; i < quotes.length - 1; i++) {
            deltas.push(quotes[i + 1].open - quotes[i].open);
        }
        deltas.push(quotes[quotes.length - 1].close - quotes[quotes.length - 1].open);
        return this.getFromDeltas(deltas, initialprice);
    },
    getFromPrices: function (prices) {
        if (prices.length < this.period) {
            throw ReferenceError('The number of prices is not enough for such a period: ' + this.period.toString())
        }
        var a = 2 / (this.period + 1);
        var EMA = [this.average(prices.slice(0, this.period))];
        for (var i = this.period; i < prices.length; i++) {
            EMA.push(a * (prices[i] - EMA[i - this.period]) + EMA[i - this.period]);
        }
        return EMA;
    },
    average: function (a) {
        var sum = 0;
        for (var i = 0; i < a.length; i++) {
            sum = sum + a[i];
        }
        return sum / a.length
    }
}

После вычислений на различных котировках значения не совпадают с реальными (которые на торговых платформах)

Пробежался с отладчиком, и все равно ошибок не нашел

Котировки использую в виде

[{
    "open": 1.14178,
    "high": 1.14203,
    "low": 1.141695,
    "close": 1.14203,
    "created_at": "2018-10-27T00:00:00.000000Z"
}, {
    "open": 1.14203,
    "high": 1.142045,
    "low": 1.14189,
    "close": 1.141915,
    "created_at": "2018-10-27T00:01:00.000000Z"
}
//, и так далее, по возрастанию времени
]

В чем может быть ошибка?

Заранее спасибо

Answer 1

Не совпадало, потому что на торговых платформах для вычисления вспомогательных EMA сглаживающие коэффициенты брали, как 1/period, а я не менял и оставлял, как 2/(period + 1)

READ ALSO
Перебрать все элементы коллекции

Перебрать все элементы коллекции

Есть такой код на VBScript

166
Как правильно спарсить массив из JSON?

Как правильно спарсить массив из JSON?

Нужно вывести на сайт 10 последних транзакций на кошелёкЗначения берутся отсюда: https://api

284
Поворот на 180 градусов со сменой Div

Поворот на 180 градусов со сменой Div

Добрый день адепты программирования, начинающему верстальщику нужна ваша помощь!!!

177
Как работает анимация слоев в этой верстке? [закрыт]

Как работает анимация слоев в этой верстке? [закрыт]

Подскажите пожалуйста что движет этой анимацией слоев? В отладчике не какие значения не меняются + js не используетсяСледовательно вопрос...

173