macd.src.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /**
  2. * @license Highstock JS v8.1.2 (2020-06-16)
  3. *
  4. * Indicator series type for Highstock
  5. *
  6. * (c) 2010-2019 Sebastian Bochan
  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/macd', ['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/macd.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 correctFloat = U.correctFloat, defined = U.defined, merge = U.merge, seriesType = U.seriesType;
  40. var noop = H.noop, SMA = H.seriesTypes.sma, EMA = H.seriesTypes.ema;
  41. /**
  42. * The MACD series type.
  43. *
  44. * @private
  45. * @class
  46. * @name Highcharts.seriesTypes.macd
  47. *
  48. * @augments Highcharts.Series
  49. */
  50. seriesType('macd', 'sma',
  51. /**
  52. * Moving Average Convergence Divergence (MACD). This series requires
  53. * `linkedTo` option to be set and should be loaded after the
  54. * `stock/indicators/indicators.js` and `stock/indicators/ema.js`.
  55. *
  56. * @sample stock/indicators/macd
  57. * MACD indicator
  58. *
  59. * @extends plotOptions.sma
  60. * @since 6.0.0
  61. * @product highstock
  62. * @requires stock/indicators/indicators
  63. * @requires stock/indicators/macd
  64. * @optionparent plotOptions.macd
  65. */
  66. {
  67. params: {
  68. /**
  69. * The short period for indicator calculations.
  70. */
  71. shortPeriod: 12,
  72. /**
  73. * The long period for indicator calculations.
  74. */
  75. longPeriod: 26,
  76. /**
  77. * The base period for signal calculations.
  78. */
  79. signalPeriod: 9,
  80. period: 26
  81. },
  82. /**
  83. * The styles for signal line
  84. */
  85. signalLine: {
  86. /**
  87. * @sample stock/indicators/macd-zones
  88. * Zones in MACD
  89. *
  90. * @extends plotOptions.macd.zones
  91. */
  92. zones: [],
  93. styles: {
  94. /**
  95. * Pixel width of the line.
  96. */
  97. lineWidth: 1,
  98. /**
  99. * Color of the line.
  100. *
  101. * @type {Highcharts.ColorString}
  102. */
  103. lineColor: void 0
  104. }
  105. },
  106. /**
  107. * The styles for macd line
  108. */
  109. macdLine: {
  110. /**
  111. * @sample stock/indicators/macd-zones
  112. * Zones in MACD
  113. *
  114. * @extends plotOptions.macd.zones
  115. */
  116. zones: [],
  117. styles: {
  118. /**
  119. * Pixel width of the line.
  120. */
  121. lineWidth: 1,
  122. /**
  123. * Color of the line.
  124. *
  125. * @type {Highcharts.ColorString}
  126. */
  127. lineColor: void 0
  128. }
  129. },
  130. threshold: 0,
  131. groupPadding: 0.1,
  132. pointPadding: 0.1,
  133. crisp: false,
  134. states: {
  135. hover: {
  136. halo: {
  137. size: 0
  138. }
  139. }
  140. },
  141. tooltip: {
  142. pointFormat: '<span style="color:{point.color}">\u25CF</span> <b> {series.name}</b><br/>' +
  143. 'Value: {point.MACD}<br/>' +
  144. 'Signal: {point.signal}<br/>' +
  145. 'Histogram: {point.y}<br/>'
  146. },
  147. dataGrouping: {
  148. approximation: 'averages'
  149. },
  150. minPointLength: 0
  151. },
  152. /**
  153. * @lends Highcharts.Series#
  154. */
  155. {
  156. nameComponents: ['longPeriod', 'shortPeriod', 'signalPeriod'],
  157. requiredIndicators: ['ema'],
  158. // "y" value is treated as Histogram data
  159. pointArrayMap: ['y', 'signal', 'MACD'],
  160. parallelArrays: ['x', 'y', 'signal', 'MACD'],
  161. pointValKey: 'y',
  162. // Columns support:
  163. markerAttribs: noop,
  164. getColumnMetrics: H.seriesTypes.column.prototype.getColumnMetrics,
  165. crispCol: H.seriesTypes.column.prototype.crispCol,
  166. // Colors and lines:
  167. init: function () {
  168. SMA.prototype.init.apply(this, arguments);
  169. // Check whether series is initialized. It may be not initialized,
  170. // when any of required indicators is missing.
  171. if (this.options) {
  172. // Set default color for a signal line and the histogram:
  173. this.options = merge({
  174. signalLine: {
  175. styles: {
  176. lineColor: this.color
  177. }
  178. },
  179. macdLine: {
  180. styles: {
  181. color: this.color
  182. }
  183. }
  184. }, this.options);
  185. // Zones have indexes automatically calculated, we need to
  186. // translate them to support multiple lines within one indicator
  187. this.macdZones = {
  188. zones: this.options.macdLine.zones,
  189. startIndex: 0
  190. };
  191. this.signalZones = {
  192. zones: this.macdZones.zones.concat(this.options.signalLine.zones),
  193. startIndex: this.macdZones.zones.length
  194. };
  195. this.resetZones = true;
  196. }
  197. },
  198. toYData: function (point) {
  199. return [point.y, point.signal, point.MACD];
  200. },
  201. translate: function () {
  202. var indicator = this, plotNames = ['plotSignal', 'plotMACD'];
  203. H.seriesTypes.column.prototype.translate.apply(indicator);
  204. indicator.points.forEach(function (point) {
  205. [point.signal, point.MACD].forEach(function (value, i) {
  206. if (value !== null) {
  207. point[plotNames[i]] =
  208. indicator.yAxis.toPixels(value, true);
  209. }
  210. });
  211. });
  212. },
  213. destroy: function () {
  214. // this.graph is null due to removing two times the same SVG element
  215. this.graph = null;
  216. this.graphmacd = this.graphmacd && this.graphmacd.destroy();
  217. this.graphsignal = this.graphsignal && this.graphsignal.destroy();
  218. SMA.prototype.destroy.apply(this, arguments);
  219. },
  220. drawPoints: H.seriesTypes.column.prototype.drawPoints,
  221. drawGraph: function () {
  222. var indicator = this, mainLinePoints = indicator.points, pointsLength = mainLinePoints.length, mainLineOptions = indicator.options, histogramZones = indicator.zones, gappedExtend = {
  223. options: {
  224. gapSize: mainLineOptions.gapSize
  225. }
  226. }, otherSignals = [[], []], point;
  227. // Generate points for top and bottom lines:
  228. while (pointsLength--) {
  229. point = mainLinePoints[pointsLength];
  230. if (defined(point.plotMACD)) {
  231. otherSignals[0].push({
  232. plotX: point.plotX,
  233. plotY: point.plotMACD,
  234. isNull: !defined(point.plotMACD)
  235. });
  236. }
  237. if (defined(point.plotSignal)) {
  238. otherSignals[1].push({
  239. plotX: point.plotX,
  240. plotY: point.plotSignal,
  241. isNull: !defined(point.plotMACD)
  242. });
  243. }
  244. }
  245. // Modify options and generate smoothing line:
  246. ['macd', 'signal'].forEach(function (lineName, i) {
  247. indicator.points = otherSignals[i];
  248. indicator.options = merge(mainLineOptions[lineName + 'Line'].styles, gappedExtend);
  249. indicator.graph = indicator['graph' + lineName];
  250. // Zones extension:
  251. indicator.currentLineZone = lineName + 'Zones';
  252. indicator.zones =
  253. indicator[indicator.currentLineZone].zones;
  254. SMA.prototype.drawGraph.call(indicator);
  255. indicator['graph' + lineName] = indicator.graph;
  256. });
  257. // Restore options:
  258. indicator.points = mainLinePoints;
  259. indicator.options = mainLineOptions;
  260. indicator.zones = histogramZones;
  261. indicator.currentLineZone = null;
  262. // indicator.graph = null;
  263. },
  264. getZonesGraphs: function (props) {
  265. var allZones = SMA.prototype.getZonesGraphs.call(this, props), currentZones = allZones;
  266. if (this.currentLineZone) {
  267. currentZones = allZones.splice(this[this.currentLineZone].startIndex + 1);
  268. if (!currentZones.length) {
  269. // Line has no zones, return basic graph "zone"
  270. currentZones = [props[0]];
  271. }
  272. else {
  273. // Add back basic prop:
  274. currentZones.splice(0, 0, props[0]);
  275. }
  276. }
  277. return currentZones;
  278. },
  279. applyZones: function () {
  280. // Histogram zones are handled by drawPoints method
  281. // Here we need to apply zones for all lines
  282. var histogramZones = this.zones;
  283. // signalZones.zones contains all zones:
  284. this.zones = this.signalZones.zones;
  285. SMA.prototype.applyZones.call(this);
  286. // applyZones hides only main series.graph, hide macd line manually
  287. if (this.graphmacd && this.options.macdLine.zones.length) {
  288. this.graphmacd.hide();
  289. }
  290. this.zones = histogramZones;
  291. },
  292. getValues: function (series, params) {
  293. var j = 0, MACD = [], xMACD = [], yMACD = [], signalLine = [], shortEMA, longEMA, i;
  294. if (series.xData.length <
  295. params.longPeriod + params.signalPeriod) {
  296. return;
  297. }
  298. // Calculating the short and long EMA used when calculating the MACD
  299. shortEMA = EMA.prototype.getValues(series, {
  300. period: params.shortPeriod
  301. });
  302. longEMA = EMA.prototype.getValues(series, {
  303. period: params.longPeriod
  304. });
  305. shortEMA = shortEMA.values;
  306. longEMA = longEMA.values;
  307. // Subtract each Y value from the EMA's and create the new dataset
  308. // (MACD)
  309. for (i = 1; i <= shortEMA.length; i++) {
  310. if (defined(longEMA[i - 1]) &&
  311. defined(longEMA[i - 1][1]) &&
  312. defined(shortEMA[i + params.shortPeriod + 1]) &&
  313. defined(shortEMA[i + params.shortPeriod + 1][0])) {
  314. MACD.push([
  315. shortEMA[i + params.shortPeriod + 1][0],
  316. 0,
  317. null,
  318. shortEMA[i + params.shortPeriod + 1][1] -
  319. longEMA[i - 1][1]
  320. ]);
  321. }
  322. }
  323. // Set the Y and X data of the MACD. This is used in calculating the
  324. // signal line.
  325. for (i = 0; i < MACD.length; i++) {
  326. xMACD.push(MACD[i][0]);
  327. yMACD.push([0, null, MACD[i][3]]);
  328. }
  329. // Setting the signalline (Signal Line: X-day EMA of MACD line).
  330. signalLine = EMA.prototype.getValues({
  331. xData: xMACD,
  332. yData: yMACD
  333. }, {
  334. period: params.signalPeriod,
  335. index: 2
  336. });
  337. signalLine = signalLine.values;
  338. // Setting the MACD Histogram. In comparison to the loop with pure
  339. // MACD this loop uses MACD x value not xData.
  340. for (i = 0; i < MACD.length; i++) {
  341. // detect the first point
  342. if (MACD[i][0] >= signalLine[0][0]) {
  343. MACD[i][2] = signalLine[j][1];
  344. yMACD[i] = [0, signalLine[j][1], MACD[i][3]];
  345. if (MACD[i][3] === null) {
  346. MACD[i][1] = 0;
  347. yMACD[i][0] = 0;
  348. }
  349. else {
  350. MACD[i][1] = correctFloat(MACD[i][3] -
  351. signalLine[j][1]);
  352. yMACD[i][0] = correctFloat(MACD[i][3] -
  353. signalLine[j][1]);
  354. }
  355. j++;
  356. }
  357. }
  358. return {
  359. values: MACD,
  360. xData: xMACD,
  361. yData: yMACD
  362. };
  363. }
  364. });
  365. /**
  366. * A `MACD` series. If the [type](#series.macd.type) option is not
  367. * specified, it is inherited from [chart.type](#chart.type).
  368. *
  369. * @extends series,plotOptions.macd
  370. * @since 6.0.0
  371. * @product highstock
  372. * @excluding dataParser, dataURL
  373. * @requires stock/indicators/indicators
  374. * @requires stock/indicators/macd
  375. * @apioption series.macd
  376. */
  377. ''; // to include the above in the js output
  378. });
  379. _registerModule(_modules, 'masters/indicators/macd.src.js', [], function () {
  380. });
  381. }));