all files / technicalindicators/lib/directionalmovement/ ADX.js

14.29% Statements 11/77
0% Branches 0/20
0% Functions 0/6
15.07% Lines 11/73
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136                                                                                                                                                                                                                                                         
/**
 * Created by AAravindan on 5/8/16.
 */
/**
 * Created by AAravindan on 5/4/16.
 */
"use strict"
const MinusDM        = require('./MinusDM');
const PlusDM         = require('./PlusDM');
const TrueRange      = require('./TrueRange');
const SMA            = require('../moving_averages/SMA');
const WEMA            = require('../moving_averages/WEMA');
 
let ADX;
 
let validateInput = function(input) {
  return input;
};
 
module.exports = ADX = function(input) {
 
  var lows = input.low;
  var highs = input.high;
  var closes = input.close;
  var period = input.period;
 
  var plusDM = new PlusDM({
    high: [],
    low : []
  });
 
  var minusDM = new MinusDM({
    high: [],
    low : []
  });
 
  var emaPDM = new WEMA({period: period, values:[], format : (v) => {return v}});
  var emaMDM = new WEMA({period: period, values:[], format : (v) => {return v}});
  var emaTR  = new WEMA({period: period, values:[], format : (v) => {return v}});
  var smaDX  = new SMA({period: period, values:[], format : (v) => {return v}});
 
  var tr    = new TrueRange({
    low : [],
    high: [],
    close: [],
  });
 
  if(!((lows.length === highs.length) && (highs.length === closes.length) )){
    throw ('Inputs(low,high, close) not of equal size');
  }
 
  if(!validateInput) {
    throw 'Invalid Input'
  };
 
 
  this.result = [];
 
  this.generator = (function* (){
    var tick = yield;
    var index = 0;
    var lastATR,lastAPDM,lastAMDM,lastPDI,lastMDI,lastDX,smoothedDX;
    lastATR = 0;
    lastAPDM = 0;
    lastAMDM = 0;
    while (true) {
      let calcTr = tr.nextValue(tick);
      let calcPDM = plusDM.nextValue(tick);
      let calcMDM = minusDM.nextValue(tick);
      if(calcTr!==undefined){
        if(index < period){
          lastATR  = lastATR + calcTr;
          lastAPDM = lastAPDM + calcPDM;
          lastAMDM = lastAMDM + calcMDM;
          index++;
          tick = yield
          continue;
        }
        else if(index === period) {
          lastPDI = (lastAPDM) * 100 / lastATR;
          lastMDI = (lastAMDM) * 100 / lastATR;
          index++;
        }
        else {
          console.log(lastATR,calcTr);
          lastATR =  (lastATR - (lastATR / period)) + calcTr;
          lastAPDM = (lastAPDM - (lastAPDM / period)) + calcPDM;
          lastAMDM = (lastAMDM - (lastAMDM / period)) + calcMDM;
          lastPDI = (lastAPDM) * 100 / lastATR;
          lastMDI = (lastAMDM) * 100 / lastATR;
        }
        lastDX = (Math.abs(lastPDI - lastMDI) / (lastPDI + lastMDI)) * 100;
        if(!smoothedDX){
          smoothedDX = smaDX.nextValue(lastDX)
        }
        else{
          smoothedDX = ((smoothedDX * (period-1)) + lastDX)/ period;
        }
      }
      tick = yield smoothedDX;
    }
  })();
 
  this.generator.next();
 
  lows.forEach((tick,index) => {
    var result = this.generator.next({
      high : highs[index],
      low  : lows[index],
      close : closes[index]
    });
    if(result.value){
      this.result.push(result.value);
    }
  });
};
 
ADX.calculate = function(input) {
  if(input.reversedInput) {
    input.high.reverse();
    input.low.reverse();
    input.close.reverse();
  }
  let result = (new ADX(input)).result;
  input.reversedInput ? result.reverse():undefined;
  return result;
};
 
ADX.prototype.getResult = function () {
  return this.result;
};
 
ADX.prototype.nextValue = function (price) {
  return this.generator.next(price).value;
};