macd.src.js 16 KB

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