"use strict";
var _ = require("underscore");
var Layer = require("../../layer/Layer");
var Arc = require("../../element/Arc");
const _default_config = {
input: "close",
outputPrefix: "_sma",
period: 50,
color: "orange"
};
/**
* Represents an EMA chart layer.
*
* @extends layer.Layer
* @memberof layer.indicator
*/
class ExponentialMovingAverageLayer extends Layer {
/**
* Instantiate ExponentialMovingAverageLayer
* @constructor
* @param {object} config
*/
constructor(config) {
config = _.extend({}, _default_config, config);
super(config);
this.output = this.outputPrefix + "" + this.period; // e.g. _sma50, _sma200, etc
this.minField = this.output;
this.maxField = this.output;
}
/**
* Precompute indicator fields using time series OHLCV data.
*
* This is invoked before draw().
* @param {timeseries.TimeSeriesData} data
*/
precompute(data) {
var data_arr = data.getRawData();
var field_map = data.getFieldMap();
var output_field = this.output;
var input_field = field_map[this.input];
var period = this.period;
var multiplier = 2.0 / (period + 1.0);
var queue = [], sum = 0.0;
var prev_ema;
for(var i = 0; i < data_arr.length; i++)
{
var dat = data_arr[i];
if(prev_ema)
{
var ema = (dat[input_field] || 1.0) * multiplier + prev_ema * (1.0 - multiplier);
dat[output_field] = ema;
prev_ema = ema;
}
else if(queue.length === period)
{
var ma = sum / period;
prev_ema = ma;
}
else
{
// Build up array to calculate initial ema values
queue.push(dat[input_field] || 1.0);
sum += (dat[input_field] || 1.0);
}
}
}
/**
* Render layer onto canvas
* @param {timeseries.TimeSeriesData} data
* @param {number} count
* @param {number} offset
* @param {valueToPixel} valueToPixel
* @param {indexToPixel} indexToPixel
*/
draw(data, count, offset, valueToPixel, indexToPixel) {
var context = this._getContext();
var field_map = data.getFieldMap();
var data_arr = data.getRawData();
this.elements = [];
var prev_arc = null;
for(var i = offset >= 0 ? offset : 0; i < offset + count && i < data_arr.length; i++)
{
var dat = data_arr[i];
var arc = new Arc(
this,
i,
dat[field_map.time],
dat[this.output],
prev_arc);
this.elements.push(arc);
arc.draw(context, valueToPixel, indexToPixel, this);
prev_arc = arc;
}
}
}
module.exports = ExponentialMovingAverageLayer;