Skip to content

Commit

Permalink
Community Channel Index (CCI) strategy added.
Browse files Browse the repository at this point in the history
  • Loading branch information
cinar committed Dec 30, 2023
1 parent 6ce0871 commit 8813be8
Show file tree
Hide file tree
Showing 5 changed files with 464 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
55 changes: 55 additions & 0 deletions strategy/trend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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>)
Expand Down Expand Up @@ -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.

<a name="CciStrategy"></a>
## type [CciStrategy](<https://github.com/cinar/indicator/blob/v2/strategy/trend/cci_strategy.go#L17-L22>)

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]
}
```

<a name="NewCciStrategy"></a>
### func [NewCciStrategy](<https://github.com/cinar/indicator/blob/v2/strategy/trend/cci_strategy.go#L25>)

```go
func NewCciStrategy() *CciStrategy
```

NewCciStrategy function initializes a new CCI strategy instance.

<a name="CciStrategy.Compute"></a>
### func \(\*CciStrategy\) [Compute](<https://github.com/cinar/indicator/blob/v2/strategy/trend/cci_strategy.go#L37>)

```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.

<a name="CciStrategy.Name"></a>
### func \(\*CciStrategy\) [Name](<https://github.com/cinar/indicator/blob/v2/strategy/trend/cci_strategy.go#L32>)

```go
func (*CciStrategy) Name() string
```

Name returns the name of the strategy.

<a name="CciStrategy.Report"></a>
### func \(\*CciStrategy\) [Report](<https://github.com/cinar/indicator/blob/v2/strategy/trend/cci_strategy.go#L66>)

```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.

<a name="DemaStrategy"></a>
## type [DemaStrategy](<https://github.com/cinar/indicator/blob/v2/strategy/trend/dema_strategy.go#L27-L37>)

Expand Down
101 changes: 101 additions & 0 deletions strategy/trend/cci_strategy.go
Original file line number Diff line number Diff line change
@@ -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
}
55 changes: 55 additions & 0 deletions strategy/trend/cci_strategy_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
Loading

0 comments on commit 8813be8

Please sign in to comment.