From d653c9fee00f81461948259ed2c96119883cb53e Mon Sep 17 00:00:00 2001 From: aquamanjl <35556329+aquamanjl@users.noreply.github.com> Date: Mon, 22 Jan 2018 06:01:40 -0500 Subject: [PATCH] Fixed StochRSI calculations (#1196) * Fix SRSI calculation * Added test case for SRSI. Switched RSI and SRSI output to float and adjusted display accordingly * Oops, disabled all other tests by mistake * Fix test assertion --- .gitignore | 2 + extensions/strategies/srsi_macd/strategy.js | 3 +- lib/rsi.js | 4 +- lib/srsi.js | 85 +++++++++++++++------ test/lib/rsi.test.js | 2 +- test/lib/srsi.test.js | 37 +++++++++ 6 files changed, 107 insertions(+), 26 deletions(-) create mode 100644 test/lib/srsi.test.js diff --git a/.gitignore b/.gitignore index 3bdb77862f..5bad1c04e7 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ temp.html logs .sync dist/* +.idea +*.iml diff --git a/extensions/strategies/srsi_macd/strategy.js b/extensions/strategies/srsi_macd/strategy.js index c184fcba42..11a646e8fc 100644 --- a/extensions/strategies/srsi_macd/strategy.js +++ b/extensions/strategies/srsi_macd/strategy.js @@ -67,7 +67,8 @@ module.exports = function container (get, set, clear) { color = 'red' } cols.push(z(8, n(s.period.macd_histogram).format('+00.0000'), ' ')[color]) - cols.push(z(8, n(s.period.srsi_K).format('000'), ' ').cyan) + cols.push(z(8, n(s.period.srsi_K).format('00.00'), ' ').cyan) + cols.push(z(8, n(s.period.srsi_D).format('00.00'), ' ').yellow) } else { cols.push(' ') diff --git a/lib/rsi.js b/lib/rsi.js index 5e2ca519ef..87ad80ec3f 100644 --- a/lib/rsi.js +++ b/lib/rsi.js @@ -1,3 +1,5 @@ +var mathjs = require('mathjs') + module.exports = function container (get, set, clear) { return function rsi (s, key, length) { if (s.lookback.length >= length) { @@ -32,7 +34,7 @@ module.exports = function container (get, set, clear) { s.period[key] = 100 } else { var rs = s.period[key + '_avg_gain'] / s.period[key + '_avg_loss'] - s.period[key] = Math.round(100 - (100 / (1 + rs))) + s.period[key] = mathjs.round(100 - (100 / (1 + rs)), 2) } } } diff --git a/lib/srsi.js b/lib/srsi.js index ba230c76c4..6fcd05d902 100644 --- a/lib/srsi.js +++ b/lib/srsi.js @@ -1,25 +1,64 @@ -module.exports = function container (get, set, clear) { - return function srsi (s, key, rsi_length, k, d) { - get('lib.rsi')(s, 'rsi', rsi_length) - let RSI = [] - let sum = 0 - if (typeof s.period.rsi !== 'undefined') - s.lookback.slice(0, k).forEach(function (period) { - if (period.rsi) - RSI.push(period.rsi) - }) - - let highestRSI = Math.max(...RSI) - let lowestRSI = Math.min(...RSI) - let stochK = ((s.period.rsi - lowestRSI) / (highestRSI - lowestRSI)) * 100 - - s.lookback.slice(0, d).forEach(period => { - if (period.srsi_K) - sum += period.srsi_K +var mathjs = require('mathjs'); + +module.exports = function container(get, set, clear) { + return function srsi(s, key, rsi_periods, k_periods, d_periods) { + let samplesRequiredForStochRSI = rsi_periods + k_periods + 1; + + if (s.lookback.length >= samplesRequiredForStochRSI - 1) { + let RSI = []; + + if (typeof s.period.rsi !== 'undefined') { + RSI.push(s.period.rsi); + } else { + get('lib.rsi')(s, 'rsi', rsi_periods); + RSI.push(s.period.rsi); + } + + s.lookback.slice(0, samplesRequiredForStochRSI - 1).forEach(function (period) { + if (period.rsi) { + RSI.push(period.rsi); + } }) - let stochD = sum / d - s.period[key + '_K'] = stochK - s.period[key + '_D'] = stochD - //console.log(s.lookback[0]) + + RSI.reverse(); + + if(RSI.length >= samplesRequiredForStochRSI) { + let stochRSI = []; + for(let i = 0; i < (k_periods + d_periods - 1); i++) { + let rsiForPeriod = RSI.slice(i, rsi_periods + i); + let highestRSI = Math.max(...rsiForPeriod); + let lowestRSI = Math.min(...rsiForPeriod); + if(highestRSI == lowestRSI) { + stochRSI.push(0); + } else { + stochRSI.push(((RSI[(rsi_periods - 1) + i] - lowestRSI) / (highestRSI - lowestRSI)) * 100); + } + } + + stochRSI.reverse(); + + let percentK = []; + for(let i = 0; i < k_periods; i++) { + let kData = stochRSI.slice(i, k_periods + i); + if(kData.length == k_periods) { + percentK.push(mathjs.mean(kData)); + } + } + + let percentD = []; + for(let i = 0; i < d_periods; i++) { + let dData = percentK.slice(i, d_periods + i); + if(dData.length == d_periods) { + percentD.push(mathjs.mean(dData)); + } + } + + s.period[key + '_K'] = percentK[0] == 0 ? 0 : mathjs.round(percentK[0], 2); + s.period[key + '_D'] = percentD[0] == 0 ? 0 : mathjs.round(percentD[0], 2); + + //console.log('lib.srsi: For RSI', RSI[RSI.length - 1], '-', '%K is', s.period[key + '_K'], ', %D is', s.period[key + '_D'], ', period info', s.period); + } + } } -} \ No newline at end of file +} + diff --git a/test/lib/rsi.test.js b/test/lib/rsi.test.js index e7f79d9351..8dd63bac2a 100644 --- a/test/lib/rsi.test.js +++ b/test/lib/rsi.test.js @@ -5,7 +5,7 @@ describe('RSI (Relative Strength Index)', function () { it('should calculate RSI with default period', function () { (RSI())(normalData, 'rsi', 14) - expect(normalData.period.rsi).toEqual(32) + expect(normalData.period.rsi).toEqual(32.26) }) it('should set RSI to 100 when there is no losses for the entire period', function() { diff --git a/test/lib/srsi.test.js b/test/lib/srsi.test.js new file mode 100644 index 0000000000..34720133d4 --- /dev/null +++ b/test/lib/srsi.test.js @@ -0,0 +1,37 @@ +var RSI = require('../../lib/rsi'); +var SRSI = require('../../lib/srsi')(RSI); + +describe('SRSI (StochRSI Oscillator)', function () { + + it('should calculate SRSI with default period', function () { + SRSI(data, 'srsi', 14, 3, 3); + + expect(data.period.srsi_K).toEqual(19.38); + expect(data.period.srsi_D).toEqual(23.18); + }) +}); + +var data = { + lookback: [ + {rsi: 64.38}, + {rsi: 66.71}, + {rsi: 70.29}, + {rsi: 66.49}, + {rsi: 71.47}, + {rsi: 76.17}, + {rsi: 83.66}, + {rsi: 81.85}, + {rsi: 82.55}, + {rsi: 82.89}, + {rsi: 78.60}, + {rsi: 64.78}, + {rsi: 64.77}, + {rsi: 70.05}, + {rsi: 68.76}, + {rsi: 69.53}, + {rsi: 70.15} + ].reverse(), + period: { + rsi: 65.61 + } +};