pivot-points.src.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /**
  2. * @license Highstock JS v8.0.0 (2019-12-10)
  3. *
  4. * Indicator series type for Highstock
  5. *
  6. * (c) 2010-2019 Paweł Fus
  7. *
  8. * License: www.highcharts.com/license
  9. */
  10. 'use strict';
  11. (function (factory) {
  12. if (typeof module === 'object' && module.exports) {
  13. factory['default'] = factory;
  14. module.exports = factory;
  15. } else if (typeof define === 'function' && define.amd) {
  16. define('highcharts/indicators/pivot-points', ['highcharts', 'highcharts/modules/stock'], function (Highcharts) {
  17. factory(Highcharts);
  18. factory.Highcharts = Highcharts;
  19. return factory;
  20. });
  21. } else {
  22. factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
  23. }
  24. }(function (Highcharts) {
  25. var _modules = Highcharts ? Highcharts._modules : {};
  26. function _registerModule(obj, path, args, fn) {
  27. if (!obj.hasOwnProperty(path)) {
  28. obj[path] = fn.apply(null, args);
  29. }
  30. }
  31. _registerModule(_modules, 'indicators/pivot-points.src.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
  32. /* *
  33. *
  34. * License: www.highcharts.com/license
  35. *
  36. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  37. *
  38. * */
  39. var defined = U.defined, isArray = U.isArray;
  40. var SMA = H.seriesTypes.sma;
  41. /* eslint-disable valid-jsdoc */
  42. /**
  43. * @private
  44. */
  45. function destroyExtraLabels(point, functionName) {
  46. var props = point.series.pointArrayMap, prop, i = props.length;
  47. SMA.prototype.pointClass.prototype[functionName].call(point);
  48. while (i--) {
  49. prop = 'dataLabel' + props[i];
  50. // S4 dataLabel could be removed by parent method:
  51. if (point[prop] && point[prop].element) {
  52. point[prop].destroy();
  53. }
  54. point[prop] = null;
  55. }
  56. }
  57. /* eslint-enable valid-jsdoc */
  58. /**
  59. * The Pivot Points series type.
  60. *
  61. * @private
  62. * @class
  63. * @name Highcharts.seriesTypes.pivotpoints
  64. *
  65. * @augments Highcharts.Series
  66. */
  67. H.seriesType('pivotpoints', 'sma',
  68. /**
  69. * Pivot points indicator. This series requires the `linkedTo` option to be
  70. * set and should be loaded after `stock/indicators/indicators.js` file.
  71. *
  72. * @sample stock/indicators/pivot-points
  73. * Pivot points
  74. *
  75. * @extends plotOptions.sma
  76. * @since 6.0.0
  77. * @product highstock
  78. * @requires stock/indicators/indicators
  79. * @requires stock/indicators/pivotpoints
  80. * @optionparent plotOptions.pivotpoints
  81. */
  82. {
  83. /**
  84. * @excluding index
  85. */
  86. params: {
  87. period: 28,
  88. /**
  89. * Algorithm used to calculate ressistance and support lines based
  90. * on pivot points. Implemented algorithms: `'standard'`,
  91. * `'fibonacci'` and `'camarilla'`
  92. */
  93. algorithm: 'standard'
  94. },
  95. marker: {
  96. enabled: false
  97. },
  98. enableMouseTracking: false,
  99. dataLabels: {
  100. enabled: true,
  101. format: '{point.pivotLine}'
  102. },
  103. dataGrouping: {
  104. approximation: 'averages'
  105. }
  106. },
  107. /**
  108. * @lends Highcharts.Series#
  109. */
  110. {
  111. nameBase: 'Pivot Points',
  112. pointArrayMap: ['R4', 'R3', 'R2', 'R1', 'P', 'S1', 'S2', 'S3', 'S4'],
  113. pointValKey: 'P',
  114. toYData: function (point) {
  115. return [point.P]; // The rest should not affect extremes
  116. },
  117. translate: function () {
  118. var indicator = this;
  119. SMA.prototype.translate.apply(indicator);
  120. indicator.points.forEach(function (point) {
  121. indicator.pointArrayMap.forEach(function (value) {
  122. if (defined(point[value])) {
  123. point['plot' + value] = (indicator.yAxis.toPixels(point[value], true));
  124. }
  125. });
  126. });
  127. // Pivot points are rendered as horizontal lines
  128. // And last point start not from the next one (as it's the last one)
  129. // But from the approximated last position in a given range
  130. indicator.plotEndPoint = indicator.xAxis.toPixels(indicator.endPoint, true);
  131. },
  132. getGraphPath: function (points) {
  133. var indicator = this, pointsLength = points.length, allPivotPoints = ([[], [], [], [], [], [], [], [], []]), path = [], endPoint = indicator.plotEndPoint, pointArrayMapLength = indicator.pointArrayMap.length, position, point, i;
  134. while (pointsLength--) {
  135. point = points[pointsLength];
  136. for (i = 0; i < pointArrayMapLength; i++) {
  137. position = indicator.pointArrayMap[i];
  138. if (defined(point[position])) {
  139. allPivotPoints[i].push({
  140. // Start left:
  141. plotX: point.plotX,
  142. plotY: point['plot' + position],
  143. isNull: false
  144. }, {
  145. // Go to right:
  146. plotX: endPoint,
  147. plotY: point['plot' + position],
  148. isNull: false
  149. }, {
  150. // And add null points in path to generate breaks:
  151. plotX: endPoint,
  152. plotY: null,
  153. isNull: true
  154. });
  155. }
  156. }
  157. endPoint = point.plotX;
  158. }
  159. allPivotPoints.forEach(function (pivotPoints) {
  160. path = path.concat(SMA.prototype.getGraphPath.call(indicator, pivotPoints));
  161. });
  162. return path;
  163. },
  164. // TODO: Rewrite this logic to use multiple datalabels
  165. drawDataLabels: function () {
  166. var indicator = this, pointMapping = indicator.pointArrayMap, currentLabel, pointsLength, point, i;
  167. if (indicator.options.dataLabels.enabled) {
  168. pointsLength = indicator.points.length;
  169. // For every Ressitance/Support group we need to render labels.
  170. // Add one more item, which will just store dataLabels from
  171. // previous iteration
  172. pointMapping.concat([false]).forEach(function (position, k) {
  173. i = pointsLength;
  174. while (i--) {
  175. point = indicator.points[i];
  176. if (!position) {
  177. // Store S4 dataLabel too:
  178. point['dataLabel' + pointMapping[k - 1]] =
  179. point.dataLabel;
  180. }
  181. else {
  182. point.y = point[position];
  183. point.pivotLine = position;
  184. point.plotY = point['plot' + position];
  185. currentLabel = point['dataLabel' + position];
  186. // Store previous label
  187. if (k) {
  188. point['dataLabel' + pointMapping[k - 1]] = point.dataLabel;
  189. }
  190. if (!point.dataLabels) {
  191. point.dataLabels = [];
  192. }
  193. point.dataLabels[0] = point.dataLabel =
  194. currentLabel =
  195. currentLabel && currentLabel.element ?
  196. currentLabel :
  197. null;
  198. }
  199. }
  200. SMA.prototype.drawDataLabels.apply(indicator, arguments);
  201. });
  202. }
  203. },
  204. getValues: function (series, params) {
  205. var period = params.period, xVal = series.xData, yVal = series.yData, yValLen = yVal ? yVal.length : 0, placement = this[params.algorithm + 'Placement'],
  206. // 0- from, 1- to, 2- R1, 3- R2, 4- pivot, 5- S1 etc.
  207. PP = [], endTimestamp, xData = [], yData = [], slicedXLen, slicedX, slicedY, lastPP, pivot, avg, i;
  208. // Pivot Points requires high, low and close values
  209. if (xVal.length < period ||
  210. !isArray(yVal[0]) ||
  211. yVal[0].length !== 4) {
  212. return;
  213. }
  214. for (i = period + 1; i <= yValLen + period; i += period) {
  215. slicedX = xVal.slice(i - period - 1, i);
  216. slicedY = yVal.slice(i - period - 1, i);
  217. slicedXLen = slicedX.length;
  218. endTimestamp = slicedX[slicedXLen - 1];
  219. pivot = this.getPivotAndHLC(slicedY);
  220. avg = placement(pivot);
  221. lastPP = PP.push([endTimestamp]
  222. .concat(avg));
  223. xData.push(endTimestamp);
  224. yData.push(PP[lastPP - 1].slice(1));
  225. }
  226. // We don't know exact position in ordinal axis
  227. // So we use simple logic:
  228. // Get first point in last range, calculate visible average range
  229. // and multiply by period
  230. this.endPoint = slicedX[0] + ((endTimestamp - slicedX[0]) /
  231. slicedXLen) * period;
  232. return {
  233. values: PP,
  234. xData: xData,
  235. yData: yData
  236. };
  237. },
  238. getPivotAndHLC: function (values) {
  239. var high = -Infinity, low = Infinity, close = values[values.length - 1][3], pivot;
  240. values.forEach(function (p) {
  241. high = Math.max(high, p[1]);
  242. low = Math.min(low, p[2]);
  243. });
  244. pivot = (high + low + close) / 3;
  245. return [pivot, high, low, close];
  246. },
  247. standardPlacement: function (values) {
  248. var diff = values[1] - values[2], avg = [
  249. null,
  250. null,
  251. values[0] + diff,
  252. values[0] * 2 - values[2],
  253. values[0],
  254. values[0] * 2 - values[1],
  255. values[0] - diff,
  256. null,
  257. null
  258. ];
  259. return avg;
  260. },
  261. camarillaPlacement: function (values) {
  262. var diff = values[1] - values[2], avg = [
  263. values[3] + diff * 1.5,
  264. values[3] + diff * 1.25,
  265. values[3] + diff * 1.1666,
  266. values[3] + diff * 1.0833,
  267. values[0],
  268. values[3] - diff * 1.0833,
  269. values[3] - diff * 1.1666,
  270. values[3] - diff * 1.25,
  271. values[3] - diff * 1.5
  272. ];
  273. return avg;
  274. },
  275. fibonacciPlacement: function (values) {
  276. var diff = values[1] - values[2], avg = [
  277. null,
  278. values[0] + diff,
  279. values[0] + diff * 0.618,
  280. values[0] + diff * 0.382,
  281. values[0],
  282. values[0] - diff * 0.382,
  283. values[0] - diff * 0.618,
  284. values[0] - diff,
  285. null
  286. ];
  287. return avg;
  288. }
  289. },
  290. /**
  291. * @lends Highcharts.Point#
  292. */
  293. {
  294. // Destroy labels:
  295. // This method is called when cropping data:
  296. destroyElements: function () {
  297. destroyExtraLabels(this, 'destroyElements');
  298. },
  299. // This method is called when removing points, e.g. series.update()
  300. destroy: function () {
  301. destroyExtraLabels(this, 'destroyElements');
  302. }
  303. });
  304. /**
  305. * A pivot points indicator. If the [type](#series.pivotpoints.type) option is
  306. * not specified, it is inherited from [chart.type](#chart.type).
  307. *
  308. * @extends series,plotOptions.pivotpoints
  309. * @since 6.0.0
  310. * @product highstock
  311. * @excluding dataParser, dataURL
  312. * @requires stock/indicators/indicators
  313. * @requires stock/indicators/pivotpoints
  314. * @apioption series.pivotpoints
  315. */
  316. ''; // to include the above in the js output'
  317. });
  318. _registerModule(_modules, 'masters/indicators/pivot-points.src.js', [], function () {
  319. });
  320. }));