| @@ -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)); | ||
| })); |