Large diffs are not rendered by default.

@@ -0,0 +1,11 @@
/*
Highcharts JS v6.0.4 (2017-12-15)
Money Flow Index indicator for Highstock
(c) 2010-2017 Grzegorz Blachliski
License: www.highcharts.com/license
*/
(function(e){"object"===typeof module&&module.exports?module.exports=e:e(Highcharts)})(function(e){(function(e){function p(b){return b.reduce(function(c,b){return c+b})}function m(b){return(b[1]+b[2]+b[3])/3}var u=e.isArray;e.seriesType("mfi","sma",{name:"Money Flow Index (14)",params:{period:14,volumeSeriesID:"volume",decimals:4}},{getValues:function(b,c){var d=c.period,n=b.xData,g=b.yData,v=g?g.length:0,w=c.decimals,h=1,a=b.chart.get(c.volumeSeriesID);b=a&&a.yData;var q=[],r=[],t=[],k=[],l=[],f;
if(!a)return e.error("Series "+c.volumeSeriesID+" not found! Check `volumeSeriesID`.",!0);if(n.length<=d||!u(g[0])||4!==g[0].length||!b)return!1;for(c=m(g[h]);h<d+1;)a=c,c=m(g[h]),a=c>=a?!0:!1,f=c*b[h],k.push(a?f:0),l.push(a?0:f),h++;for(d=h-1;d<v;d++)d>h-1&&(k.shift(),l.shift(),a=c,c=m(g[d]),a=c>a?!0:!1,f=c*b[d],k.push(a?f:0),l.push(a?0:f)),a=p(l),f=p(k),a=f/a,a=parseFloat((100-100/(1+a)).toFixed(w)),q.push([n[d],a]),r.push(n[d]),t.push(a);return{values:q,xData:r,yData:t}}})})(e)});
@@ -0,0 +1,211 @@
/**
* @license Highcharts JS v6.0.4 (2017-12-15)
*
* Money Flow Index indicator for Highstock
*
* (c) 2010-2017 Grzegorz Blachliński
*
* License: www.highcharts.com/license
*/
'use strict';
(function(factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory;
} else {
factory(Highcharts);
}
}(function(Highcharts) {
(function(H) {




var isArray = H.isArray;

// Utils:
function sumArray(array) {

return array.reduce(function(prev, cur) {
return prev + cur;
});
}

function toFixed(a, n) {
return parseFloat(a.toFixed(n));
}

function calculateTypicalPrice(point) {
return (point[1] + point[2] + point[3]) / 3;
}

function calculateRawMoneyFlow(typicalPrice, volume) {
return typicalPrice * volume;
}
/**
* The MFI series type.
*
* @constructor seriesTypes.mfi
* @augments seriesTypes.sma
*/
H.seriesType('mfi', 'sma',

/**
* Money Flow Index. This series requires `linkedTo`
* option to be set and should be loaded after `stock/indicators/indicators.js` file.
*
* @extends {plotOptions.sma}
* @product highstock
* @sample {highstock} stock/indicators/mfi
* Money Flow Index Indicator
* @since 6.0.0
* @optionparent plotOptions.mfi
*/

{

name: 'Money Flow Index (14)',
/**
* @excluding index
*/
params: {
period: 14,
/**
* The id of volume series which is mandatory.
* For example using OHLC data, volumeSeriesID='volume' means
* the indicator will be calculated using OHLC and volume values.
*
* @type {String}
* @since 6.0.0
* @product highstock
*/
volumeSeriesID: 'volume',
/**
* Number of maximum decimals that are used in MFI calculations.
*
* @type {Number}
* @since 6.0.0
* @product highstock
*/
decimals: 4

}
}, {
getValues: function(series, params) {
var period = params.period,
xVal = series.xData,
yVal = series.yData,
yValLen = yVal ? yVal.length : 0,
decimals = params.decimals,
// MFI starts calculations from the second point
// Cause we need to calculate change between two points
range = 1,
volumeSeries = series.chart.get(params.volumeSeriesID),
yValVolume = volumeSeries && volumeSeries.yData,
MFI = [],
isUp = false,
xData = [],
yData = [],
positiveMoneyFlow = [],
negativeMoneyFlow = [],
newTypicalPrice,
oldTypicalPrice,
rawMoneyFlow,
negativeMoneyFlowSum,
positiveMoneyFlowSum,
moneyFlowRatio,
MFIPoint, i;

if (!volumeSeries) {
return H.error(
'Series ' +
params.volumeSeriesID +
' not found! Check `volumeSeriesID`.',
true
);
}

// MFI requires high low and close values
if ((xVal.length <= period) || !isArray(yVal[0]) || yVal[0].length !== 4 || !yValVolume) {
return false;
}
// Calculate first typical price
newTypicalPrice = calculateTypicalPrice(yVal[range]);
// Accumulate first N-points
while (range < period + 1) {
// Calculate if up or down
oldTypicalPrice = newTypicalPrice;
newTypicalPrice = calculateTypicalPrice(yVal[range]);
isUp = newTypicalPrice >= oldTypicalPrice ? true : false;
// Calculate raw money flow
rawMoneyFlow = calculateRawMoneyFlow(newTypicalPrice, yValVolume[range]);
// Add to array
positiveMoneyFlow.push(isUp ? rawMoneyFlow : 0);
negativeMoneyFlow.push(isUp ? 0 : rawMoneyFlow);
range++;
}
for (i = range - 1; i < yValLen; i++) {
if (i > range - 1) {
// Remove first point from array
positiveMoneyFlow.shift();
negativeMoneyFlow.shift();
// Calculate if up or down
oldTypicalPrice = newTypicalPrice;
newTypicalPrice = calculateTypicalPrice(yVal[i]);
isUp = newTypicalPrice > oldTypicalPrice ? true : false;
// Calculate raw money flow
rawMoneyFlow = calculateRawMoneyFlow(newTypicalPrice, yValVolume[i]);
// Add to array
positiveMoneyFlow.push(isUp ? rawMoneyFlow : 0);
negativeMoneyFlow.push(isUp ? 0 : rawMoneyFlow);
}

// Calculate sum of negative and positive money flow:
negativeMoneyFlowSum = sumArray(negativeMoneyFlow);
positiveMoneyFlowSum = sumArray(positiveMoneyFlow);

moneyFlowRatio = positiveMoneyFlowSum / negativeMoneyFlowSum;
MFIPoint = toFixed(100 - (100 / (1 + moneyFlowRatio)), decimals);
MFI.push([xVal[i], MFIPoint]);
xData.push(xVal[i]);
yData.push(MFIPoint);
}

return {
values: MFI,
xData: xData,
yData: yData
};
}
}
);

/**
* A `MFI` series. If the [type](#series.mfi.type) option is not
* specified, it is inherited from [chart.type](#chart.type).
*
* For options that apply to multiple series, it is recommended to add
* them to the [plotOptions.series](#plotOptions.series) options structure.
* To apply to all series of this specific type, apply it to [plotOptions.
* mfi](#plotOptions.mfi).
*
* @type {Object}
* @since 6.0.0
* @extends series,plotOptions.mfi
* @excluding data,dataParser,dataURL
* @product highstock
* @apioption series.mfi
*/

/**
* An array of data points for the series. For the `mfi` series type,
* points are calculated dynamically.
*
* @type {Array<Object|Array>}
* @since 6.0.0
* @extends series.line.data
* @product highstock
* @apioption series.mfi.data
*/

}(Highcharts));
}));
@@ -0,0 +1,11 @@
/*
Highcharts JS v6.0.4 (2017-12-15)
Indicator series type for Highstock
(c) 2010-2017 Sebastian Bochan
License: www.highcharts.com/license
*/
(function(a){"object"===typeof module&&module.exports?module.exports=a:a(Highcharts)})(function(a){(function(a){function m(n,b,a,e,c){a=a[e-1][3]-a[e-c-1][3];b=b[e-1];n.shift();return[b,a]}var p=a.isArray;a=a.seriesType;a("momentum","sma",{name:"Momentum (14)",params:{period:14}},{getValues:function(a,b){b=b.period;var f=a.xData,e=(a=a.yData)?a.length:0,c=f[0],g=[],h=[],k=[],l,d;if(f.length<=b||!p(a[0]))return!1;l=[[c,a[0][3]]];for(c=b+1;c<e;c++)d=m(l,f,a,c,b,void 0),g.push(d),h.push(d[0]),k.push(d[1]);
d=m(l,f,a,c,b,void 0);g.push(d);h.push(d[0]);k.push(d[1]);return{values:g,xData:h,yData:k}}})})(a)});
@@ -0,0 +1,132 @@
/**
* @license Highcharts JS v6.0.4 (2017-12-15)
*
* Indicator series type for Highstock
*
* (c) 2010-2017 Sebastian Bochan
*
* License: www.highcharts.com/license
*/
'use strict';
(function(factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory;
} else {
factory(Highcharts);
}
}(function(Highcharts) {
(function(H) {

var isArray = H.isArray,
seriesType = H.seriesType;

function populateAverage(points, xVal, yVal, i, period) {
var mmY = yVal[i - 1][3] - yVal[i - period - 1][3],
mmX = xVal[i - 1];

points.shift(); // remove point until range < period

return [mmX, mmY];
}

/**
* The Momentum series type.
*
* @constructor seriesTypes.momentum
* @augments seriesTypes.sma
*/
seriesType('momentum', 'sma',
/**
* Momentum. This series requires `linkedTo` option to be set.
*
* @extends {plotOptions.sma}
* @product highstock
* @sample {highstock} stock/indicators/momentum Momentum indicator
* @since 6.0.0
* @optionparent plotOptions.momentum
*/
{
name: 'Momentum (14)',
params: {
period: 14
}
}, {
getValues: function(series, params) {
var period = params.period,
xVal = series.xData,
yVal = series.yData,
yValLen = yVal ? yVal.length : 0,
xValue = xVal[0],
yValue = yVal[0],
MM = [],
xData = [],
yData = [],
index,
i,
points,
MMPoint;

if (xVal.length <= period) {
return false;
}

// Switch index for OHLC / Candlestick / Arearange
if (isArray(yVal[0])) {
yValue = yVal[0][3];
} else {
return false;
}
// Starting point
points = [
[xValue, yValue]
];


// Calculate value one-by-one for each perdio in visible data
for (i = (period + 1); i < yValLen; i++) {
MMPoint = populateAverage(points, xVal, yVal, i, period, index);
MM.push(MMPoint);
xData.push(MMPoint[0]);
yData.push(MMPoint[1]);
}

MMPoint = populateAverage(points, xVal, yVal, i, period, index);
MM.push(MMPoint);
xData.push(MMPoint[0]);
yData.push(MMPoint[1]);

return {
values: MM,
xData: xData,
yData: yData
};
}
});

/**
* A `Momentum` series. If the [type](#series.momentum.type) option is not
* specified, it is inherited from [chart.type](#chart.type).
*
* For options that apply to multiple series, it is recommended to add
* them to the [plotOptions.series](#plotOptions.series) options structure.
* To apply to all series of this specific type, apply it to
* [plotOptions.momentum](#plotOptions.momentum).
*
* @type {Object}
* @since 6.0.0
* @extends series,plotOptions.momentum
* @excluding data,dataParser,dataURL
* @product highstock
* @apioption series.momentum
*/

/**
* @type {Array<Object|Array>}
* @since 6.0.0
* @extends series.sma.data
* @product highstock
* @apioption series.momentum.data
*/

}(Highcharts));
}));
@@ -0,0 +1,370 @@
/**
* @license Highcharts JS v6.0.4 (2017-12-15)
*
* Indicator series type for Highstock
*
* (c) 2010-2017 Paweł Fus
*
* License: www.highcharts.com/license
*/
'use strict';
(function(factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory;
} else {
factory(Highcharts);
}
}(function(Highcharts) {
(function(H) {


var each = H.each,
defined = H.defined,
isArray = H.isArray,
SMA = H.seriesTypes.sma;

function destroyExtraLabels(point, functionName) {
var props = point.series.pointArrayMap,
prop,
i = props.length;

SMA.prototype.pointClass.prototype[functionName].call(point);

while (i--) {
prop = 'dataLabel' + props[i];
// S4 dataLabel could be removed by parent method:
if (point[prop] && point[prop].element) {
point[prop].destroy();
}
point[prop] = null;
}
}

H.seriesType('pivotpoints', 'sma',
/**
* Pivot points indicator. This series requires `linkedTo`
* option to be set and should be loaded after `stock/indicators/indicators.js` file.
*
* @extends {plotOptions.sma}
* @product highstock
* @sample {highstock} stock/indicators/pivot-points
* Pivot points
* @since 6.0.0
* @optionparent plotOptions.pivotpoints
*/
{
name: 'Pivot Points (28)',
/**
* @excluding index
*/
params: {
period: 28,
/**
* Algorithm used to calculate ressistance and support lines based on pivot points.
* Implemented algorithms: `'standard'`, `'fibonacci'` and `'camarilla'`
*
* @type {String}
* @since 6.0.0
* @product highstock
*/
algorithm: 'standard'
},
marker: {
enabled: false
},
enableMouseTracking: false,
dataLabels: {
enabled: true,
format: '{point.pivotLine}'
},
dataGrouping: {
approximation: 'averages'
}
}, {
pointArrayMap: ['R4', 'R3', 'R2', 'R1', 'P', 'S1', 'S2', 'S3', 'S4'],
pointValKey: 'P',
toYData: function(point) {
return [point.P]; // The rest should not affect extremes
},
translate: function() {
var indicator = this;

SMA.prototype.translate.apply(indicator);

each(indicator.points, function(point) {
each(indicator.pointArrayMap, function(value) {
if (defined(point[value])) {
point['plot' + value] = indicator.yAxis.toPixels(
point[value],
true
);
}
});
});

// Pivot points are rendered as horizontal lines
// And last point start not from the next one (as it's the last one)
// But from the approximated last position in a given range
indicator.plotEndPoint = indicator.xAxis.toPixels(
indicator.endPoint,
true
);
},
getGraphPath: function(points) {
var indicator = this,
pointsLength = points.length,
allPivotPoints = [
[],
[],
[],
[],
[],
[],
[],
[],
[]
],
path = [],
endPoint = indicator.plotEndPoint,
pointArrayMapLength = indicator.pointArrayMap.length,
position,
point,
i;

while (pointsLength--) {
point = points[pointsLength];
for (i = 0; i < pointArrayMapLength; i++) {
position = indicator.pointArrayMap[i];

if (defined(point[position])) {
allPivotPoints[i].push({
// Start left:
plotX: point.plotX,
plotY: point['plot' + position],
isNull: false
}, {
// Go to right:
plotX: endPoint,
plotY: point['plot' + position],
isNull: false
}, {
// And add null points in path to generate breaks:
plotX: endPoint,
plotY: null,
isNull: true
});
}
}
endPoint = point.plotX;
}

each(allPivotPoints, function(pivotPoints) {
path = path.concat(
SMA.prototype.getGraphPath.call(indicator, pivotPoints)
);
});

return path;
},
drawDataLabels: function() {
var indicator = this,
pointMapping = indicator.pointArrayMap,
currentLabel,
pointsLength,
point,
i;

if (indicator.options.dataLabels.enabled) {
pointsLength = indicator.points.length;

// For every Ressitance/Support group we need to render labels
// Add one more item, which will just store dataLabels from previous iteration
each(pointMapping.concat([false]), function(position, k) {
i = pointsLength;
while (i--) {
point = indicator.points[i];

if (!position) {
// Store S4 dataLabel too:
point['dataLabel' + pointMapping[k - 1]] = point.dataLabel;
} else {
point.y = point[position];
point.pivotLine = position;
point.plotY = point['plot' + position];
currentLabel = point['dataLabel' + position];

// Store previous label
if (k) {
point['dataLabel' + pointMapping[k - 1]] = point.dataLabel;
}

point.dataLabel = currentLabel = currentLabel && currentLabel.element ? currentLabel : null;
}
}
SMA.prototype.drawDataLabels.apply(indicator, arguments);
});
}
},
getValues: function(series, params) {
var period = params.period,
xVal = series.xData,
yVal = series.yData,
yValLen = yVal ? yVal.length : 0,
placement = this[params.algorithm + 'Placement'],
PP = [], // 0- from, 1- to, 2- R1, 3- R2, 4- pivot, 5- S1, 6- S2 etc.
endTimestamp,
xData = [],
yData = [],
slicedXLen,
slicedX,
slicedY,
lastPP,
pivot,
avg,
i;

// Pivot Points requires high, low and close values
if (
xVal.length < period ||
!isArray(yVal[0]) ||
yVal[0].length !== 4
) {
return false;
}

for (i = period + 1; i <= yValLen + period; i += period) {
slicedX = xVal.slice(i - period - 1, i);
slicedY = yVal.slice(i - period - 1, i);

slicedXLen = slicedX.length;

endTimestamp = slicedX[slicedXLen - 1];

pivot = this.getPivotAndHLC(slicedY);
avg = placement(pivot);

lastPP = PP.push(
[endTimestamp]
.concat(avg)
);

xData.push(endTimestamp);
yData.push(PP[lastPP - 1].slice(1));
}

// We don't know exact position in ordinal axis
// So we use simple logic:
// Get first point in last range, calculate visible average range and multiply by period
this.endPoint = slicedX[0] +
((endTimestamp - slicedX[0]) / slicedXLen) * period;

return {
values: PP,
xData: xData,
yData: yData
};
},
getPivotAndHLC: function(values) {
var high = -Infinity,
low = Infinity,
close = values[values.length - 1][3],
pivot;
each(values, function(p) {
high = Math.max(high, p[1]);
low = Math.min(low, p[2]);
});
pivot = (high + low + close) / 3;

return [pivot, high, low, close];
},
standardPlacement: function(values) {
var diff = values[1] - values[2],
avg = [
null,
null,
values[0] + diff,
values[0] * 2 - values[2],
values[0],
values[0] * 2 - values[1],
values[0] - diff,
null,
null
];

return avg;
},
camarillaPlacement: function(values) {
var diff = values[1] - values[2],
avg = [
values[3] + diff * 1.5,
values[3] + diff * 1.25,
values[3] + diff * 1.1666,
values[3] + diff * 1.0833,
values[0],
values[3] - diff * 1.0833,
values[3] - diff * 1.1666,
values[3] - diff * 1.25,
values[3] - diff * 1.5
];

return avg;
},
fibonacciPlacement: function(values) {
var diff = values[1] - values[2],
avg = [
null,
values[0] + diff,
values[0] + diff * 0.618,
values[0] + diff * 0.382,
values[0],
values[0] - diff * 0.382,
values[0] - diff * 0.618,
values[0] - diff,
null
];

return avg;
}
}, {
// Destroy labels:
// This method is called when cropping data:
destroyElements: function() {
destroyExtraLabels(this, 'destroyElements');
},
// This method is called when removing points, e.g. series.update()
destroy: function() {
destroyExtraLabels(this, 'destroyElements');
}
}
);

/**
* A pivot points indicator. If the [type](#series.pivotpoints.type) option is not
* specified, it is inherited from [chart.type](#chart.type).
*
* For options that apply to multiple series, it is recommended to add
* them to the [plotOptions.series](#plotOptions.series) options structure.
* To apply to all series of this specific type, apply it to [plotOptions.
* pivotpoints](#plotOptions.pivotpoints).
*
* @type {Object}
* @since 6.0.0
* @extends series,plotOptions.pivotpoints
* @excluding data,dataParser,dataURL
* @product highstock
* @apioption series.pivotpoints
*/

/**
* An array of data points for the series. For the `pivotpoints` series type,
* points are calculated dynamically.
*
* @type {Array<Object|Array>}
* @since 6.0.0
* @extends series.line.data
* @product highstock
* @apioption series.pivotpoints.data
*/

}(Highcharts));
}));
@@ -0,0 +1,298 @@
/**
* @license Highcharts JS v6.0.4 (2017-12-15)
*
* Indicator series type for Highstock
*
* (c) 2010-2017 Paweł Fus
*
* License: www.highcharts.com/license
*/
'use strict';
(function(factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory;
} else {
factory(Highcharts);
}
}(function(Highcharts) {
(function(H) {


var each = H.each,
merge = H.merge,
isArray = H.isArray,
SMA = H.seriesTypes.sma;

H.seriesType('priceenvelopes', 'sma',
/**
* Price envelopes indicator based on [SMA](#plotOptions.sma) calculations. This series requires `linkedTo`
* option to be set and should be loaded after `stock/indicators/indicators.js` file.
*
* @extends {plotOptions.sma}
* @product highstock
* @sample {highstock} stock/indicators/price-envelopes
* Price envelopes
* @since 6.0.0
* @optionparent plotOptions.priceenvelopes
*/
{
name: 'Price envelopes (20, 0.1, 0.1)',
marker: {
enabled: false
},
tooltip: {
/**
* The HTML of the point's line in the tooltip. Variables are enclosed
* by curly brackets. Available variables are point.x, point.y, series.
* name and series.color and other properties on the same form. Furthermore,
* point.y can be extended by the `tooltip.valuePrefix` and `tooltip.
* valueSuffix` variables. This can also be overridden for each series,
* which makes it a good hook for displaying units.
*
* In styled mode, the dot is colored by a class name rather
* than the point color.
*
* @type {String}
* @sample {highcharts} highcharts/tooltip/pointformat/ A different point format with value suffix
* @sample {highmaps} maps/tooltip/format/ Format demo
* @default
* <span style="color:{point.color}">\u25CF</span> <b> {series.name}</b><br/>
* Top: {point.top}<br/>
* Middle: {point.middle}<br/>
* Bottom: {point.bottom}<br/>
*/
pointFormat: '<span style="color:{point.color}">\u25CF</span>' +
'<b> {series.name}</b><br/>' +
'Top: {point.top}<br/>' +
'Middle: {point.middle}<br/>' +
'Bottom: {point.bottom}<br/>'
},
params: {
period: 20,
/**
* Percentage above the moving average that should be displayed.
* 0.1 means 110%. Relative to the calculated value.
*
* @type {Number}
* @since 6.0.0
* @product highstock
*/
topBand: 0.1,
/**
* Percentage below the moving average that should be displayed.
* 0.1 means 90%. Relative to the calculated value.
*
* @type {Number}
* @since 6.0.0
* @product highstock
*/
bottomBand: 0.1
},
/**
* Bottom line options.
*
* @since 6.0.0
* @product highstock
*/
bottomLine: {
styles: {
/**
* Pixel width of the line.
*
* @type {Number}
* @since 6.0.0
* @product highstock
*/
lineWidth: 1,
/**
* Color of the line.
* If not set, it's inherited from [plotOptions.priceenvelopes.color](#plotOptions.priceenvelopes.color).
*
* @type {String}
* @since 6.0.0
* @product highstock
*/
lineColor: undefined
}
},
/**
* Top line options.
*
* @extends {plotOptions.priceenvelopes.bottomLine}
* @since 6.0.0
* @product highstock
*/
topLine: {
styles: {
lineWidth: 1
}
},
dataGrouping: {
approximation: 'averages'
}
}, /** @lends Highcharts.Series.prototype */ {
pointArrayMap: ['top', 'middle', 'bottom'],
parallelArrays: ['x', 'y', 'top', 'bottom'],
pointValKey: 'middle',
init: function() {
SMA.prototype.init.apply(this, arguments);

// Set default color for lines:
this.options = merge({
topLine: {
styles: {
lineColor: this.color
}
},
bottomLine: {
styles: {
lineColor: this.color
}
}
}, this.options);
},
toYData: function(point) {
return [point.top, point.middle, point.bottom];
},
translate: function() {
var indicator = this,
translatedEnvelopes = ['plotTop', 'plotMiddle', 'plotBottom'];

SMA.prototype.translate.apply(indicator);

each(indicator.points, function(point) {
each([point.top, point.middle, point.bottom], function(value, i) {
if (value !== null) {
point[translatedEnvelopes[i]] = indicator.yAxis.toPixels(value, true);
}
});
});
},
drawGraph: function() {
var indicator = this,
middleLinePoints = indicator.points,
pointsLength = middleLinePoints.length,
middleLineOptions = indicator.options,
middleLinePath = indicator.graph,
gappedExtend = {
options: {
gapSize: middleLineOptions.gapSize
}
},
deviations = [
[],
[]
], // top and bottom point place holders
point;

// Generate points for top and bottom lines:
while (pointsLength--) {
point = middleLinePoints[pointsLength];
deviations[0].push({
plotX: point.plotX,
plotY: point.plotTop,
isNull: point.isNull
});
deviations[1].push({
plotX: point.plotX,
plotY: point.plotBottom,
isNull: point.isNull
});
}

// Modify options and generate lines:
each(['topLine', 'bottomLine'], function(lineName, i) {
indicator.points = deviations[i];
indicator.options = merge(middleLineOptions[lineName].styles, gappedExtend);
indicator.graph = indicator['graph' + lineName];
SMA.prototype.drawGraph.call(indicator);

// Now save lines:
indicator['graph' + lineName] = indicator.graph;
});

// Restore options and draw a middle line:
indicator.points = middleLinePoints;
indicator.options = middleLineOptions;
indicator.graph = middleLinePath;
SMA.prototype.drawGraph.call(indicator);
},
getValues: function(series, params) {
var period = params.period,
topPercent = params.topBand,
botPercent = params.bottomBand,
xVal = series.xData,
yVal = series.yData,
yValLen = yVal ? yVal.length : 0,
PE = [], // 0- date, 1-top line, 2-middle line, 3-bottom line
ML, TL, BL, // middle line, top line and bottom line
date,
xData = [],
yData = [],
slicedX,
slicedY,
point,
i;

// Price envelopes requires close value
if (xVal.length < period || !isArray(yVal[0]) || yVal[0].length !== 4) {
return false;
}

for (i = period; i <= yValLen; i++) {
slicedX = xVal.slice(i - period, i);
slicedY = yVal.slice(i - period, i);

point = SMA.prototype.getValues.call(this, {
xData: slicedX,
yData: slicedY
}, params);

date = point.xData[0];
ML = point.yData[0];
TL = ML * (1 + topPercent);
BL = ML * (1 - botPercent);
PE.push([date, TL, ML, BL]);
xData.push(date);
yData.push([TL, ML, BL]);
}

return {
values: PE,
xData: xData,
yData: yData
};
}
}
);

/**
* A price envelopes indicator. If the [type](#series.priceenvelopes.type) option is not
* specified, it is inherited from [chart.type](#chart.type).
*
* For options that apply to multiple series, it is recommended to add
* them to the [plotOptions.series](#plotOptions.series) options structure.
* To apply to all series of this specific type, apply it to [plotOptions.
* priceenvelopes](#plotOptions.priceenvelopes).
*
* @type {Object}
* @since 6.0.0
* @extends series,plotOptions.priceenvelopes
* @excluding data,dataParser,dataURL
* @product highstock
* @apioption series.priceenvelopes
*/

/**
* An array of data points for the series. For the `priceenvelopes` series type,
* points are calculated dynamically.
*
* @type {Array<Object|Array>}
* @since 6.0.0
* @extends series.line.data
* @product highstock
* @apioption series.priceenvelopes.data
*/

}(Highcharts));
}));
@@ -0,0 +1,12 @@
/*
Highcharts JS v6.0.4 (2017-12-15)
Parabolic SAR Indicator for Highstock
(c) 2010-2017 Grzegorz Blachliski
License: www.highcharts.com/license
*/
(function(f){"object"===typeof module&&module.exports?module.exports=f:f(Highcharts)})(function(f){(function(f){f.seriesType("psar","sma",{name:"PSAR",lineWidth:0,marker:{enabled:!0},states:{hover:{lineWidthPlus:0}},params:{initialAccelerationFactor:.02,maxAccelerationFactor:.2,increment:.02,index:2,decimals:4}},{getValues:function(c,d){var f=c.xData;c=c.yData;var e=c[0][1],x=d.maxAccelerationFactor,y=d.increment,z=d.initialAccelerationFactor,b=c[0][2],r=d.decimals,g=d.index,t=[],u=[],v=[],k=1,m,
h,n,l,q,w,p,a;for(a=0;a<g;a++)e=Math.max(c[a][1],e),b=Math.min(c[a][2],parseFloat(b.toFixed(r)));m=c[a][1]>b?1:-1;d=d.initialAccelerationFactor;h=d*(e-b);t.push([f[g],b]);u.push(f[g]);v.push(parseFloat(b.toFixed(r)));for(a=g+1;a<c.length;a++)g=c[a-1][2],l=c[a-2][2],q=c[a-1][1],w=c[a-2][1],n=c[a][1],p=c[a][2],b=m===k?1===m?b+h<Math.min(l,g)?b+h:Math.min(l,g):b+h>Math.max(w,q)?b+h:Math.max(w,q):e,g=1===m?n>e?n:e:p<e?p:e,n=1===k&&p>b||-1===k&&n>b?1:-1,k=n,h=g,p=y,l=x,q=z,d=k===m?1===k&&h>e?d===l?l:parseFloat((d+
p).toFixed(2)):-1===k&&h<e?d===l?l:parseFloat((d+p).toFixed(2)):d:q,e=g-b,h=d*e,t.push([f[a],parseFloat(b.toFixed(r))]),u.push(f[a]),v.push(parseFloat(b.toFixed(r))),k=m,m=n,e=g;return{values:t,xData:u,yData:v}}})})(f)});
@@ -0,0 +1,325 @@
/**
* @license Highcharts JS v6.0.4 (2017-12-15)
*
* Parabolic SAR Indicator for Highstock
*
* (c) 2010-2017 Grzegorz Blachliński
*
* License: www.highcharts.com/license
*/
'use strict';
(function(factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory;
} else {
factory(Highcharts);
}
}(function(Highcharts) {
(function(H) {




// Utils:

function toFixed(a, n) {
return parseFloat(a.toFixed(n));
}

function calculateDirection(previousDirection, low, high, PSAR) {
if (
(previousDirection === 1 && low > PSAR) ||
(previousDirection === -1 && high > PSAR)
) {
return 1;
}
return -1;
}

/*
* Method for calculating acceleration factor
* dir - direction
* pDir - previous Direction
* eP - extreme point
* pEP - previous extreme point
* inc - increment for acceleration factor
* maxAcc - maximum acceleration factor
* initAcc - initial acceleration factor
*/
function getAccelerationFactor(dir, pDir, eP, pEP, pAcc, inc, maxAcc, initAcc) {
if (dir === pDir) {
if (dir === 1 && (eP > pEP)) {
return (pAcc === maxAcc) ? maxAcc : toFixed(pAcc + inc, 2);
} else if (dir === -1 && (eP < pEP)) {
return (pAcc === maxAcc) ? maxAcc : toFixed(pAcc + inc, 2);
}
return pAcc;
}
return initAcc;
}

function getExtremePoint(high, low, previousDirection, previousExtremePoint) {
if (previousDirection === 1) {
return (high > previousExtremePoint) ? high : previousExtremePoint;
}
return (low < previousExtremePoint) ? low : previousExtremePoint;
}

function getEPMinusPSAR(EP, PSAR) {
return EP - PSAR;
}

function getAccelerationFactorMultiply(accelerationFactor, EPMinusSAR) {
return accelerationFactor * EPMinusSAR;
}

/*
* Method for calculating PSAR
* pdir - previous direction
* sDir - second previous Direction
* PSAR - previous PSAR
* pACCMultiply - previous acceleration factor multiply
* sLow - second previous low
* pLow - previous low
* sHigh - second previous high
* pHigh - previous high
* pEP - previous extreme point
*/
function getPSAR(pdir, sDir, PSAR, pACCMulti, sLow, pLow, pHigh, sHigh, pEP) {
if (pdir === sDir) {
if (pdir === 1) {
return (PSAR + pACCMulti < Math.min(sLow, pLow)) ?
PSAR + pACCMulti :
Math.min(sLow, pLow);
}
return (PSAR + pACCMulti > Math.max(sHigh, pHigh)) ?
PSAR + pACCMulti :
Math.max(sHigh, pHigh);
}
return pEP;
}



/**
* The Parabolic SAR series type.
*
* @constructor seriesTypes.psar
* @augments seriesTypes.sma
*/
H.seriesType('psar', 'sma',

/**
* Parabolic SAR. This series requires `linkedTo`
* option to be set and should be loaded
* after `stock/indicators/indicators.js` file.
*
* @extends {plotOptions.sma}
* @product highstock
* @sample {highstock} stock/indicators/psar
* Parabolic SAR Indicator
* @since 6.0.0
* @optionparent plotOptions.psar
*/

{
name: 'PSAR',
lineWidth: 0,
marker: {
enabled: true
},
states: {
hover: {
lineWidthPlus: 0
}
},
/**
* @excluding index
* @excluding period
*/
params: {
/**
* The initial value for acceleration factor.
* Acceleration factor is starting with this value
* and increases by specified increment each time
* the extreme point makes a new high.
* AF can reach a maximum of maxAccelerationFactor,
* no matter how long the uptrend extends.
*
* @type {Number}
* @since 6.0.0
* @excluding period
* @product highstock
*/
initialAccelerationFactor: 0.02,
/**
* The Maximum value for acceleration factor.
* AF can reach a maximum of maxAccelerationFactor,
* no matter how long the uptrend extends.
*
* @type {Number}
* @since 6.0.0
* @product highstock
*/
maxAccelerationFactor: 0.2,
/**
* Acceleration factor increases by increment each time
* the extreme point makes a new high.
*
* @type {Number}
* @since 6.0.0
* @product highstock
*/
increment: 0.02,
/**
* Index from which PSAR is starting calculation
*
* @type {Number}
* @since 6.0.0
* @product highstock
*/
index: 2,
/**
* Number of maximum decimals that are used in PSAR calculations.
*
* @type {Number}
* @since 6.0.0
* @product highstock
*/
decimals: 4
}
}, {
getValues: function(series, params) {
var xVal = series.xData,
yVal = series.yData,
extremePoint = yVal[0][1], // Extreme point is the lowest low for falling and highest high for rising psar - and we are starting with falling
accelerationFactor = params.initialAccelerationFactor,
maxAccelerationFactor = params.maxAccelerationFactor,
increment = params.increment,
initialAccelerationFactor = params.initialAccelerationFactor, // Set initial acc factor (for every new trend!)
PSAR = yVal[0][2],
decimals = params.decimals,
index = params.index,
PSARArr = [],
xData = [],
yData = [],
previousDirection = 1,
direction, EPMinusPSAR, accelerationFactorMultiply,
newDirection,
prevLow,
prevPrevLow,
prevHigh,
prevPrevHigh,
newExtremePoint,
high, low, ind;

for (ind = 0; ind < index; ind++) {
extremePoint = Math.max(yVal[ind][1], extremePoint);
PSAR = Math.min(yVal[ind][2], toFixed(PSAR, decimals));
}

direction = (yVal[ind][1] > PSAR) ? 1 : -1;
EPMinusPSAR = getEPMinusPSAR(extremePoint, PSAR);
accelerationFactor = params.initialAccelerationFactor;
accelerationFactorMultiply = getAccelerationFactorMultiply(accelerationFactor, EPMinusPSAR);

PSARArr.push([xVal[index], PSAR]);
xData.push(xVal[index]);
yData.push(toFixed(PSAR, decimals));

for (ind = index + 1; ind < yVal.length; ind++) {

prevLow = yVal[ind - 1][2];
prevPrevLow = yVal[ind - 2][2];
prevHigh = yVal[ind - 1][1];
prevPrevHigh = yVal[ind - 2][1];
high = yVal[ind][1];
low = yVal[ind][2];

PSAR = getPSAR(
direction,
previousDirection,
PSAR,
accelerationFactorMultiply,
prevPrevLow,
prevLow,
prevHigh,
prevPrevHigh,
extremePoint
);
newExtremePoint = getExtremePoint(
high,
low,
direction,
extremePoint
);
newDirection = calculateDirection(
previousDirection,
low,
high,
PSAR
);
accelerationFactor = getAccelerationFactor(
newDirection,
direction,
newExtremePoint,
extremePoint,
accelerationFactor,
increment,
maxAccelerationFactor,
initialAccelerationFactor
);

EPMinusPSAR = getEPMinusPSAR(newExtremePoint, PSAR);
accelerationFactorMultiply = getAccelerationFactorMultiply(
accelerationFactor,
EPMinusPSAR
);

PSARArr.push([xVal[ind], toFixed(PSAR, decimals)]);
xData.push(xVal[ind]);
yData.push(toFixed(PSAR, decimals));

previousDirection = direction;
direction = newDirection;
extremePoint = newExtremePoint;
}
return {
values: PSARArr,
xData: xData,
yData: yData
};
}
}
);

/**
* A `PSAR` series. If the [type](#series.psar.type) option is not
* specified, it is inherited from [chart.type](#chart.type).
*
* For options that apply to multiple series, it is recommended to add
* them to the [plotOptions.series](#plotOptions.series) options structure.
* To apply to all series of this specific type, apply it to [plotOptions.
* psar](#plotOptions.psar).
*
* @type {Object}
* @since 6.0.0
* @extends series,plotOptions.psar
* @excluding data,dataParser,dataURL
* @product highstock
* @apioption series.psar
*/

/**
* An array of data points for the series. For the `psar` series type,
* points are calculated dynamically.
*
* @type {Array<Object|Array>}
* @since 6.0.0
* @extends series.line.data
* @product highstock
* @apioption series.psar.data
*/

}(Highcharts));
}));
@@ -0,0 +1,11 @@
/*
Highcharts JS v6.0.4 (2017-12-15)
Indicator series type for Highstock
(c) 2010-2017 Kacper Madej
License: www.highcharts.com/license
*/
(function(b){"object"===typeof module&&module.exports?module.exports=b:b(Highcharts)})(function(b){(function(b){var f=b.seriesType,m=b.isArray;f("roc","sma",{name:"Rate of Change (9)",params:{index:3,period:9}},{getValues:function(d,c){var b=c.period,g=d.xData,f=(d=d.yData)?d.length:0,h=[],k=[],l=[],e=-1,a;if(g.length<=b)return!1;m(d[0])&&(e=c.index);for(c=b;c<f;c++)a=0>e?(a=d[c-b])?(d[c]-a)/a*100:null:(a=d[c-b][e])?(d[c][e]-a)/a*100:null,a=[g[c],a],h.push(a),k.push(a[0]),l.push(a[1]);return{values:h,
xData:k,yData:l}}})})(b)});
@@ -0,0 +1,166 @@
/**
* @license Highcharts JS v6.0.4 (2017-12-15)
*
* Indicator series type for Highstock
*
* (c) 2010-2017 Kacper Madej
*
* License: www.highcharts.com/license
*/
'use strict';
(function(factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory;
} else {
factory(Highcharts);
}
}(function(Highcharts) {
(function(H) {
/**
* (c) 2010-2017 Kacper Madej
*
* License: www.highcharts.com/license
*/


var seriesType = H.seriesType,
isArray = H.isArray;

// Utils:
function populateAverage(xVal, yVal, i, period, index) {
/**
* Calculated as:
* (Closing Price [today] - Closing Price [n days ago]) /
* Closing Price [n days ago] * 100
*
* Return y as null when avoiding division by zero
*/
var nDaysAgoY,
rocY;

if (index < 0) {
// y data given as an array of values
nDaysAgoY = yVal[i - period];
rocY = nDaysAgoY ?
(yVal[i] - nDaysAgoY) / nDaysAgoY * 100 :
null;
} else {
// y data given as an array of arrays and the index should be used
nDaysAgoY = yVal[i - period][index];
rocY = nDaysAgoY ?
(yVal[i][index] - nDaysAgoY) / nDaysAgoY * 100 :
null;
}

return [xVal[i], rocY];
}

/**
* The ROC series type.
*
* @constructor seriesTypes.roc
* @augments seriesTypes.sma
*/
seriesType('roc', 'sma',
/**
* Rate of change indicator (ROC). The indicator value for each point
* is defined as:
*
* `(C - Cn) / Cn * 100`
*
* where: `C` is the close value of the point of the same x in the
* linked series and `Cn` is the close value of the point `n` periods
* ago. `n` is set through [period](#plotOptions.roc.params.period).
*
* This series requires `linkedTo` option to be set.
*
* @extends {plotOptions.sma}
* @product highstock
* @sample {highstock} stock/indicators/roc
* Rate of change indicator
* @since 6.0.0
* @optionparent plotOptions.roc
*/
{
name: 'Rate of Change (9)',
params: {
index: 3,
period: 9
}
}, {
getValues: function(series, params) {
var period = params.period,
xVal = series.xData,
yVal = series.yData,
yValLen = yVal ? yVal.length : 0,
ROC = [],
xData = [],
yData = [],
i,
index = -1,
ROCPoint;

// Period is used as a number of time periods ago, so we need more
// (at least 1 more) data than the period value
if (xVal.length <= period) {
return false;
}

// Switch index for OHLC / Candlestick / Arearange
if (isArray(yVal[0])) {
index = params.index;
}

// i = period <-- skip first N-points
// Calculate value one-by-one for each period in visible data
for (i = period; i < yValLen; i++) {
ROCPoint = populateAverage(xVal, yVal, i, period, index);
ROC.push(ROCPoint);
xData.push(ROCPoint[0]);
yData.push(ROCPoint[1]);
}

return {
values: ROC,
xData: xData,
yData: yData
};
}
});

/**
* A `ROC` series. If the [type](#series.wma.type) option is not
* specified, it is inherited from [chart.type](#chart.type).
*
* Rate of change indicator (ROC). The indicator value for each point
* is defined as:
*
* `(C - Cn) / Cn * 100`
*
* where: `C` is the close value of the point of the same x in the
* linked series and `Cn` is the close value of the point `n` periods
* ago. `n` is set through [period](#series.roc.params.period).
*
* This series requires `linkedTo` option to be set.
*
* For options that apply to multiple series, it is recommended to add
* them to the [plotOptions.series](#plotOptions.series) options structure.
* To apply to all series of this specific type, apply it to
* [plotOptions.wma](#plotOptions.wma).
*
* @type {Object}
* @since 6.0.0
* @extends series,plotOptions.roc
* @excluding data,dataParser,dataURL
* @product highstock
* @apioption series.roc
*/

/**
* @extends series.sma.data
* @product highstock
* @apioption series.roc.data
*/

}(Highcharts));
}));