highcharts-indicators
Version:
Highstock plugin to add technical indicators to charts.
151 lines (128 loc) • 3.91 kB
JavaScript
/* global Highcharts module:true */
(function (factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory;
} else {
factory(Highcharts);
}
}(function (HC) {
'use strict';
/**
Each indicator requires mothods:
- getDefaultOptions() - returns object with default parameters, like period etc.
- getValues(chart, series, options, points) - returns array of calculated values for indicator
- getGraph(chart, series, options, values) - returns path, or columns as SVG elements to add.
Doesn't add to the chart via renderer!
**/
var merge = HC.merge,
isArray = HC.isArray,
minInArray = HC.Axis.prototype.minInArray,
maxInArray = HC.Axis.prototype.maxInArray;
HC.Indicator.prototype.ema = {
getDefaultOptions: function () {
return {
period: 14,
index: 0,
approximation: 'average'
};
},
getValues: function (chart, series, options, extraPoints) {
var utils = this.utils,
params = options.params,
period = params.period,
xVal = extraPoints[0].concat(series.processedXData || []), // #22
yVal = extraPoints[1].concat(series.processedYData || []), // #22
yValLen = yVal ? yVal.length : 0,
EMApercent = (2 / (period + 1)),
calEMA = 0,
range = 1,
xValue = xVal[0],
yValue = yVal[0],
EMA = [],
xData = [],
yData = [],
index = -1,
i, points,
EMAPoint;
// check period, if bigger than points length, skip
if (xVal.length <= period) {
return false;
}
// switch index for OHLC / Candlestick / Arearange
if (isArray(yVal[0])) {
index = params.index ? params.index : 0;
yValue = yVal[0][index];
}
// starting point
points = [[xValue, yValue]];
// accumulate first N-points
while (range !== period) {
utils.accumulateAverage(points, xVal, yVal, range, index);
range++;
}
// calculate value one-by-one for each perdio in visible data
for (i = range; i < yValLen; i++) {
EMAPoint = utils.populateAverage(points, xVal, yVal, i, EMApercent, calEMA, index);
EMA.push(EMAPoint);
xData.push(EMAPoint[0]);
yData.push(EMAPoint[1]);
calEMA = EMAPoint[1];
utils.accumulateAverage(points, xVal, yVal, i, index);
}
EMAPoint = utils.populateAverage(points, xVal, yVal, i, EMApercent, calEMA, index);
EMA.push(EMAPoint);
xData.push(EMAPoint[0]);
yData.push(EMAPoint[1]);
// registger extremes for axis;
options.yAxisMax = maxInArray(EMA);
options.yAxisMin = minInArray(EMA);
return {
values: EMA,
xData: xData,
yData: yData
};
},
getGraph: function (chart, series, options, values) {
var path = [],
attrs = {},
xAxis = series.xAxis,
yAxis = options.Axis = series.yAxis,
ema = values,
emaLen = ema.length,
emaX,
emaY,
i;
if (options.visible === false) {
return false;
}
options.styles = attrs = merge({
'stroke-width': 2,
stroke: 'red',
dashstyle: 'Dash'
}, options.styles);
path.push('M', xAxis.toPixels(ema[0][0]), yAxis.toPixels(ema[0][1]));
for (i = 0; i < emaLen; i++) {
emaX = ema[i][0];
emaY = ema[i][1];
path.push('L', xAxis.toPixels(emaX), yAxis.toPixels(emaY));
}
return [chart.renderer.path(path).attr(attrs)];
},
utils: {
accumulateAverage: function (points, xVal, yVal, i, index) {
var xValue = xVal[i],
yValue = index < 0 ? yVal[i] : yVal[i][index];
points.push([xValue, yValue]);
},
populateAverage: function (points, xVal, yVal, i, EMApercent, calEMA, index) {
var x = xVal[i - 1],
yValuePrev = index < 0 ? yVal[i - 2] : yVal[i - 2][index],
yValue = index < 0 ? yVal[i - 1] : yVal[i - 1][index],
prevPoint, y;
prevPoint = calEMA === 0 ? yValuePrev : calEMA;
y = ((yValue * EMApercent) + (prevPoint * (1 - EMApercent)));
return [x, y];
}
}
};
}));