Repository: cinar/indicatorts (ts)

Issue:
Make RSI use RMA.
As reported in https://github.com/cinar/indicator/issues/68. Currently RSI is using SMA but it should be using RMA instead.



Pull request:
Make RSI use RMA.
Fixes #39

# Describe Request

Added Rolling Moving Average (RMA) indicator, and made RSI use RMA.

Fixed # 39.

# Change Type

Fixed bug.


Patch:
diff --git a/README.md b/README.md
index 50c1483..974100a 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,7 @@ The following list of indicators are currently supported by this package:
 - [Parabolic SAR](src/indicator/trend/index.md#parabolic-sar)
 - [Qstick](src/indicator/trend/index.md#qstick)
 - [Random Index (KDJ)](src/indicator/trend/index.md#random-index-kdj)
+- [Rolling Moving Average (RMA)](src/indicator/trend/index.md#rolling-moving-average-rma)
 - [Simple Moving Average (SMA)](src/indicator/trend/index.md#simple-moving-average-sma)
 - [Since Change](src/indicator/trend/index.md#since-change)
 - [Triple Exponential Moving Average (TEMA)](src/indicator/trend/index.md#triple-exponential-moving-average-tema)
diff --git a/src/index.ts b/src/index.ts
index 24d667a..b0d10bb 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -37,6 +37,7 @@ export * from './indicator/trend/msum';
 export * from './indicator/trend/parabolicSar';
 export * from './indicator/trend/qstick';
 export * from './indicator/trend/since';
+export * from './indicator/trend/rma';
 export * from './indicator/trend/sma';
 export * from './indicator/trend/tema';
 export * from './indicator/trend/trima';
diff --git a/src/indicator/momentum/rsi.ts b/src/indicator/momentum/rsi.ts
index dd49179..a0f0969 100644
--- a/src/indicator/momentum/rsi.ts
+++ b/src/indicator/momentum/rsi.ts
@@ -1,7 +1,7 @@
 // Copyright (c) 2022 Onur Cinar. All Rights Reserved.
 // https://github.com/cinar/indicatorts
 
-import { sma } from '../trend/sma';
+import { rma } from '../trend/rma';
 
 /**
  * Relative Strength Index (RSI). It is a momentum indicator that measures
@@ -30,8 +30,8 @@ export function rsi(closings: number[]): number[] {
     }
   }
 
-  const meanGains = sma(14, gains);
-  const meanLosses = sma(14, losses);
+  const meanGains = rma(14, gains);
+  const meanLosses = rma(14, losses);
 
   const r = new Array<number>(closings.length);
   const rs = new Array<number>(closings.length);
diff --git a/src/indicator/trend/index.md b/src/indicator/trend/index.md
index 3f0ddfb..faab77d 100644
--- a/src/indicator/trend/index.md
+++ b/src/indicator/trend/index.md
@@ -17,6 +17,7 @@ Trend indicators measure the direction and strength of a trend.
 - [Parabolic SAR](#parabolic-sar)
 - [Qstick](trend_indicator.md#qstick)
 - [Random Index (KDJ)](#random-index-kdj)
+- [Rolling Moving Average (RMA)](#rolling-moving-average-rma)
 - [Simple Moving Average (SMA)](#simple-moving-average-sma)
 - [Since Change](#since-change)
 - [Triple Exponential Moving Average (TEMA)](#triple-exponential-moving-average-tema)
@@ -275,6 +276,21 @@ import {defaultKdj} from 'indicatorts';
 const result = defaultKdj(highs, lows, closings);
 ```
 
+#### Rolling Moving Average (RMA)
+
+The [rma](./rma.ts) function calculates the rolling moving average for a given period.
+
+```
+R[0] to R[p-1] is SMA(values)
+R[p] and after is R[i] = ((R[i-1]*(p-1)) + v[i]) / p
+```
+
+```TypeScript
+import {rma} from 'indicatorts';
+
+const result = rma(period, values);
+```
+
 #### Simple Moving Average (SMA)
 
 The [sma](./sma.ts) function calculates the simple moving average for a given period.
diff --git a/src/indicator/trend/rma.ts b/src/indicator/trend/rma.ts
new file mode 100644
index 0000000..e74c385
--- /dev/null
+++ b/src/indicator/trend/rma.ts
@@ -0,0 +1,32 @@
+// Copyright (c) 2022 Onur Cinar. All Rights Reserved.
+// https://github.com/cinar/indicatorts
+
+/**
+ * Rolling moving average (RMA).
+ *
+ * R[0] to R[p-1] is SMA(values)
+ * R[p] and after is R[i] = ((R[i-1]*(p-1)) + v[i]) / p
+ *
+ * @param period window period.
+ * @param values values array.
+ * @returns RMA values.
+ */
+export function rma(period: number, values: number[]): number[] {
+  const result = new Array<number>(values.length);
+  let sum = 0;
+
+  for (let i = 0; i < values.length; i++) {
+    let count = i + 1;
+
+    if (i < period) {
+      sum += values[i];
+    } else {
+      sum = result[i - 1] * (period - 1) + values[i];
+      count = period;
+    }
+
+    result[i] = sum / count;
+  }
+
+  return result;
+}


Test patch:
diff --git a/src/indicator/trend/rma.test.ts b/src/indicator/trend/rma.test.ts
new file mode 100644
index 0000000..3d40838
--- /dev/null
+++ b/src/indicator/trend/rma.test.ts
@@ -0,0 +1,17 @@
+// Copyright (c) 2022 Onur Cinar. All Rights Reserved.
+// https://github.com/cinar/indicatorts
+
+import { deepStrictEqual } from 'assert';
+import { roundDigitsAll } from '../../helper/numArray';
+import { rma } from './rma';
+
+describe('Rolling Moving Average (RMA)', () => {
+  it('should be able to compute rma', () => {
+    const values = [2, 4, 6, 8, 10, 12];
+    const expected = [2, 3, 4, 5, 6.25, 7.69];
+    const period = 4;
+
+    const actual = rma(period, values);
+    deepStrictEqual(roundDigitsAll(2, actual), expected);
+  });
+});