PSARIndicator.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /* *
  2. *
  3. * Parabolic SAR indicator for Highstock
  4. *
  5. * (c) 2010-2020 Grzegorz Blachliński
  6. *
  7. * License: www.highcharts.com/license
  8. *
  9. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  10. *
  11. * */
  12. 'use strict';
  13. import U from '../../Core/Utilities.js';
  14. var seriesType = U.seriesType;
  15. /* eslint-disable require-jsdoc */
  16. // Utils:
  17. function toFixed(a, n) {
  18. return parseFloat(a.toFixed(n));
  19. }
  20. function calculateDirection(previousDirection, low, high, PSAR) {
  21. if ((previousDirection === 1 && low > PSAR) ||
  22. (previousDirection === -1 && high > PSAR)) {
  23. return 1;
  24. }
  25. return -1;
  26. }
  27. /* *
  28. * Method for calculating acceleration factor
  29. * dir - direction
  30. * pDir - previous Direction
  31. * eP - extreme point
  32. * pEP - previous extreme point
  33. * inc - increment for acceleration factor
  34. * maxAcc - maximum acceleration factor
  35. * initAcc - initial acceleration factor
  36. */
  37. function getAccelerationFactor(dir, pDir, eP, pEP, pAcc, inc, maxAcc, initAcc) {
  38. if (dir === pDir) {
  39. if (dir === 1 && (eP > pEP)) {
  40. return (pAcc === maxAcc) ? maxAcc : toFixed(pAcc + inc, 2);
  41. }
  42. if (dir === -1 && (eP < pEP)) {
  43. return (pAcc === maxAcc) ? maxAcc : toFixed(pAcc + inc, 2);
  44. }
  45. return pAcc;
  46. }
  47. return initAcc;
  48. }
  49. function getExtremePoint(high, low, previousDirection, previousExtremePoint) {
  50. if (previousDirection === 1) {
  51. return (high > previousExtremePoint) ? high : previousExtremePoint;
  52. }
  53. return (low < previousExtremePoint) ? low : previousExtremePoint;
  54. }
  55. function getEPMinusPSAR(EP, PSAR) {
  56. return EP - PSAR;
  57. }
  58. function getAccelerationFactorMultiply(accelerationFactor, EPMinusSAR) {
  59. return accelerationFactor * EPMinusSAR;
  60. }
  61. /* *
  62. * Method for calculating PSAR
  63. * pdir - previous direction
  64. * sDir - second previous Direction
  65. * PSAR - previous PSAR
  66. * pACCMultiply - previous acceleration factor multiply
  67. * sLow - second previous low
  68. * pLow - previous low
  69. * sHigh - second previous high
  70. * pHigh - previous high
  71. * pEP - previous extreme point
  72. */
  73. function getPSAR(pdir, sDir, PSAR, pACCMulti, sLow, pLow, pHigh, sHigh, pEP) {
  74. if (pdir === sDir) {
  75. if (pdir === 1) {
  76. return (PSAR + pACCMulti < Math.min(sLow, pLow)) ?
  77. PSAR + pACCMulti :
  78. Math.min(sLow, pLow);
  79. }
  80. return (PSAR + pACCMulti > Math.max(sHigh, pHigh)) ?
  81. PSAR + pACCMulti :
  82. Math.max(sHigh, pHigh);
  83. }
  84. return pEP;
  85. }
  86. /* eslint-enable require-jsdoc */
  87. /**
  88. * The Parabolic SAR series type.
  89. *
  90. * @private
  91. * @class
  92. * @name Highcharts.seriesTypes.psar
  93. *
  94. * @augments Highcharts.Series
  95. */
  96. seriesType('psar', 'sma',
  97. /**
  98. * Parabolic SAR. This series requires `linkedTo`
  99. * option to be set and should be loaded
  100. * after `stock/indicators/indicators.js` file.
  101. *
  102. * @sample stock/indicators/psar
  103. * Parabolic SAR Indicator
  104. *
  105. * @extends plotOptions.sma
  106. * @since 6.0.0
  107. * @product highstock
  108. * @requires stock/indicators/indicators
  109. * @requires stock/indicators/psar
  110. * @optionparent plotOptions.psar
  111. */
  112. {
  113. lineWidth: 0,
  114. marker: {
  115. enabled: true
  116. },
  117. states: {
  118. hover: {
  119. lineWidthPlus: 0
  120. }
  121. },
  122. /**
  123. * @excluding period
  124. */
  125. params: {
  126. /**
  127. * The initial value for acceleration factor.
  128. * Acceleration factor is starting with this value
  129. * and increases by specified increment each time
  130. * the extreme point makes a new high.
  131. * AF can reach a maximum of maxAccelerationFactor,
  132. * no matter how long the uptrend extends.
  133. */
  134. initialAccelerationFactor: 0.02,
  135. /**
  136. * The Maximum value for acceleration factor.
  137. * AF can reach a maximum of maxAccelerationFactor,
  138. * no matter how long the uptrend extends.
  139. */
  140. maxAccelerationFactor: 0.2,
  141. /**
  142. * Acceleration factor increases by increment each time
  143. * the extreme point makes a new high.
  144. *
  145. * @since 6.0.0
  146. */
  147. increment: 0.02,
  148. /**
  149. * Index from which PSAR is starting calculation
  150. *
  151. * @since 6.0.0
  152. */
  153. index: 2,
  154. /**
  155. * Number of maximum decimals that are used in PSAR calculations.
  156. *
  157. * @since 6.0.0
  158. */
  159. decimals: 4
  160. }
  161. }, {
  162. nameComponents: false,
  163. getValues: function (series, params) {
  164. var xVal = series.xData, yVal = series.yData,
  165. // Extreme point is the lowest low for falling and highest high
  166. // for rising psar - and we are starting with falling
  167. extremePoint = yVal[0][1], accelerationFactor = params.initialAccelerationFactor, maxAccelerationFactor = params.maxAccelerationFactor, increment = params.increment,
  168. // Set initial acc factor (for every new trend!)
  169. initialAccelerationFactor = params.initialAccelerationFactor, PSAR = yVal[0][2], decimals = params.decimals, index = params.index, PSARArr = [], xData = [], yData = [], previousDirection = 1, direction, EPMinusPSAR, accelerationFactorMultiply, newDirection, prevLow, prevPrevLow, prevHigh, prevPrevHigh, newExtremePoint, high, low, ind;
  170. if (index >= yVal.length) {
  171. return;
  172. }
  173. for (ind = 0; ind < index; ind++) {
  174. extremePoint = Math.max(yVal[ind][1], extremePoint);
  175. PSAR = Math.min(yVal[ind][2], toFixed(PSAR, decimals));
  176. }
  177. direction = (yVal[ind][1] > PSAR) ? 1 : -1;
  178. EPMinusPSAR = getEPMinusPSAR(extremePoint, PSAR);
  179. accelerationFactor = params.initialAccelerationFactor;
  180. accelerationFactorMultiply = getAccelerationFactorMultiply(accelerationFactor, EPMinusPSAR);
  181. PSARArr.push([xVal[index], PSAR]);
  182. xData.push(xVal[index]);
  183. yData.push(toFixed(PSAR, decimals));
  184. for (ind = index + 1; ind < yVal.length; ind++) {
  185. prevLow = yVal[ind - 1][2];
  186. prevPrevLow = yVal[ind - 2][2];
  187. prevHigh = yVal[ind - 1][1];
  188. prevPrevHigh = yVal[ind - 2][1];
  189. high = yVal[ind][1];
  190. low = yVal[ind][2];
  191. // Null points break PSAR
  192. if (prevPrevLow !== null &&
  193. prevPrevHigh !== null &&
  194. prevLow !== null &&
  195. prevHigh !== null &&
  196. high !== null &&
  197. low !== null) {
  198. PSAR = getPSAR(direction, previousDirection, PSAR, accelerationFactorMultiply, prevPrevLow, prevLow, prevHigh, prevPrevHigh, extremePoint);
  199. newExtremePoint = getExtremePoint(high, low, direction, extremePoint);
  200. newDirection = calculateDirection(previousDirection, low, high, PSAR);
  201. accelerationFactor = getAccelerationFactor(newDirection, direction, newExtremePoint, extremePoint, accelerationFactor, increment, maxAccelerationFactor, initialAccelerationFactor);
  202. EPMinusPSAR = getEPMinusPSAR(newExtremePoint, PSAR);
  203. accelerationFactorMultiply = getAccelerationFactorMultiply(accelerationFactor, EPMinusPSAR);
  204. PSARArr.push([xVal[ind], toFixed(PSAR, decimals)]);
  205. xData.push(xVal[ind]);
  206. yData.push(toFixed(PSAR, decimals));
  207. previousDirection = direction;
  208. direction = newDirection;
  209. extremePoint = newExtremePoint;
  210. }
  211. }
  212. return {
  213. values: PSARArr,
  214. xData: xData,
  215. yData: yData
  216. };
  217. }
  218. });
  219. /**
  220. * A `PSAR` series. If the [type](#series.psar.type) option is not specified, it
  221. * is inherited from [chart.type](#chart.type).
  222. *
  223. * @extends series,plotOptions.psar
  224. * @since 6.0.0
  225. * @product highstock
  226. * @excluding dataParser, dataURL
  227. * @requires stock/indicators/indicators
  228. * @requires stock/indicators/psar
  229. * @apioption series.psar
  230. */
  231. ''; // to include the above in the js output