Skip to content

Commit

Permalink
Merge pull request #30 from sdcoffey/sc/adx-ketlner-crsi
Browse files Browse the repository at this point in the history
ADx, Keltner Chan, CRSI
  • Loading branch information
sdcoffey authored Mar 6, 2021
2 parents e87ec2e + d2b159a commit a2f4ef8
Show file tree
Hide file tree
Showing 27 changed files with 654 additions and 350 deletions.
4 changes: 4 additions & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ignore:
- testutils.go
- example/**/*
- scripts/**/*
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
files := $(shell find . -name "*.go" | grep -v vendor)

bootstrap:
go get golang.org/x/lint/golint
go get honnef.co/go/tools/...
go install -v golang.org/x/lint/golint@latest
go install -v golang.org/x/tools/...@latest
go install -v honnef.co/go/tools/cmd/staticcheck@latest

clean:
goimports -w $(files)
Expand Down
46 changes: 46 additions & 0 deletions cached_indicator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package techan

import "github.com/sdcoffey/big"

type resultCache []*big.Decimal

type cachedIndicator interface {
Indicator
cache() resultCache
setCache(cache resultCache)
windowSize() int
}

func cacheResult(indicator cachedIndicator, index int, val big.Decimal) {
if index < len(indicator.cache()) {
indicator.cache()[index] = &val
} else if index == len(indicator.cache()) {
indicator.setCache(append(indicator.cache(), &val))
} else {
expandResultCache(indicator, index+1)
cacheResult(indicator, index, val)
}
}

func expandResultCache(indicator cachedIndicator, newSize int) {
sizeDiff := newSize - len(indicator.cache())

expansion := make([]*big.Decimal, sizeDiff)
indicator.setCache(append(indicator.cache(), expansion...))
}

func returnIfCached(indicator cachedIndicator, index int, firstValueFallback func(int) big.Decimal) *big.Decimal {
if index >= len(indicator.cache()) {
expandResultCache(indicator, index+1)
} else if index < indicator.windowSize()-1 {
return &big.ZERO
} else if val := indicator.cache()[index]; val != nil {
return val
} else if index == indicator.windowSize()-1 {
value := firstValueFallback(index)
cacheResult(indicator, index, value)
return &value
}

return nil
}
8 changes: 2 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ module github.com/sdcoffey/techan
go 1.12

require (
github.com/davecgh/go-spew v1.1.0
github.com/pmezard/go-difflib v1.0.0
github.com/sdcoffey/big v0.4.1
github.com/stretchr/testify v1.2.1
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
honnef.co/go/tools v0.0.1-2020.1.6 // indirect
github.com/sdcoffey/big v0.7.0
github.com/stretchr/testify v1.7.0
)
77 changes: 12 additions & 65 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,72 +1,19 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/sdcoffey/big v0.0.0-20180413224939-438f3d83db4c h1:avDKoFuBXMQAcu0sxdpbS88WAiPt2e9YtSuEWfOPj7E=
github.com/sdcoffey/big v0.0.0-20180413224939-438f3d83db4c/go.mod h1:WzOYJJhNOp7m1u1MrNQaYSHmgqHGkZThC+VgDqdFl0I=
github.com/sdcoffey/big v0.4.1 h1:DyK4tHRbbAfdIZV/VbxrEz/ZpcVv5GWNNw+G6AOhfpM=
github.com/sdcoffey/big v0.4.1/go.mod h1:spXh3ZRHdlXkg4SzauLC8ahWmHpxWL5/6drgufL73es=
github.com/sdcoffey/big v0.6.0 h1:0C+nB/91mHQGAxlgvDy/hFO3MMv3dTnCuNA3qfhEYYQ=
github.com/sdcoffey/big v0.6.0/go.mod h1:spXh3ZRHdlXkg4SzauLC8ahWmHpxWL5/6drgufL73es=
github.com/sdcoffey/big v0.7.0 h1:OnE7fcHq/C59WxWrMegftFa1nftCjsZLVf7PLXsxj2Y=
github.com/sdcoffey/big v0.7.0/go.mod h1:2T05Q7Mt6F1kHHb+PFa0odPFwU67YnSAFYgiYy7krPU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422 h1:QzoH/1pFpZguR8NrRHLcO6jKqfv2zpuSqZLgdm7ZmjI=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e h1:JgcxKXxCjrA2tyDP/aNU9K0Ck5Czfk6C7e2tMw7+bSI=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac h1:MQEvx39qSf8vyrx3XRaOe+j1UDIzKwkYOVObRgGPVqI=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7 h1:EBZoQjiKKPaLbPrbpssUfuHtwM6KV/vb4U85g/cigFY=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef h1:RHORRhs540cYZYrzgU2CPUyykkwZM78hGdzocOo9P8A=
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
honnef.co/go/tools v0.0.0-20190412205916-e87e8279b4cd h1:hnvxEW8n8IJasi4s1HJpanZ1ebTAdsjxzbZPO8Viw+s=
honnef.co/go/tools v0.0.0-20190412205916-e87e8279b4cd/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.5 h1:nI5egYTGJakVyOryqLs1cQO5dO0ksin5XXs2pspk75k=
honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.6 h1:W18jzjh8mfPez+AwGLxmOImucz/IFjpNlrKVnaj2YVc=
honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
32 changes: 32 additions & 0 deletions indicator_average_true_range.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package techan

import "github.com/sdcoffey/big"

type averageTrueRangeIndicator struct {
series *TimeSeries
window int
}

