indicators.src.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. /**
  2. * @license Highstock JS v8.2.0 (2020-08-20)
  3. *
  4. * Indicator series type for Highstock
  5. *
  6. * (c) 2010-2019 Pawel Fus, 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/indicators', ['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, 'Mixins/IndicatorRequired.js', [_modules['Core/Utilities.js']], function (U) {
  32. /**
  33. *
  34. * (c) 2010-2020 Daniel Studencki
  35. *
  36. * License: www.highcharts.com/license
  37. *
  38. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  39. *
  40. * */
  41. var error = U.error;
  42. /* eslint-disable no-invalid-this, valid-jsdoc */
  43. var requiredIndicatorMixin = {
  44. /**
  45. * Check whether given indicator is loaded,
  46. else throw error.
  47. * @private
  48. * @param {Highcharts.Indicator} indicator
  49. * Indicator constructor function.
  50. * @param {string} requiredIndicator
  51. * Required indicator type.
  52. * @param {string} type
  53. * Type of indicator where function was called (parent).
  54. * @param {Highcharts.IndicatorCallbackFunction} callback
  55. * Callback which is triggered if the given indicator is loaded.
  56. * Takes indicator as an argument.
  57. * @param {string} errMessage
  58. * Error message that will be logged in console.
  59. * @return {boolean}
  60. * Returns false when there is no required indicator loaded.
  61. */
  62. isParentLoaded: function (indicator,
  63. requiredIndicator,
  64. type,
  65. callback,
  66. errMessage) {
  67. if (indicator) {
  68. return callback ? callback(indicator) : true;
  69. }
  70. error(errMessage || this.generateMessage(type, requiredIndicator));
  71. return false;
  72. },
  73. /**
  74. * @private
  75. * @param {string} indicatorType
  76. * Indicator type
  77. * @param {string} required
  78. * Required indicator
  79. * @return {string}
  80. * Error message
  81. */
  82. generateMessage: function (indicatorType, required) {
  83. return 'Error: "' + indicatorType +
  84. '" indicator type requires "' + required +
  85. '" indicator loaded before. Please read docs: ' +
  86. 'https://api.highcharts.com/highstock/plotOptions.' +
  87. indicatorType;
  88. }
  89. };
  90. return requiredIndicatorMixin;
  91. });
  92. _registerModule(_modules, 'Stock/Indicators/Indicators.js', [_modules['Core/Globals.js'], _modules['Mixins/IndicatorRequired.js'], _modules['Core/Utilities.js']], function (H, requiredIndicator, U) {
  93. /* *
  94. *
  95. * License: www.highcharts.com/license
  96. *
  97. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  98. *
  99. * */
  100. var addEvent = U.addEvent,
  101. error = U.error,
  102. extend = U.extend,
  103. isArray = U.isArray,
  104. pick = U.pick,
  105. seriesType = U.seriesType,
  106. splat = U.splat;
  107. var Series = H.Series,
  108. seriesTypes = H.seriesTypes,
  109. ohlcProto = H.seriesTypes.ohlc.prototype,
  110. generateMessage = requiredIndicator.generateMessage;
  111. /**
  112. * The parameter allows setting line series type and use OHLC indicators. Data
  113. * in OHLC format is required.
  114. *
  115. * @sample {highstock} stock/indicators/use-ohlc-data
  116. * Plot line on Y axis
  117. *
  118. * @type {boolean}
  119. * @product highstock
  120. * @apioption plotOptions.line.useOhlcData
  121. */
  122. /* eslint-disable no-invalid-this */
  123. addEvent(H.Series, 'init', function (eventOptions) {
  124. var series = this,
  125. options = eventOptions.options;
  126. if (options.useOhlcData &&
  127. options.id !== 'highcharts-navigator-series') {
  128. extend(series, {
  129. pointValKey: ohlcProto.pointValKey,
  130. keys: ohlcProto.keys,
  131. pointArrayMap: ohlcProto.pointArrayMap,
  132. toYData: ohlcProto.toYData
  133. });
  134. }
  135. });
  136. addEvent(Series, 'afterSetOptions', function (e) {
  137. var options = e.options,
  138. dataGrouping = options.dataGrouping;
  139. if (dataGrouping &&
  140. options.useOhlcData &&
  141. options.id !== 'highcharts-navigator-series') {
  142. dataGrouping.approximation = 'ohlc';
  143. }
  144. });
  145. /* eslint-enable no-invalid-this */
  146. /**
  147. * The SMA series type.
  148. *
  149. * @private
  150. * @class
  151. * @name Highcharts.seriesTypes.sma
  152. *
  153. * @augments Highcharts.Series
  154. */
  155. seriesType('sma', 'line',
  156. /**
  157. * Simple moving average indicator (SMA). This series requires `linkedTo`
  158. * option to be set.
  159. *
  160. * @sample stock/indicators/sma
  161. * Simple moving average indicator
  162. *
  163. * @extends plotOptions.line
  164. * @since 6.0.0
  165. * @excluding allAreas, colorAxis, dragDrop, joinBy, keys,
  166. * navigatorOptions, pointInterval, pointIntervalUnit,
  167. * pointPlacement, pointRange, pointStart, showInNavigator,
  168. * stacking, useOhlcData
  169. * @product highstock
  170. * @requires stock/indicators/indicators
  171. * @optionparent plotOptions.sma
  172. */
  173. {
  174. /**
  175. * The name of the series as shown in the legend, tooltip etc. If not
  176. * set, it will be based on a technical indicator type and default
  177. * params.
  178. *
  179. * @type {string}
  180. */
  181. name: void 0,
  182. tooltip: {
  183. /**
  184. * Number of decimals in indicator series.
  185. */
  186. valueDecimals: 4
  187. },
  188. /**
  189. * The main series ID that indicator will be based on. Required for this
  190. * indicator.
  191. *
  192. * @type {string}
  193. */
  194. linkedTo: void 0,
  195. /**
  196. * Whether to compare indicator to the main series values
  197. * or indicator values.
  198. *
  199. * @sample {highstock} stock/plotoptions/series-comparetomain/
  200. * Difference between comparing SMA values to the main series
  201. * and its own values.
  202. *
  203. * @type {boolean}
  204. */
  205. compareToMain: false,
  206. /**
  207. * Paramters used in calculation of regression series' points.
  208. */
  209. params: {
  210. /**
  211. * The point index which indicator calculations will base. For
  212. * example using OHLC data, index=2 means the indicator will be
  213. * calculated using Low values.
  214. */
  215. index: 0,
  216. /**
  217. * The base period for indicator calculations. This is the number of
  218. * data points which are taken into account for the indicator
  219. * calculations.
  220. */
  221. period: 14
  222. }
  223. },
  224. /**
  225. * @lends Highcharts.Series.prototype
  226. */
  227. {
  228. processData: function () {
  229. var series = this,
  230. compareToMain = series.options.compareToMain,
  231. linkedParent = series.linkedParent;
  232. Series.prototype.processData.apply(series, arguments);
  233. if (linkedParent && linkedParent.compareValue && compareToMain) {
  234. series.compareValue = linkedParent.compareValue;
  235. }
  236. return;
  237. },
  238. bindTo: {
  239. series: true,
  240. eventName: 'updatedData'
  241. },
  242. hasDerivedData: true,
  243. useCommonDataGrouping: true,
  244. nameComponents: ['period'],
  245. nameSuffixes: [],
  246. calculateOn: 'init',
  247. // Defines on which other indicators is this indicator based on.
  248. requiredIndicators: [],
  249. requireIndicators: function () {
  250. var obj = {
  251. allLoaded: true
  252. };
  253. // Check whether all required indicators are loaded, else return
  254. // the object with missing indicator's name.
  255. this.requiredIndicators.forEach(function (indicator) {
  256. if (seriesTypes[indicator]) {
  257. seriesTypes[indicator].prototype.requireIndicators();
  258. }
  259. else {
  260. obj.allLoaded = false;
  261. obj.needed = indicator;
  262. }
  263. });
  264. return obj;
  265. },
  266. init: function (chart, options) {
  267. var indicator = this,
  268. requiredIndicators = indicator.requireIndicators();
  269. // Check whether all required indicators are loaded.
  270. if (!requiredIndicators.allLoaded) {
  271. return error(generateMessage(indicator.type, requiredIndicators.needed));
  272. }
  273. Series.prototype.init.call(indicator, chart, options);
  274. // Make sure we find series which is a base for an indicator
  275. chart.linkSeries();
  276. indicator.dataEventsToUnbind = [];
  277. /**
  278. * @private
  279. * @return {void}
  280. */
  281. function recalculateValues() {
  282. var oldData = indicator.points || [],
  283. oldDataLength = (indicator.xData || []).length,
  284. processedData = indicator.getValues(indicator.linkedParent,
  285. indicator.options.params) || {
  286. values: [],
  287. xData: [],
  288. yData: []
  289. },
  290. croppedDataValues = [],
  291. overwriteData = true,
  292. oldFirstPointIndex,
  293. oldLastPointIndex,
  294. croppedData,
  295. min,
  296. max,
  297. i;
  298. // We need to update points to reflect changes in all,
  299. // x and y's, values. However, do it only for non-grouped
  300. // data - grouping does it for us (#8572)
  301. if (oldDataLength &&
  302. !indicator.hasGroupedData &&
  303. indicator.visible &&
  304. indicator.points) {
  305. // When data is cropped update only avaliable points (#9493)
  306. if (indicator.cropped) {
  307. if (indicator.xAxis) {
  308. min = indicator.xAxis.min;
  309. max = indicator.xAxis.max;
  310. }
  311. croppedData = indicator.cropData(processedData.xData, processedData.yData, min, max);
  312. for (i = 0; i < croppedData.xData.length; i++) {
  313. // (#10774)
  314. croppedDataValues.push([
  315. croppedData.xData[i]
  316. ].concat(splat(croppedData.yData[i])));
  317. }
  318. oldFirstPointIndex = processedData.xData.indexOf(indicator.xData[0]);
  319. oldLastPointIndex = processedData.xData.indexOf(indicator.xData[indicator.xData.length - 1]);
  320. // Check if indicator points should be shifted (#8572)
  321. if (oldFirstPointIndex === -1 &&
  322. oldLastPointIndex === processedData.xData.length - 2) {
  323. if (croppedDataValues[0][0] === oldData[0].x) {
  324. croppedDataValues.shift();
  325. }
  326. }
  327. indicator.updateData(croppedDataValues);
  328. // Omit addPoint() and removePoint() cases
  329. }
  330. else if (processedData.xData.length !== oldDataLength - 1 &&
  331. processedData.xData.length !== oldDataLength + 1) {
  332. overwriteData = false;
  333. indicator.updateData(processedData.values);
  334. }
  335. }
  336. if (overwriteData) {
  337. indicator.xData = processedData.xData;
  338. indicator.yData = processedData.yData;
  339. indicator.options.data = processedData.values;
  340. }
  341. // Removal of processedXData property is required because on
  342. // first translate processedXData array is empty
  343. if (indicator.bindTo.series === false) {
  344. delete indicator.processedXData;
  345. indicator.isDirty = true;
  346. indicator.redraw();
  347. }
  348. indicator.isDirtyData = false;
  349. }
  350. if (!indicator.linkedParent) {
  351. return error('Series ' +
  352. indicator.options.linkedTo +
  353. ' not found! Check `linkedTo`.', false, chart);
  354. }
  355. indicator.dataEventsToUnbind.push(addEvent(indicator.bindTo.series ?
  356. indicator.linkedParent : indicator.linkedParent.xAxis, indicator.bindTo.eventName, recalculateValues));
  357. if (indicator.calculateOn === 'init') {
  358. recalculateValues();
  359. }
  360. else {
  361. var unbinder = addEvent(indicator.chart,
  362. indicator.calculateOn,
  363. function () {
  364. recalculateValues();
  365. // Call this just once, on init
  366. unbinder();
  367. });
  368. }
  369. return indicator;
  370. },
  371. getName: function () {
  372. var name = this.name,
  373. params = [];
  374. if (!name) {
  375. (this.nameComponents || []).forEach(function (component, index) {
  376. params.push(this.options.params[component] +
  377. pick(this.nameSuffixes[index], ''));
  378. }, this);
  379. name = (this.nameBase || this.type.toUpperCase()) +
  380. (this.nameComponents ? ' (' + params.join(', ') + ')' : '');
  381. }
  382. return name;
  383. },
  384. getValues: function (series, params) {
  385. var period = params.period,
  386. xVal = series.xData,
  387. yVal = series.yData,
  388. yValLen = yVal.length,
  389. range = 0,
  390. sum = 0,
  391. SMA = [],
  392. xData = [],
  393. yData = [],
  394. index = -1,
  395. i,
  396. SMAPoint;
  397. if (xVal.length < period) {
  398. return;
  399. }
  400. // Switch index for OHLC / Candlestick / Arearange
  401. if (isArray(yVal[0])) {
  402. index = params.index ? params.index : 0;
  403. }
  404. // Accumulate first N-points
  405. while (range < period - 1) {
  406. sum += index < 0 ? yVal[range] : yVal[range][index];
  407. range++;
  408. }
  409. // Calculate value one-by-one for each period in visible data
  410. for (i = range; i < yValLen; i++) {
  411. sum += index < 0 ? yVal[i] : yVal[i][index];
  412. SMAPoint = [xVal[i], sum / period];
  413. SMA.push(SMAPoint);
  414. xData.push(SMAPoint[0]);
  415. yData.push(SMAPoint[1]);
  416. sum -= (index < 0 ?
  417. yVal[i - range] :
  418. yVal[i - range][index]);
  419. }
  420. return {
  421. values: SMA,
  422. xData: xData,
  423. yData: yData
  424. };
  425. },
  426. destroy: function () {
  427. this.dataEventsToUnbind.forEach(function (unbinder) {
  428. unbinder();
  429. });
  430. Series.prototype.destroy.apply(this, arguments);
  431. }
  432. });
  433. /**
  434. * A `SMA` series. If the [type](#series.sma.type) option is not specified, it
  435. * is inherited from [chart.type](#chart.type).
  436. *
  437. * @extends series,plotOptions.sma
  438. * @since 6.0.0
  439. * @product highstock
  440. * @excluding dataParser, dataURL, useOhlcData
  441. * @requires stock/indicators/indicators
  442. * @apioption series.sma
  443. */
  444. ''; // adds doclet above to the transpiled file
  445. });
  446. _registerModule(_modules, 'masters/indicators/indicators.src.js', [], function () {
  447. });
  448. }));