Skip to content

Commit

Permalink
Bollinger Bands standard deviation calculation is different from othe…
Browse files Browse the repository at this point in the history
…r implementations (#103)

* Bollinger Bands standard deviation calculation is different from other implementations
Fixes #102

* Bollinger bands test case.
  • Loading branch information
cinar committed Jun 24, 2022
1 parent f4fab52 commit 6b80892
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 13 deletions.
20 changes: 8 additions & 12 deletions volatility_indicators.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,20 +117,16 @@ func ChandelierExit(high, low, closing []float64) ([]float64, []float64) {
func Std(period int, values []float64) []float64 {
result := make([]float64, len(values))
sma := Sma(period, values)
sum := float64(0)

for i, value := range values {
d1 := math.Pow(value-sma[i], 2)
count := i + 1
sum += d1

if i >= period {
first := i - period
sum -= math.Pow(values[first]-sma[first], 2)
count = period
for i := range values {
result[i] = 0.0
if i >= period-1 {
sum := float64(0)
for k := i - (period - 1); k <= i; k++ {
sum += (values[k] - sma[i]) * (values[k] - sma[i])
}
result[i] = math.Sqrt(sum / float64(period))
}

result[i] = math.Sqrt(sum / float64(count))
}

return result
Expand Down
37 changes: 36 additions & 1 deletion volatility_indicators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,44 @@ import (
"testing"
)

func TestBollingerBands(t *testing.T) {
closing := []float64{
2, 4, 6, 8, 12, 14, 16, 18, 20,
2, 4, 6, 8, 12, 14, 16, 18, 20,
2, 4, 6, 8, 12, 14, 16, 18, 20,
2, 4, 6, 8, 12, 14, 16, 18, 20,
}

expectedMiddleBand := []float64{
2, 3, 4, 5, 6.4, 7.67, 8.86, 10, 11.11,
10.2, 9.64, 9.33, 9.23, 9.43, 9.73, 10.13, 10.59, 11.11,
10.63, 10.3, 10.5, 10.7, 11, 11.3, 11.5, 11.7, 11.9,
11.1, 10.3, 10.5, 10.7, 11, 11.3, 11.5, 11.7, 11.9,
}

expectedUpperBand := []float64{
2, 3, 4, 5, 6.4, 7.67, 8.86, 10, 11.11, 10.2,
9.64, 9.33, 9.23, 9.43, 9.73, 10.13, 10.59, 11.11,
10.63, 22.78, 22.56, 22.45, 22.56, 22.84, 23.22, 23.72, 24.32,
23.9, 22.78, 22.56, 22.45, 22.56, 22.84, 23.22, 23.72, 24.32,
}

expectedLowerBand := []float64{
2, 3, 4, 5, 6.4, 7.67, 8.86, 10, 11.11,
10.2, 9.64, 9.33, 9.23, 9.43, 9.73, 10.13, 10.59, 11.11,
10.63, -2.18, -1.56, -1.05, -0.56, -0.24, -0.22, -0.32, -0.52,
-1.7, -2.18, -1.56, -1.05, -0.56, -0.24, -0.22, -0.32, -0.52,
}

actualMiddleBand, actualUpperBand, actualLowerBand := BollingerBands(closing)
testEquals(t, roundDigitsAll(actualMiddleBand, 2), expectedMiddleBand)
testEquals(t, roundDigitsAll(actualUpperBand, 2), expectedUpperBand)
testEquals(t, roundDigitsAll(actualLowerBand, 2), expectedLowerBand)
}

func TestStd(t *testing.T) {
values := []float64{2, 4, 6, 8, 12, 14, 16, 18, 20}
expected := []float64{0, 0.707, 1, 1, 1.581, 1.581, 1, 1, 1}
expected := []float64{0, 1, 1, 1, 2, 1, 1, 1, 1}
period := 2

actual := Std(period, values)
Expand Down

0 comments on commit 6b80892

Please sign in to comment.