PriceEnvelopesIndicator.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /* *
  2. *
  3. * License: www.highcharts.com/license
  4. *
  5. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  6. *
  7. * */
  8. 'use strict';
  9. import H from '../../Core/Globals.js';
  10. import U from '../../Core/Utilities.js';
  11. var isArray = U.isArray, merge = U.merge, seriesType = U.seriesType;
  12. var SMA = H.seriesTypes.sma;
  13. /**
  14. * The Price Envelopes series type.
  15. *
  16. * @private
  17. * @class
  18. * @name Highcharts.seriesTypes.priceenvelopes
  19. *
  20. * @augments Highcharts.Series
  21. */
  22. seriesType('priceenvelopes', 'sma',
  23. /**
  24. * Price envelopes indicator based on [SMA](#plotOptions.sma) calculations.
  25. * This series requires the `linkedTo` option to be set and should be loaded
  26. * after the `stock/indicators/indicators.js` file.
  27. *
  28. * @sample stock/indicators/price-envelopes
  29. * Price envelopes
  30. *
  31. * @extends plotOptions.sma
  32. * @since 6.0.0
  33. * @product highstock
  34. * @requires stock/indicators/indicators
  35. * @requires stock/indicators/price-envelopes
  36. * @optionparent plotOptions.priceenvelopes
  37. */
  38. {
  39. marker: {
  40. enabled: false
  41. },
  42. tooltip: {
  43. 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/>'
  44. },
  45. params: {
  46. period: 20,
  47. /**
  48. * Percentage above the moving average that should be displayed.
  49. * 0.1 means 110%. Relative to the calculated value.
  50. */
  51. topBand: 0.1,
  52. /**
  53. * Percentage below the moving average that should be displayed.
  54. * 0.1 means 90%. Relative to the calculated value.
  55. */
  56. bottomBand: 0.1
  57. },
  58. /**
  59. * Bottom line options.
  60. */
  61. bottomLine: {
  62. styles: {
  63. /**
  64. * Pixel width of the line.
  65. */
  66. lineWidth: 1,
  67. /**
  68. * Color of the line. If not set, it's inherited from
  69. * [plotOptions.priceenvelopes.color](
  70. * #plotOptions.priceenvelopes.color).
  71. *
  72. * @type {Highcharts.ColorString}
  73. */
  74. lineColor: void 0
  75. }
  76. },
  77. /**
  78. * Top line options.
  79. *
  80. * @extends plotOptions.priceenvelopes.bottomLine
  81. */
  82. topLine: {
  83. styles: {
  84. lineWidth: 1
  85. }
  86. },
  87. dataGrouping: {
  88. approximation: 'averages'
  89. }
  90. },
  91. /**
  92. * @lends Highcharts.Series#
  93. */
  94. {
  95. nameComponents: ['period', 'topBand', 'bottomBand'],
  96. nameBase: 'Price envelopes',
  97. pointArrayMap: ['top', 'middle', 'bottom'],
  98. parallelArrays: ['x', 'y', 'top', 'bottom'],
  99. pointValKey: 'middle',
  100. init: function () {
  101. SMA.prototype.init.apply(this, arguments);
  102. // Set default color for lines:
  103. this.options = merge({
  104. topLine: {
  105. styles: {
  106. lineColor: this.color
  107. }
  108. },
  109. bottomLine: {
  110. styles: {
  111. lineColor: this.color
  112. }
  113. }
  114. }, this.options);
  115. },
  116. toYData: function (point) {
  117. return [point.top, point.middle, point.bottom];
  118. },
  119. translate: function () {
  120. var indicator = this, translatedEnvelopes = ['plotTop', 'plotMiddle', 'plotBottom'];
  121. SMA.prototype.translate.apply(indicator);
  122. indicator.points.forEach(function (point) {
  123. [point.top, point.middle, point.bottom].forEach(function (value, i) {
  124. if (value !== null) {
  125. point[translatedEnvelopes[i]] =
  126. indicator.yAxis.toPixels(value, true);
  127. }
  128. });
  129. });
  130. },
  131. drawGraph: function () {
  132. var indicator = this, middleLinePoints = indicator.points, pointsLength = middleLinePoints.length, middleLineOptions = (indicator.options), middleLinePath = indicator.graph, gappedExtend = {
  133. options: {
  134. gapSize: middleLineOptions.gapSize
  135. }
  136. }, deviations = [[], []], // top and bottom point place holders
  137. point;
  138. // Generate points for top and bottom lines:
  139. while (pointsLength--) {
  140. point = middleLinePoints[pointsLength];
  141. deviations[0].push({
  142. plotX: point.plotX,
  143. plotY: point.plotTop,
  144. isNull: point.isNull
  145. });
  146. deviations[1].push({
  147. plotX: point.plotX,
  148. plotY: point.plotBottom,
  149. isNull: point.isNull
  150. });
  151. }
  152. // Modify options and generate lines:
  153. ['topLine', 'bottomLine'].forEach(function (lineName, i) {
  154. indicator.points = deviations[i];
  155. indicator.options = merge(middleLineOptions[lineName].styles, gappedExtend);
  156. indicator.graph = indicator['graph' + lineName];
  157. SMA.prototype.drawGraph.call(indicator);
  158. // Now save lines:
  159. indicator['graph' + lineName] = indicator.graph;
  160. });
  161. // Restore options and draw a middle line:
  162. indicator.points = middleLinePoints;
  163. indicator.options = middleLineOptions;
  164. indicator.graph = middleLinePath;
  165. SMA.prototype.drawGraph.call(indicator);
  166. },
  167. getValues: function (series, params) {
  168. var period = params.period, topPercent = params.topBand, botPercent = params.bottomBand, xVal = series.xData, yVal = series.yData, yValLen = yVal ? yVal.length : 0,
  169. // 0- date, 1-top line, 2-middle line, 3-bottom line
  170. PE = [],
  171. // middle line, top line and bottom line
  172. ML, TL, BL, date, xData = [], yData = [], slicedX, slicedY, point, i;
  173. // Price envelopes requires close value
  174. if (xVal.length < period ||
  175. !isArray(yVal[0]) ||
  176. yVal[0].length !== 4) {
  177. return;
  178. }
  179. for (i = period; i <= yValLen; i++) {
  180. slicedX = xVal.slice(i - period, i);
  181. slicedY = yVal.slice(i - period, i);
  182. point = SMA.prototype.getValues.call(this, {
  183. xData: slicedX,
  184. yData: slicedY
  185. }, params);
  186. date = point.xData[0];
  187. ML = point.yData[0];
  188. TL = ML * (1 + topPercent);
  189. BL = ML * (1 - botPercent);
  190. PE.push([date, TL, ML, BL]);
  191. xData.push(date);
  192. yData.push([TL, ML, BL]);
  193. }
  194. return {
  195. values: PE,
  196. xData: xData,
  197. yData: yData
  198. };
  199. }
  200. });
  201. /**
  202. * A price envelopes indicator. If the [type](#series.priceenvelopes.type)
  203. * option is not specified, it is inherited from [chart.type](#chart.type).
  204. *
  205. * @extends series,plotOptions.priceenvelopes
  206. * @since 6.0.0
  207. * @excluding dataParser, dataURL
  208. * @product highstock
  209. * @requires stock/indicators/indicators
  210. * @requires stock/indicators/price-envelopes
  211. * @apioption series.priceenvelopes
  212. */
  213. ''; // to include the above in the js output