Repository: cinar/indicatorts (ts)

Issue:
Trend: Commodity Channel Index (CCI)
The Commodity Channel Index​ (CCI) is a momentum-based oscillator used to help determine when an investment vehicle is reaching a condition of being overbought or oversold.

https://www.investopedia.com/terms/c/commoditychannelindex.asp


Pull request:
Community Channel Index (CMI) added.
# Describe Request

Community Channel Index (CMI).

Fixed #10

# Change Type

New Indicator.


Patch:
diff --git a/README.md b/README.md
index 853062c..d3fc89e 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,7 @@ The following list of indicators are currently supported by this package:
 - [Aroon Indicator](src/indicator/trend/index.md#aroon-indicator)
 - [Balance of Power (BOP)](src/indicator/trend/index.md#balance-of-power-bop)
 - [Chande Forecast Oscillator (CFO)](src/indicator/trend/index.md#chande-forecast-oscillator-cfo)
+- [Community Channel Index (CMI)](src/indicator/trend/index.md#community-channel-index-cmi)
 - [Double Exponential Moving Average (DEMA)](src/indicator/trend/index.md#double-exponential-moving-average-dema)
 - [Exponential Moving Average (EMA)](src/indicator/trend/index.md#exponential-moving-average-ema)
 - [Moving Average Convergence Divergence (MACD)](src/indicator/trend/index.md#moving-average-convergence-divergence-macd)
diff --git a/src/index.ts b/src/index.ts
index fc96fb5..840bb9a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -25,6 +25,7 @@ export * from './indicator/trend/absolutePriceOscillator';
 export * from './indicator/trend/aroon';
 export * from './indicator/trend/balanceOfPower';
 export * from './indicator/trend/chandeForecastOscillator';
+export * from './indicator/trend/communityChannelIndex';
 export * from './indicator/trend/dema';
 export * from './indicator/trend/ema';
 export * from './indicator/trend/kdj';
diff --git a/src/indicator/trend/communityChannelIndex.ts b/src/indicator/trend/communityChannelIndex.ts
new file mode 100644
index 0000000..6631e9a
--- /dev/null
+++ b/src/indicator/trend/communityChannelIndex.ts
@@ -0,0 +1,55 @@
+// Copyright (c) 2022 Onur Cinar. All Rights Reserved.
+// https://github.com/cinar/indicatorts
+
+import { abs, divide, multiplyBy, substract } from '../../helper/numArray';
+import { sma } from './sma';
+import { typicalPrice } from './typicalPrice';
+
+/**
+ * Default period of CMI.
+ */
+export const CMI_PERIOD = 20;
+
+/**
+ * The Community Channel Index (CMI) 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)
+ *
+ * @param period window period.
+ * @param highs high values.
+ * @param lows low values.
+ * @param closings closing values.
+ * @returns cmi values.
+ */
+export function communityChannelIndex(
+  period: number,
+  highs: number[],
+  lows: number[],
+  closings: number[]
+): number[] {
+  const tp = typicalPrice(highs, lows, closings);
+  const ma = sma(period, tp);
+  const md = sma(period, abs(substract(tp, ma)));
+  const cci = divide(substract(tp, ma), multiplyBy(0.015, md));
+  return cci;
+}
+
+/**
+ * The default community channel index with the period of 20.
+ *
+ * @param highs high values.
+ * @param lows low values.
+ * @param closings closing values.
+ * @returns cmi values.
+ */
+export function defaultCommunityChannelIndex(
+  highs: number[],
+  lows: number[],
+  closings: number[]
+): number[] {
+  return communityChannelIndex(CMI_PERIOD, highs, lows, closings);
+}
diff --git a/src/indicator/trend/index.md b/src/indicator/trend/index.md
index e1d5959..082dcf3 100644
--- a/src/indicator/trend/index.md
+++ b/src/indicator/trend/index.md
@@ -6,6 +6,7 @@ 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)
@@ -87,6 +88,30 @@ 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.


Test patch:
diff --git a/src/indicator/trend/communityChannelIndex.test.ts b/src/indicator/trend/communityChannelIndex.test.ts
new file mode 100644
index 0000000..fd7d37d
--- /dev/null
+++ b/src/indicator/trend/communityChannelIndex.test.ts
@@ -0,0 +1,17 @@
+// Copyright (c) 2022 Onur Cinar. All Rights Reserved.
+// https://github.com/cinar/indicatorts
+
+import { roundDigitsAll } from '../../helper/numArray';
+import { defaultCommunityChannelIndex } from './communityChannelIndex';
+
+describe('Community Channel Index (CMI)', () => {
+  it('should be able to compute CMI', () => {
+    const highs = [10, 9, 12, 14, 12];
+    const lows = [6, 7, 9, 12, 10];
+    const closings = [9, 11, 7, 10, 8];
+    const expected = [NaN, 133.33, 114.29, 200, 26.32];
+
+    const actual = defaultCommunityChannelIndex(highs, lows, closings);
+    expect(roundDigitsAll(2, actual)).toStrictEqual(expected);
+  });
+});