blockchain/internal/lib/strategy/ema_sma_talib_test.go

89 lines
2.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package strategy
import (
"github.com/markcheno/go-talib"
"github.com/shopspring/decimal"
"math"
"testing"
)
func dv(v float64) decimal.Decimal { return decimal.NewFromFloat(v) }
func genPrices(n int) []float64 {
out := make([]float64, n)
base := 10.0
for i := 0; i < n; i++ {
out[i] = base + float64(i)*0.5 + math.Sin(float64(i)/3.0)*0.7
}
return out
}
func almostEqualDecFloat(dec decimal.Decimal, f float64, tol float64) bool {
df, _ := dec.Float64()
return math.Abs(df-f) <= tol
}
// 注意:使用 NewEMAForTalib(period)First-Price seed來比對 TA-Lib
func TestEMA_MatchesGoTalib(t *testing.T) {
prices := genPrices(300)
tol := 1e-7 // decimal<->float64 轉換微誤差
periods := []uint{3, 5, 12, 26}
for _, p := range periods {
t.Run("EMA_p="+decimal.NewFromInt(int64(p)).String(), func(t *testing.T) {
ema := NewEMA(p) // 重點:用 TA-Lib 兼容 seed
our := make([]decimal.Decimal, len(prices))
ready := make([]bool, len(prices))
for i, px := range prices {
out := ema.Update(dv(px))
our[i] = out.Value
ready[i] = out.Ready
}
ref := talib.Ema(prices, int(p))
start := p // talib 第一個有效值在 index = period-1
for i := start; i < uint(len(prices)); i++ {
if !ready[i] {
t.Fatalf("i=%d: our not ready but talib has value", i)
}
if !almostEqualDecFloat(our[i], ref[i], tol) {
t.Fatalf("i=%d: EMA mismatch: our=%s ref=%f", i, our[i], ref[i])
}
}
})
}
}
func TestSMA_MatchesGoTalib(t *testing.T) {
prices := genPrices(300)
tol := 1e-9
windows := []uint{3, 5, 20, 50}
for _, w := range windows {
t.Run("SMA_w="+decimal.NewFromInt(int64(w)).String(), func(t *testing.T) {
sma := NewSMA(w)
our := make([]decimal.Decimal, len(prices))
ready := make([]bool, len(prices))
for i, px := range prices {
out := sma.Update(dv(px))
our[i] = out.Value
ready[i] = out.Ready
}
ref := talib.Sma(prices, int(w))
start := w
for i := start; i < uint(len(prices)); i++ {
if !ready[i] {
t.Fatalf("i=%d: our not ready but talib has value", i)
}
if !almostEqualDecFloat(our[i], ref[i], tol) {
t.Fatalf("i=%d: SMA mismatch: our=%s ref=%f", i, our[i], ref[i])
}
}
})
}
}