diff --git a/README.md b/README.md
index 64ab278..55c6687 100644
--- a/README.md
+++ b/README.md
@@ -109,6 +109,7 @@ The following list of strategies are currently supported by this package:
- [Balance of Power (BoP) Strategy](strategy/trend/README.md#type-bopstrategy)
- [Double Exponential Moving Average (DEMA) Strategy](strategy/trend/README.md#type-demastrategy)
- Chande Forecast Oscillator Strategy
+- [Community Channel Index (CCI) Strategy](strategy/trend/README.md#type-ccistrategy)
- [Random Index (KDJ) Strategy](strategy/trend/README.md#type-kdjstrategy)
- [Moving Average Convergence Divergence (MACD) Strategy](strategy/trend/README.md#type-macdstrategy)
- [Qstick Strategy](strategy/trend/README.md#type-qstickstrategy)
diff --git a/strategy/trend/README.md b/strategy/trend/README.md
index d228b3d..92220b1 100644
--- a/strategy/trend/README.md
+++ b/strategy/trend/README.md
@@ -41,6 +41,11 @@ The information provided on this project is strictly for informational purposes
- [func \(b \*BopStrategy\) Compute\(c \<\-chan \*asset.Snapshot\) \<\-chan strategy.Action](<#BopStrategy.Compute>)
- [func \(\*BopStrategy\) Name\(\) string](<#BopStrategy.Name>)
- [func \(b \*BopStrategy\) Report\(c \<\-chan \*asset.Snapshot\) \*helper.Report](<#BopStrategy.Report>)
+- [type CciStrategy](<#CciStrategy>)
+ - [func NewCciStrategy\(\) \*CciStrategy](<#NewCciStrategy>)
+ - [func \(t \*CciStrategy\) Compute\(c \<\-chan \*asset.Snapshot\) \<\-chan strategy.Action](<#CciStrategy.Compute>)
+ - [func \(\*CciStrategy\) Name\(\) string](<#CciStrategy.Name>)
+ - [func \(t \*CciStrategy\) Report\(c \<\-chan \*asset.Snapshot\) \*helper.Report](<#CciStrategy.Report>)
- [type DemaStrategy](<#DemaStrategy>)
- [func NewDemaStrategy\(\) \*DemaStrategy](<#NewDemaStrategy>)
- [func \(d \*DemaStrategy\) Compute\(c \<\-chan \*asset.Snapshot\) \<\-chan strategy.Action](<#DemaStrategy.Compute>)
@@ -274,6 +279,56 @@ func (b *BopStrategy) Report(c <-chan *asset.Snapshot) *helper.Report
Report processes the provided asset snapshots and generates a report annotated with the recommended actions.
+
+## type [CciStrategy]()
+
+CciStrategy represents the configuration parameters for calculating the CCI strategy. A CCI value crossing above the 100\+ suggests a bullish trend, while crossing below the 100\- indicates a bearish trend.
+
+```go
+type CciStrategy struct {
+ strategy.Strategy
+
+ // Cci represents the configuration parameters for calculating the CCI.
+ Cci *trend.Cci[float64]
+}
+```
+
+
+### func [NewCciStrategy]()
+
+```go
+func NewCciStrategy() *CciStrategy
+```
+
+NewCciStrategy function initializes a new CCI strategy instance.
+
+
+### func \(\*CciStrategy\) [Compute]()
+
+```go
+func (t *CciStrategy) Compute(c <-chan *asset.Snapshot) <-chan strategy.Action
+```
+
+Compute processes the provided asset snapshots and generates a stream of actionable recommendations.
+
+
+### func \(\*CciStrategy\) [Name]()
+
+```go
+func (*CciStrategy) Name() string
+```
+
+Name returns the name of the strategy.
+
+
+### func \(\*CciStrategy\) [Report]()
+
+```go
+func (t *CciStrategy) Report(c <-chan *asset.Snapshot) *helper.Report
+```
+
+Report processes the provided asset snapshots and generates a report annotated with the recommended actions.
+
## type [DemaStrategy]()
diff --git a/strategy/trend/cci_strategy.go b/strategy/trend/cci_strategy.go
new file mode 100644
index 0000000..f4f67ed
--- /dev/null
+++ b/strategy/trend/cci_strategy.go
@@ -0,0 +1,101 @@
+// Copyright (c) 2021-2023 Onur Cinar.
+// The source code is provided under GNU AGPLv3 License.
+// https://github.com/cinar/indicator
+
+package trend
+
+import (
+ "github.com/cinar/indicator/asset"
+ "github.com/cinar/indicator/helper"
+ "github.com/cinar/indicator/strategy"
+ "github.com/cinar/indicator/trend"
+)
+
+// CciStrategy represents the configuration parameters for calculating the CCI strategy.
+// A CCI value crossing above the 100+ suggests a bullish trend, while crossing below
+// the 100- indicates a bearish trend.
+type CciStrategy struct {
+ strategy.Strategy
+
+ // Cci represents the configuration parameters for calculating the CCI.
+ Cci *trend.Cci[float64]
+}
+
+// NewCciStrategy function initializes a new CCI strategy instance.
+func NewCciStrategy() *CciStrategy {
+ return &CciStrategy{
+ Cci: trend.NewCci[float64](),
+ }
+}
+
+// Name returns the name of the strategy.
+func (*CciStrategy) Name() string {
+ return "CCI Strategy"
+}
+
+// Compute processes the provided asset snapshots and generates a stream of actionable recommendations.
+func (t *CciStrategy) Compute(c <-chan *asset.Snapshot) <-chan strategy.Action {
+ snapshots := helper.Duplicate(c, 3)
+ highs := asset.SnapshotsAsHighs(snapshots[0])
+ lows := asset.SnapshotsAsHighs(snapshots[1])
+ closings := asset.SnapshotsAsHighs(snapshots[2])
+
+ ccis := t.Cci.Compute(highs, lows, closings)
+
+ actions := helper.Map(ccis, func(cci float64) strategy.Action {
+ if cci >= 100 {
+ return strategy.Buy
+ }
+
+ if cci <= -100 {
+ return strategy.Sell
+ }
+
+ return strategy.Hold
+ })
+
+ actions = strategy.NormalizeActions(actions)
+
+ // CCI starts only after a full period.
+ actions = helper.Shift(actions, t.Cci.IdlePeriod(), strategy.Hold)
+
+ return actions
+}
+
+// Report processes the provided asset snapshots and generates a report annotated with the recommended actions.
+func (t *CciStrategy) Report(c <-chan *asset.Snapshot) *helper.Report {
+ //
+ // snapshots[0] -> dates
+ // snapshots[1] -> highs |
+ // snapshots[2] -> lows |
+ // snapshots[3] -> closings[1] |> ccis
+ // closings[0] -> closings
+ // snapshots[4] -> actions -> annotations
+ // -> outcomes
+ //
+ snapshots := helper.Duplicate(c, 5)
+
+ dates := asset.SnapshotsAsDates(snapshots[0])
+ highs := asset.SnapshotsAsHighs(snapshots[1])
+ lows := asset.SnapshotsAsHighs(snapshots[2])
+ closings := helper.Duplicate(asset.SnapshotsAsHighs(snapshots[3]), 2)
+
+ ccis := t.Cci.Compute(highs, lows, closings[1])
+ ccis = helper.Shift(ccis, t.Cci.IdlePeriod(), 0)
+
+ actions, outcomes := strategy.ComputeWithOutcome(t, snapshots[4])
+ annotations := strategy.ActionsToAnnotations(actions)
+ outcomes = helper.MultiplyBy(outcomes, 100)
+
+ report := helper.NewReport(t.Name(), dates)
+ report.AddChart()
+ report.AddChart()
+
+ report.AddColumn(helper.NewNumericReportColumn("Close", closings[0]))
+ report.AddColumn(helper.NewNumericReportColumn("CCI", ccis), 1)
+ report.AddColumn(helper.NewAnnotationReportColumn(annotations), 0, 1)
+
+ report.AddColumn(helper.NewNumericReportColumn("Outcome", outcomes), 2)
+
+ return report
+}
diff --git a/strategy/trend/cci_strategy_test.go b/strategy/trend/cci_strategy_test.go
new file mode 100644
index 0000000..041a3b5
--- /dev/null
+++ b/strategy/trend/cci_strategy_test.go
@@ -0,0 +1,55 @@
+// Copyright (c) 2021-2023 Onur Cinar.
+// The source code is provided under GNU AGPLv3 License.
+// https://github.com/cinar/indicator
+
+package trend_test
+
+import (
+ "os"
+ "testing"
+
+ "github.com/cinar/indicator/asset"
+ "github.com/cinar/indicator/helper"
+ "github.com/cinar/indicator/strategy"
+ "github.com/cinar/indicator/strategy/trend"
+)
+
+func TestCciStrategy(t *testing.T) {
+ snapshots, err := helper.ReadFromCsvFile[asset.Snapshot]("testdata/brk-b.csv", true)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ results, err := helper.ReadFromCsvFile[strategy.Result]("testdata/cci_strategy.csv", true)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ cci := trend.NewCciStrategy()
+ actions, outcomes := strategy.ComputeWithOutcome(cci, snapshots)
+ outcomes = helper.RoundDigits(outcomes, 2)
+
+ err = strategy.CheckResults(results, actions, outcomes)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestCciStrategyReport(t *testing.T) {
+ snapshots, err := helper.ReadFromCsvFile[asset.Snapshot]("testdata/brk-b.csv", true)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ cci := trend.NewCciStrategy()
+
+ report := cci.Report(snapshots)
+
+ fileName := "cci_strategy.html"
+ defer os.Remove(fileName)
+
+ err = report.WriteToFile(fileName)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/strategy/trend/testdata/cci_strategy.csv b/strategy/trend/testdata/cci_strategy.csv
new file mode 100644
index 0000000..a7148b3
--- /dev/null
+++ b/strategy/trend/testdata/cci_strategy.csv
@@ -0,0 +1,252 @@
+Action,Outcome
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+1,0
+0,-0.02
+0,-0.02
+0,-0.04
+0,-0.04
+0,-0.04
+0,-0.04
+-1,-0.06
+0,-0.06
+0,-0.06
+0,-0.06
+0,-0.06
+0,-0.06
+0,-0.06
+0,-0.06
+0,-0.06
+0,-0.06
+0,-0.06
+0,-0.06
+0,-0.06
+0,-0.06
+0,-0.06
+0,-0.06
+1,-0.06
+0,-0.06
+0,-0.06
+0,-0.05
+0,-0.04
+0,-0.04
+0,-0.03
+0,-0.02
+0,-0.03
+0,-0.03
+0,-0.02
+0,-0.02
+0,-0.02
+0,-0.04
+0,-0.02
+0,-0.01
+0,-0.01
+0,-0.02
+0,-0.03
+0,-0.04
+0,-0.03
+0,-0.02
+0,-0.02
+0,-0.03
+0,-0.03
+0,-0.03
+0,-0.03
+0,-0.03
+0,-0.02
+0,-0.01
+0,-0.01
+0,-0.01
+0,-0.03
+0,-0.04
+-1,-0.04
+0,-0.04
+0,-0.04
+0,-0.04
+0,-0.04
+0,-0.04
+0,-0.04
+1,-0.04
+0,-0.03
+0,-0.03
+0,-0.04
+0,-0.04
+0,-0.03
+0,-0.03
+0,-0.02
+0,-0.03
+0,-0.03
+0,-0.03
+0,-0.03
+0,-0.04
+0,-0.04
+0,-0.04
+0,-0.04
+0,-0.03
+0,-0.02
+0,-0.02
+0,-0.02
+0,-0.02
+0,-0.02
+0,-0.02
+0,-0.01
+0,-0.01
+0,-0.01
+0,-0.02
+0,-0.01
+0,-0.01
+0,-0.01
+0,-0
+0,-0.01
+0,0.01
+0,0
+0,0.01
+0,0.01
+0,0.01
+0,0.01
+0,0.01
+0,0.01
+0,0.02
+0,0.01
+0,0.04
+0,0.05
+0,0.03
+0,0.03
+0,0.03
+0,0.03
+0,0.02
+0,0.02
+0,0.02
+0,0.01
+0,0.01
+0,0.01
+0,0.02
+0,0.02
+0,0.02
+0,0.02
+0,0.03
+0,0.04
+0,0.04
+0,0.04
+0,0.04
+0,0.04
+0,0.04
+0,0.04
+0,0.05
+0,0.06
+0,0.06
+0,0.06
+0,0.06
+0,0.07
+0,0.07
+0,0.06
+0,0.05
+0,0.04
+0,0.04
+0,0.03
+0,0.03
+0,0.03
+0,0.01
+-1,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+0,0
+1,0
+0,0.01
+0,0.02
+0,0.01
+0,0.02
+0,0.02
+0,0.02
+0,0.03
+0,0.02
+0,0.02
+0,0.01