package strategy import ( "github.com/shopspring/decimal" "testing" ) func TestBoll_WarmupAndSliding(t *testing.T) { n := 5 k := d(2.0) b := NewBollW(n) // 前 n-1 根:not ready for i, px := range []float64{10, 11, 12, 13} { out := b.Push(d(int64(px)), k) if out.Ready { t.Fatalf("i=%d: should not be ready yet", i) } } // 第 n 根開始:ready out := b.Push(d(14), k) if !out.Ready { t.Fatalf("should be ready at %d-th push", n) } // 中線應為 (10+11+12+13+14)/5 = 12 if out.Mid.StringFixed(6) != d(12).StringFixed(6) { t.Fatalf("mid expect 12, got %s", out.Mid) } // 標準差 > 0;上軌 > 中線 > 下軌 if !out.Std.GreaterThan(decimal.Zero) || !out.Upper.GreaterThan(out.Mid) || !out.Mid.GreaterThan(out.Lower) { t.Fatalf("band ordering violated: U=%s M=%s L=%s Std=%s", out.Upper, out.Mid, out.Lower, out.Std) } // 再推兩根 -> 視窗滑到 [12,13,14,15,16],中線=14 for _, px := range []float64{15, 16} { out = b.Push(d(int64(px)), k) } if out.Mid.StringFixed(6) != d(14).StringFixed(6) { t.Fatalf("sliding mid expect 14, got %s", out.Mid) } if !out.Std.GreaterThan(decimal.Zero) { t.Fatalf("std should remain > 0 after slide, got %s", out.Std) } } func TestBoll_FlatSeries(t *testing.T) { n := 4 k := d(2.0) b := NewBollW(n) // 全部相同價格 -> 標準差=0、三條線重合 for i := 0; i < n; i++ { _ = b.Push(d(10), k) } out := b.Push(d(10), k) // 視窗仍為相同值 if !out.Std.Equal(decimal.Zero) { t.Fatalf("std should be 0 on flat series, got %s", out.Std) } if !(out.Upper.Equal(out.Mid) && out.Mid.Equal(out.Lower) && out.Mid.Equal(d(10))) { t.Fatalf("bands should coincide at 10: U=%s M=%s L=%s", out.Upper, out.Mid, out.Lower) } }