103 lines
2.7 KiB
Go
103 lines
2.7 KiB
Go
package strategy
|
||
|
||
import (
|
||
"github.com/shopspring/decimal"
|
||
"testing"
|
||
)
|
||
|
||
// --- EMA 的表格式驅動測試 (新增) ---
|
||
|
||
func TestEMA(t *testing.T) {
|
||
d10 := decimal.NewFromInt(10)
|
||
d11 := decimal.NewFromInt(11)
|
||
d12 := decimal.NewFromInt(12)
|
||
d13 := decimal.NewFromInt(13)
|
||
d20 := decimal.NewFromInt(20)
|
||
|
||
type pushCheck struct {
|
||
wantEMA decimal.Decimal
|
||
wantOK bool
|
||
}
|
||
|
||
testCases := []struct {
|
||
name string
|
||
n uint
|
||
inputs []decimal.Decimal
|
||
pushChecks []pushCheck
|
||
wantFinalEMA decimal.Decimal
|
||
wantFinalOK bool
|
||
}{
|
||
{
|
||
name: "EMA-3 標準計算",
|
||
n: 3, // α = 2 / (3 + 1) = 0.5
|
||
inputs: []decimal.Decimal{d10, d11, d12},
|
||
pushChecks: []pushCheck{
|
||
{d10, true}, // 第一次, EMA = 10
|
||
{decimal.NewFromFloat(10.5), true}, // 第二次, 0.5*11 + (1-0.5)*10 = 5.5 + 5 = 10.5
|
||
{decimal.NewFromFloat(11.25), true}, // 第三次, 0.5*12 + (1-0.5)*10.5 = 6 + 5.25 = 11.25
|
||
},
|
||
wantFinalEMA: decimal.NewFromFloat(11.25),
|
||
wantFinalOK: true,
|
||
},
|
||
{
|
||
name: "EMA-1 邊界情況",
|
||
n: 1, // α = 2 / (1 + 1) = 1
|
||
inputs: []decimal.Decimal{d10, d13, d11},
|
||
pushChecks: []pushCheck{
|
||
{d10, true}, // 第一次, EMA = 10
|
||
{d13, true}, // 第二次, 1*13 + 0*10 = 13
|
||
{d11, true}, // 第三次, 1*11 + 0*13 = 11
|
||
},
|
||
wantFinalEMA: d11,
|
||
wantFinalOK: true,
|
||
},
|
||
{
|
||
name: "EMA-0 無效情況",
|
||
n: 0,
|
||
inputs: []decimal.Decimal{d10, d20},
|
||
pushChecks: []pushCheck{
|
||
{decimal.Zero, false},
|
||
{decimal.Zero, false},
|
||
},
|
||
wantFinalEMA: decimal.Zero,
|
||
wantFinalOK: false,
|
||
},
|
||
{
|
||
name: "在空實例上呼叫 GetEMA",
|
||
n: 5,
|
||
inputs: []decimal.Decimal{},
|
||
pushChecks: []pushCheck{},
|
||
wantFinalEMA: decimal.Zero,
|
||
wantFinalOK: false,
|
||
},
|
||
}
|
||
|
||
for _, tc := range testCases {
|
||
t.Run(tc.name, func(t *testing.T) {
|
||
ema := NewEMA(tc.n)
|
||
|
||
for i, input := range tc.inputs {
|
||
gotEMA, gotOK := ema.Push(input)
|
||
if i < len(tc.pushChecks) {
|
||
check := tc.pushChecks[i]
|
||
if gotOK != check.wantOK {
|
||
t.Errorf("Push #%d 的 OK 狀態錯誤: got %v, want %v", i+1, gotOK, check.wantOK)
|
||
}
|
||
// 使用 String() 進行比較,避免浮點數精度問題
|
||
if gotEMA.String() != check.wantEMA.String() {
|
||
t.Errorf("Push #%d 的 EMA 值錯誤: got %s, want %s", i+1, gotEMA.String(), check.wantEMA.String())
|
||
}
|
||
}
|
||
}
|
||
|
||
finalEMA, finalOK := ema.GetEMA()
|
||
if finalOK != tc.wantFinalOK {
|
||
t.Errorf("最終 GetEMA 的 OK 狀態錯誤: got %v, want %v", finalOK, tc.wantFinalOK)
|
||
}
|
||
if finalEMA.String() != tc.wantFinalEMA.String() {
|
||
t.Errorf("最終 GetEMA 的 EMA 值錯誤: got %s, want %s", finalEMA.String(), tc.wantFinalEMA.String())
|
||
}
|
||
})
|
||
}
|
||
}
|