// NewAverageTrueRangeIndicator returns a base indicator that calculates the average true range of the
// underlying over a window
// https://www.investopedia.com/terms/a/atr.asp
func NewAverageTrueRangeIndicator(series *TimeSeries, window int) Indicator {
return averageTrueRangeIndicator{
series: series,
window: window,
}
}

func (atr averageTrueRangeIndicator) Calculate(index int) big.Decimal {
if index < atr.window {
return big.ZERO
}

sum := big.ZERO

for i := index; i > index-atr.window; i-- {
sum = sum.Add(NewTrueRangeIndicator(atr.series).Calculate(i))
}

return sum.Div(big.NewFromInt(atr.window))
}
24 changes: 24 additions & 0 deletions indicator_average_true_range_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package techan

import "testing"

func TestAverageTrueRangeIndicator(t *testing.T) {
atrIndicator := NewAverageTrueRangeIndicator(mockedTimeSeries, 3)

expectedValues := []float64{
0,
0,
0,
2,
2,
2,
2,
2,
2,
2,
2.3467,
2.3467,
}

indicatorEquals(t, expectedValues, atrIndicator)
}
45 changes: 45 additions & 0 deletions indicator_exponential_moving_average.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package techan

import "github.com/sdcoffey/big"

type emaIndicator struct {
indicator Indicator
window int
alpha big.Decimal
resultCache resultCache
}

// NewEMAIndicator returns a derivative indicator which returns the average of the current and preceding values in
// the given windowSize, with values closer to current index given more weight. A more in-depth explanation can be found here:
// http://www.investopedia.com/terms/e/ema.asp
func NewEMAIndicator(indicator Indicator, window int) Indicator {
return &emaIndicator{
indicator: indicator,
window: window,
alpha: big.ONE.Frac(2).Div(big.NewFromInt(window + 1)),
resultCache: make([]*big.Decimal, 1000),
}
}

func (ema *emaIndicator) Calculate(index int) big.Decimal {
if cachedValue := returnIfCached(ema, index, func(i int) big.Decimal {
return NewSimpleMovingAverage(ema.indicator, ema.window).Calculate(i)
}); cachedValue != nil {
return *cachedValue
}

todayVal := ema.indicator.Calculate(index).Mul(ema.alpha)
result := todayVal.Add(ema.Calculate(index - 1).Mul(ema.alpha))

cacheResult(ema, index, result)

return result
}

func (ema emaIndicator) cache() resultCache { return ema.resultCache }

func (ema *emaIndicator) setCache(newCache resultCache) {
ema.resultCache = newCache
}

func (ema emaIndicator) windowSize() int { return ema.window }
62 changes: 62 additions & 0 deletions indicator_exponential_moving_average_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package techan

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestExponentialMovingAverage(t *testing.T) {
t.Run("Default Case", func(t *testing.T) {
expectedValues := []float64{
0,
0,
64.09,
63.91,
63.73,
63.46,
63.685,
63.7675,
63.3588,
63.3644,
62.3472,
61.9286,
}

closePriceIndicator := NewClosePriceIndicator(mockedTimeSeries)
indicatorEquals(t, expectedValues, NewEMAIndicator(closePriceIndicator, 3))
})

t.Run("Expands Result Cache", func(t *testing.T) {
closeIndicator := NewClosePriceIndicator(randomTimeSeries(1001))
ema := NewEMAIndicator(closeIndicator, 20)

ema.Calculate(1000)

emaStruct, ok := ema.(cachedIndicator)
assert.True(t, ok)
assert.EqualValues(t, 1001, len(emaStruct.cache()))
})
}

func BenchmarkExponetialMovingAverage(b *testing.B) {
size := 10000
ts := randomTimeSeries(size)

b.ResetTimer()
for i := 0; i < b.N; i++ {
ema := NewEMAIndicator(NewClosePriceIndicator(ts), 10)
ema.Calculate(size - 1)
}
}

func BenchmarkExponentialMovingAverage_Cached(b *testing.B) {
size := 10000
ts := randomTimeSeries(size)
ema := NewEMAIndicator(NewClosePriceIndicator(ts), 10)

b.ResetTimer()
for i := 0; i < b.N; i++ {
ema.Calculate(size - 1)
}
}
40 changes: 40 additions & 0 deletions indicator_keltner_channel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package techan

import (
"github.com/sdcoffey/big"
)

type keltnerChannelIndicator struct {
ema Indicator
atr Indicator
mul big.Decimal
window int
}

func NewKeltnerChannelUpperIndicator(series *TimeSeries, window int) Indicator {
return keltnerChannelIndicator{
atr: NewAverageTrueRangeIndicator(series, window),
ema: NewEMAIndicator(NewClosePriceIndicator(series), window),
mul: big.ONE,
window: window,
}
}

func NewKeltnerChannelLowerIndicator(series *TimeSeries, window int) Indicator {
return keltnerChannelIndicator{
atr: NewAverageTrueRangeIndicator(series, window),
ema: NewEMAIndicator(NewClosePriceIndicator(series), window),
mul: big.ONE.Neg(),
window: window,
}
}

func (kci keltnerChannelIndicator) Calculate(index int) big.Decimal {
if index <= kci.window-1 {
return big.ZERO
}

coefficient := big.NewFromInt(2).Mul(kci.mul)

return kci.ema.Calculate(index).Add(kci.atr.Calculate(index).Mul(coefficient))
}
Loading

0 comments on commit a2f4ef8

Please sign in to comment.