Repository: cinar/indicatorts (ts)

Issue:
Trend: Trix (TRIX)
The triple exponential average (TRIX) indicator is an oscillator used to identify oversold and overbought markets, and it can also be used as a momentum indicator. Like many oscillators, TRIX oscillates around a zero line.

https://www.investopedia.com/articles/technical/02/092402.asp


Pull request description:
Triple Exponential Average (TRIX) is added.
# Describe Request

Triple Exponential Average (TRIX).

Fixed #8

# Change Type

New Indicator.


Patch:
diff --git a/README.md b/README.md
index d3fc89e..63cdd50 100644
--- a/README.md
+++ b/README.md
@@ -30,8 +30,9 @@ The following list of indicators are currently supported by this package:
 - [Random Index (KDJ)](src/indicator/trend/index.md#random-index-kdj)
 - [Simple Moving Average (SMA)](src/indicator/trend/index.md#simple-moving-average-sma)
 - [Since Change](src/indicator/trend/index.md#since-change)
-- [Triangular Moving Average (TRIMA)](src/indicator/trend/index.md#triangular-moving-average-trima)
 - [Triple Exponential Moving Average (TEMA)](src/indicator/trend/index.md#triple-exponential-moving-average-tema)
+- [Triangular Moving Average (TRIMA)](src/indicator/trend/index.md#triangular-moving-average-trima)
+- [Triple Exponential Average (TRIX)](#triple-exponential-average-trix)
 - [Typical Price](src/indicator/trend/index.md#typical-price)
 - [Vortex Indicator](src/indicator/trend/index.md#vortex-indicator)
 
diff --git a/src/helper/numArray.ts b/src/helper/numArray.ts
index 5b70867..8a89dac 100644
--- a/src/helper/numArray.ts
+++ b/src/helper/numArray.ts
@@ -163,17 +163,22 @@ export function substractBy(n: number, values: number[]): number[] {
 }
 
 /**
- * Shifts values right by given amount.
+ * Shift values right by given amount and fill with value.
  * @param n shift amount.
+ * @param fill fill value.
  * @param values values array.
- * @return shifted values.
+ * @returns shifted and filled values.
  */
-export function shiftRightBy(n: number, values: number[]): number[] {
+export function shiftRightAndFillBy(
+  n: number,
+  fill: number,
+  values: number[]
+): number[] {
   const result = new Array<number>(values.length);
 
   for (let i = 0; i < result.length; i++) {
     if (i < n) {
-      result[i] = 0;
+      result[i] = fill;
     } else {
       result[i] = values[i - n];
     }
@@ -182,6 +187,16 @@ export function shiftRightBy(n: number, values: number[]): number[] {
   return result;
 }
 
+/**
+ * Shifts values right by given amount.
+ * @param n shift amount.
+ * @param values values array.
+ * @return shifted values.
+ */
+export function shiftRightBy(n: number, values: number[]): number[] {
+  return shiftRightAndFillBy(n, 0, values);
+}
+
 /**
  * Change between the current value and the value n before.
  * @param n shift amount.
diff --git a/src/index.ts b/src/index.ts
index 840bb9a..7bad7e0 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -39,6 +39,7 @@ export * from './indicator/trend/since';
 export * from './indicator/trend/sma';
 export * from './indicator/trend/tema';
 export * from './indicator/trend/trima';
+export * from './indicator/trend/trix';
 export * from './indicator/trend/typicalPrice';
 export * from './indicator/trend/vortex';
 export * from './indicator/volatility/accelerationBands';
diff --git a/src/indicator/trend/index.md b/src/indicator/trend/index.md
index 082dcf3..09320f9 100644
--- a/src/indicator/trend/index.md
+++ b/src/indicator/trend/index.md
@@ -6,7 +6,6 @@ Trend indicators measure the direction and strength of a trend.
 - [Aroon Indicator](#aroon-indicator)
 - [Balance of Power (BOP)](trend_indicators.md#balance-of-power-bop)
 - [Chande Forecast Oscillator (CFO)](#chande-forecast-oscillator-cfo)
-- [Community Channel Index (CMI)](#community-channel-index-cmi)
 - [Double Exponential Moving Average (DEMA)](#double-exponential-moving-average-dema)
 - [Exponential Moving Average (EMA)](#exponential-moving-average-ema)
 - [Moving Average Convergence Divergence (MACD)](#moving-average-convergence-divergence-macd)
@@ -18,8 +17,9 @@ Trend indicators measure the direction and strength of a trend.
 - [Random Index (KDJ)](#random-index-kdj)
 - [Simple Moving Average (SMA)](#simple-moving-average-sma)
 - [Since Change](#since-change)
-- [Triangular Moving Average (TRIMA)](#triangular-moving-average-trima)
 - [Triple Exponential Moving Average (TEMA)](#triple-exponential-moving-average-tema)
+- [Triangular Moving Average (TRIMA)](#triangular-moving-average-trima)
+- [Triple Exponential Average (TRIX)](#triple-exponential-average-trix)
 - [Typical Price](#typical-price)
 - [Vortex Indicator](#vortex-indicator)
 
@@ -88,30 +88,6 @@ import {chandeForecastOscillator} from 'indicatorts';
 const cfo = chandeForecastOscillator(closings);
 ```
 
-#### Community Channel Index (CMI)
-
-The [communityChannelIndex](./communityChannelIndex.ts) is a momentum-based oscillator used to help determine when an investment vehicle is reaching a condition of being overbought or oversold.
-
-```
-Moving Average = Sma(Period, Typical Price)
-Mean Deviation = Sma(Period, Abs(Typical Price - Moving Average))
-CMI = (Typical Price - Moving Average) / (0.015 * Mean Deviation)
-```
-
-```TypeScript
-import {communityChannelIndex} from 'indicatorts';
-
-const result = communityChannelIndex(period, highs, lows, closings);
-```
-
-The [defaultCommunityChannelIndex](./communityChannelIndex.ts) calculates with the period of 20.
-
-```TypeScript
-import {defaultCommunityChannelIndex} from 'indicatorts';
-
-const result = defaultCommunityChannelIndex(highs, lows, closings);
-```
-
 #### Double Exponential Moving Average (DEMA)
 
 The [dema](./dema.ts) function calculates the Double Exponential Moving Average (DEMA) for a given period.
@@ -278,6 +254,27 @@ import {since} from 'indicatorts';
 const result = since(values);
 ```
 
+#### Triple Exponential Moving Average (TEMA)
+
+The [tema](./tema.ts) function calculates the Triple Exponential Moving Average (TEMA) for a given period.
+
+The triple exponential moving average (TEMA) was designed to smooth value fluctuations, thereby making it easier to identify trends without the lag associated with traditional moving averages. It does this by taking multiple exponential moving averages (EMA) of the original EMA and subtracting out some of the lag.
+
+```
+TEMA = (3 * EMA1) - (3 * EMA2) + EMA3
+EMA1 = EMA(values)
+EMA2 = EMA(EMA1)
+EMA3 = EMA(EMA2)
+```
+
+```TypeScript
+import {tema} from 'indicatorts';
+
+const result = tema(period, values);
+```
+
+Based on [Triple Exponential Moving Average (TEMA)](https://www.investopedia.com/terms/t/triple-exponential-moving-average.asp).
+
 #### Triangular Moving Average (TRIMA)
 
 The [trima](./trima.ts) function calculates the Triangular Moving Average (TRIMA) for a given period.
@@ -299,27 +296,23 @@ const result = trima(period, values);
 
 Based on [Triangular Moving Average](https://tulipindicators.org/trima).
 
-#### Triple Exponential Moving Average (TEMA)
-
-The [tema](./tema.ts) function calculates the Triple Exponential Moving Average (TEMA) for a given period.
+#### Triple Exponential Average (TRIX)
 
-The triple exponential moving average (TEMA) was designed to smooth value fluctuations, thereby making it easier to identify trends without the lag associated with traditional moving averages. It does this by taking multiple exponential moving averages (EMA) of the original EMA and subtracting out some of the lag.
+The [trix](./trix.ts) indicator is an oscillator used to identify oversold and overbought markets, and it can also be used as a momentum indicator. Like many oscillators, TRIX oscillates around a zero line.
 
 ```
-TEMA = (3 * EMA1) - (3 * EMA2) + EMA3
-EMA1 = EMA(values)
-EMA2 = EMA(EMA1)
-EMA3 = EMA(EMA2)
+EMA1 = EMA(period, values)
+EMA2 = EMA(period, EMA1)
+EMA3 = EMA(period, EMA2)
+TRIX = (EMA3 - Previous EMA3) / Previous EMA3
 ```
 
 ```TypeScript
-import {tema} from 'indicatorts';
+import {trix} from 'indicatorts';
 
-const result = tema(period, values);
+const result = trix(period, values);
 ```
 
-Based on [Triple Exponential Moving Average (TEMA)](https://www.investopedia.com/terms/t/triple-exponential-moving-average.asp).
-
 #### Typical Price
 
 The [typicalPrice](./typicalPrice.ts) function calculates another approximation of average price for each period and can be used as a filter for moving average systems.
diff --git a/src/indicator/trend/trix.ts b/src/indicator/trend/trix.ts
new file mode 100644
index 0000000..5e1700a
--- /dev/null
+++ b/src/indicator/trend/trix.ts
@@ -0,0 +1,29 @@
+// Copyright (c) 2022 Onur Cinar. All Rights Reserved.
+// https://github.com/cinar/indicatorts
+
+import { divide, shiftRightAndFillBy, substract } from '../../helper/numArray';
+import { ema } from './ema';
+
+/**
+ * Triple Exponential Average (TRIX) indicator is an oscillator used to
+ * identify oversold and overbought markets, and it can also be used
+ * as a momentum indicator. Like many oscillators, TRIX oscillates
+ * around a zero line.
+ *
+ * EMA1 = EMA(period, values)
+ * EMA2 = EMA(period, EMA1)
+ * EMA3 = EMA(period, EMA2)
+ * TRIX = (EMA3 - Previous EMA3) / Previous EMA3
+ *
+ * @param period window period.
+ * @param values values array.
+ * @returns trix values.
+ */
+export function trix(period: number, values: number[]): number[] {
+  const ema1 = ema(period, values);
+  const ema2 = ema(period, ema1);
+  const ema3 = ema(period, ema2);
+  const previous = shiftRightAndFillBy(1, ema3[0], ema3);
+  const trix = divide(substract(ema3, previous), previous);
+  return trix;
+}
diff --git a/src/indicator/volume/volumePriceTrend.ts b/src/indicator/volume/volumePriceTrend.ts
index 326f7d0..fadc287 100644
--- a/src/indicator/volume/volumePriceTrend.ts
+++ b/src/indicator/volume/volumePriceTrend.ts
@@ -4,7 +4,7 @@
 import {
   divide,
   multiply,
-  shiftRightBy,
+  shiftRightAndFillBy,
   substract,
 } from '../../helper/numArray';
 import { msum } from '../trend/msum';
@@ -23,9 +23,7 @@ export function volumePriceTrend(
   closings: number[],
   volumes: number[]
 ): number[] {
-  const previousClosings = shiftRightBy(1, closings);
-  // TODO: Consider changing shiftRightBy to fill with last value.
-  previousClosings[0] = closings[0];
+  const previousClosings = shiftRightAndFillBy(1, closings[0], closings);
   const vpt = multiply(
     volumes,
     divide(substract(closings, previousClosings), previousClosings)


Test patch:
diff --git a/src/helper/numArray.test.ts b/src/helper/numArray.test.ts
index ec034ab..b5d1ae5 100644
--- a/src/helper/numArray.test.ts
+++ b/src/helper/numArray.test.ts
@@ -85,6 +85,15 @@ describe('Number Array', () => {
     deepStrictEqual(actual, expected);
   });
 
+  it('should be able to shift and fill values', () => {
+    const values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+    const expected = [1, 1, 1, 2, 3, 4, 5, 6, 7, 8];
+    const n = 2;
+
+    const actual = NumArray.shiftRightAndFillBy(n, values[0], values);
+    deepStrictEqual(actual, expected);
+  });
+
   it('should be able to shift values', () => {
     const values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
     const expected = [0, 0, 1, 2, 3, 4, 5, 6, 7, 8];
diff --git a/src/indicator/trend/trix.test.ts b/src/indicator/trend/trix.test.ts
new file mode 100644
index 0000000..9ac774b
--- /dev/null
+++ b/src/indicator/trend/trix.test.ts
@@ -0,0 +1,16 @@
+// Copyright (c) 2022 Onur Cinar. All Rights Reserved.
+// https://github.com/cinar/indicatorts
+
+import { roundDigitsAll } from '../../helper/numArray';
+import { trix } from './trix';
+
+describe('Triple Exponential Average (TRIX)', () => {
+  it('should be able to compute TRIX', () => {
+    const values = [2, 4, 6, 8, 12, 14, 16, 18, 20];
+    const period = 4;
+    const expected = [0, 0.06, 0.17, 0.26, 0.33, 0.33, 0.3, 0.25, 0.21];
+
+    const actual = trix(period, values);
+    expect(roundDigitsAll(2, actual)).toStrictEqual(expected);
+  });
+});