Skip to content

Commit

Permalink
feature: add cci indicator
Browse files Browse the repository at this point in the history
  • Loading branch information
zenixls2 committed May 9, 2022
1 parent 3af08ab commit 2311fbd
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 0 deletions.
102 changes: 102 additions & 0 deletions pkg/indicator/cci.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package indicator

import (
"github.com/c9s/bbgo/pkg/types"
)

// Refer: Commodity Channel Index
// Refer URL: https://www.investopedia.com/terms/c/commoditychannelindex.asp
//go:generate callbackgen -type CCI
type CCI struct {
types.IntervalWindow
HLC3 types.Float64Slice
TypicalPrice types.Float64Slice
MA types.Float64Slice
Values types.Float64Slice

UpdateCallbacks []func(value float64)
}

func (inc *CCI) Update(high, low, cloze float64) {
if len(inc.TypicalPrice) == 0 {
inc.HLC3.Push((high + low + cloze) / 3.)
inc.TypicalPrice.Push(inc.HLC3.Last())
return
} else if len(inc.TypicalPrice) > MaxNumOfEWMA {
inc.TypicalPrice = inc.TypicalPrice[MaxNumOfEWMATruncateSize-1:]
inc.HLC3 = inc.HLC3[MaxNumOfEWMATruncateSize-1:]
}

hlc3 := (high + low + cloze) / 3.
tp := inc.TypicalPrice.Last() - inc.HLC3.Index(inc.Window) + hlc3
inc.TypicalPrice.Push(tp)
if len(inc.TypicalPrice) < inc.Window {
return
}
ma := 0.
for i := 0; i < inc.Window; i++ {
ma += inc.TypicalPrice.Index(i)
}
ma /= float64(inc.Window)
inc.MA.Push(ma)
if len(inc.MA) < MaxNumOfEWMA {
inc.MA = inc.MA[MaxNumOfEWMATruncateSize-1:]
}
md := 0.
for i := 0; i < inc.Window; i++ {
md += inc.TypicalPrice.Index(i) - inc.MA.Index(i)
}
md /= float64(inc.Window)

cci := (tp - ma) / (0.15 * md)

inc.Values.Push(cci)
if len(inc.Values) > MaxNumOfEWMA {
inc.Values = inc.Values[MaxNumOfEWMATruncateSize-1:]
}
}

func (inc *CCI) Last() float64 {
if len(inc.Values) == 0 {
return 0
}
return inc.Values[len(inc.Values) - 1]
}

func (inc *CCI) Index(i int) float64 {
if i >= len(inc.Values) {
return 0
}
return inc.Values[len(inc.Values)-1-i]
}

func (inc *CCI) Length() int {
return len(inc.Values)
}

var _ types.Series = &CCI{}

func (inc *CCI) calculateAndUpdate(allKLines []types.KLine) {
if inc.HLC3.Length() == 0 {
for _, k := range allKLines {
inc.Update(k.High.Float64(), k.Low.Float64(), k.Close.Float64())
inc.EmitUpdate(inc.Last())
}
} else {
k := allKLines[len(allKLines)-1]
inc.Update(k.High.Float64(), k.Low.Float64(), k.Close.Float64())
inc.EmitUpdate(inc.Last())
}
}

func (inc *CCI) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
if inc.Interval != interval {
return
}

inc.calculateAndUpdate(window)
}

func (inc *CCI) Bind(updater KLineWindowUpdater) {
updater.OnKLineWindowUpdate(inc.handleKLineWindowUpdate)
}
15 changes: 15 additions & 0 deletions pkg/indicator/cci_callbacks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 2311fbd

Please sign in to comment.