diff --git a/formula/README.md b/formula/README.md index e4e9976f78ea53c8358deb831c9dca11a0efa00b..cb5f555e24dc3aeec9c681c41e81628653813a7d 100644 --- a/formula/README.md +++ b/formula/README.md @@ -20,7 +20,7 @@ formula | 0 | MIN | 计算AB最小值 | MIN(CLOSE,HIGH) | [√] | [√] | | 0 | MA | 计算N周期的移动平均值, 简称均线 | MA(CLOSE,5) | [√] | [√] | | 0 | DMA | S序列的动态移动平均, A作为平滑因子 | DMA(CLOSE,5) | [X] | [X] | -| 0 | EMA | S序列N周期的指数移动平均, α=/(1+com) | EMA(CLOSE,5) | [X] | [X] | +| 0 | EMA | S序列N周期的指数移动平均, α=/(1+com) | EMA(CLOSE,5) | [√] | [√] | | 0 | SMA | 计算N周期的简单移动平均值 | SMA(CLOSE,5, 1) | [√] | [√] | | 0 | WMA | S序列的N周期的加权移动平均值 | WMA(CLOSE,5) | [√] | [√] | | 0 | STD | 计算N周期内的标准差 | STD(CLOSE,20) | [√] | [√] | diff --git a/formula/ema.go b/formula/ema.go new file mode 100644 index 0000000000000000000000000000000000000000..0b844a3e473c73614e587742b322c18f82edaa42 --- /dev/null +++ b/formula/ema.go @@ -0,0 +1,83 @@ +package formula + +import ( + "gitee.com/quant1x/pandas" + "gitee.com/quant1x/pandas/exception" + "gitee.com/quant1x/pandas/stat" +) + +// EMA 指数移动平均,为了精度 S>4*N EMA至少需要120周期 +// alpha=2/(span+1) +// TODO:这个版本是对的, 通达信EMA居然实现了真的序列, 那为啥SMA不是呢?! +func EMA(S pandas.Series, N any) any { + var X []stat.DType + switch v := N.(type) { + case int: + X = stat.Repeat[stat.DType](stat.DType(v), S.Len()) + case pandas.Series: + vs := v.DTypes() + X = stat.Align(vs, stat.DTypeNaN, S.Len()) + default: + panic(exception.New(1, "error window")) + } + k := X[0] + x := S.EWM(pandas.EW{Span: stat.DTypeNaN, Callback: func(idx int) stat.DType { + j := X[idx] + if j == 0 { + j = 1 + } else { + k = j + } + return stat.DType(stat.DType(2) / (j + 1)) + }, Adjust: false}).Mean().Values() + _ = k + return x +} + +// EMA_v2 通达信公式管理器上提示, EMA(S, N) 相当于SMA(S, N + 1, M=2), 骗子, 根本不对 +func EMA_v2(S pandas.Series, N any) any { + M := 2 + var X float32 + switch v := N.(type) { + case int: + X = float32(v) + case pandas.Series: + vs := v.Values() + fs := pandas.SliceToFloat32(vs) + X = fs[len(fs)-1] + default: + panic(exception.New(1, "error window")) + } + x := S.EWM(pandas.EW{Alpha: float64(M) / float64(X+1), Adjust: false}).Mean().Values() + return x +} + +// EMA_v0 仿SMA实现, 错误 +func EMA_v0(S pandas.Series, N any) any { + var X float32 + switch v := N.(type) { + case int: + X = float32(v) + case pandas.Series: + vs := v.Values() + fs := pandas.SliceToFloat32(vs) + X = fs[len(fs)-1] + default: + panic(exception.New(1, "error window")) + } + x := S.EWM(pandas.EW{Span: stat.DType(X), Adjust: false}).Mean().Values() + return x +} + +// EMA_v1 Rolling(N), 每个都取最后一个, 错误 +func EMA_v1(S pandas.Series, N any) any { + x := S.Rolling(N).Apply(func(S pandas.Series, N stat.DType) stat.DType { + r := S.EWM(pandas.EW{Span: N, Adjust: false}).Mean().DTypes() + if len(r) == 0 { + return stat.DTypeNaN + } + return r[len(r)-1] + }).Values() + return x + +} diff --git a/formula/ema_test.go b/formula/ema_test.go new file mode 100644 index 0000000000000000000000000000000000000000..2c06b410ccd0cfccc265a3528ec3a3a24041ff74 --- /dev/null +++ b/formula/ema_test.go @@ -0,0 +1,45 @@ +package formula + +import ( + "fmt" + "gitee.com/quant1x/pandas" + "gitee.com/quant1x/pandas/stat" + "github.com/viterin/vek/vek32" + "testing" +) + +func TestEMA(t *testing.T) { + f0 := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9} + s0 := pandas.NewSeriesWithoutType("f0", f0) + fmt.Println(EMA(s0, 7)) + csv := "~/.quant1x/data/cn/002528.csv" + df := pandas.ReadCSV(csv) + df.SetNames("data", "open", "close", "high", "low", "volume", "amount", "zf", "zdf", "zde", "hsl") + fmt.Println(df) + //df.SetName("收盘", "close") + CLOSE := df.Col("close") + + cs := CLOSE.Values().([]float32) + REF10 := REF(CLOSE, 10).([]float32) + v1 := vek32.Div(cs, REF10) + df01 := pandas.NewSeries(pandas.SERIES_TYPE_FLOAT32, "x", v1) + x0 := make([]stat.DType, CLOSE.Len()) + df01.Apply(func(idx int, v any) { + f := v.(float32) + t := stat.DType(0) + if f >= 1.05 { + t = stat.DType(1) + } + x0[idx] = t + }) + //x := stat.Where(v2, as, bs) + n := BARSLAST(pandas.NewSeries(pandas.SERIES_TYPE_FLOAT32, "", x0)) + fmt.Println(n[len(n)-10:]) + x := EMA(CLOSE, pandas.NewSeries(pandas.SERIES_TYPE_DTYPE, "", n)) + + //x := EMA(CLOSE, 7) + sx := pandas.NewSeries(pandas.SERIES_TYPE_DTYPE, "x", x) + df = pandas.NewDataFrame(CLOSE, sx) + fmt.Println(df) + +} diff --git a/formula/sma.go b/formula/sma.go index 485317ebbc4695eb5c288dbc6dbc99b9dc98d346..a836711840b0b93c52aac854656785fb98993876 100644 --- a/formula/sma.go +++ b/formula/sma.go @@ -56,7 +56,7 @@ func SMA_v5(S pandas.Series, N any, M int) any { return x } -// 听说SMA(S, N, 1) 其实就是MA(S,N), 试验后发现是骗子 +// SMA_v4 听说SMA(S, N, 1) 其实就是MA(S,N), 试验后发现是骗子 func SMA_v4(S pandas.Series, N any, M int) any { var X []float32 switch v := N.(type) { @@ -72,7 +72,7 @@ func SMA_v4(S pandas.Series, N any, M int) any { return S.Rolling(X).Mean().Values() } -// 使用滑动窗口 +// SMA_v3 使用滑动窗口 func SMA_v3(S pandas.Series, N any, M int) any { if M == 0 { M = 1 @@ -87,7 +87,7 @@ func SMA_v3(S pandas.Series, N any, M int) any { return x } -// 最原始的python写法 +// SMA_v1 最原始的python写法 func SMA_v1(S pandas.Series, N int, M int) any { if M == 0 { M = 1 diff --git a/formula/sma_test.go b/formula/sma_test.go index e373bd05c909bac1e1c025e0a1f529765b913093..0ddc743340d2d57619456c1133ab3dd50e356894 100644 --- a/formula/sma_test.go +++ b/formula/sma_test.go @@ -37,7 +37,7 @@ func TestSMA(t *testing.T) { n := BARSLAST(pandas.NewSeries(pandas.SERIES_TYPE_FLOAT32, "", x)) fmt.Println(n[len(n)-10:]) //r1 := SMA(CLOSE, pandas.NewSeries(pandas.SERIES_TYPE_FLOAT32, "", n), 1) - r1 := SMA(CLOSE, 6, 1) + r1 := SMA(CLOSE, 7, 1) s2 := pandas.NewSeries(pandas.SERIES_TYPE_FLOAT32, "sma", r1) df2 := pandas.NewDataFrame(s2) fmt.Println(df2) diff --git a/generic_ewm.go b/generic_ewm.go index 640cb8d2d6a9b9d34d06c00be26054f8888de650..3ad3e36b3b072ef5662239d2f071967677b40227 100644 --- a/generic_ewm.go +++ b/generic_ewm.go @@ -149,8 +149,9 @@ func (w ExponentialMovingWindow) notadjustedMean(data Series, alpha stat.DType, var ( count int values = data.Values().([]stat.DType) - beta = 1 - alpha - last = values[0] + //values = data.DTypes() // Dtypes有复制功能 + beta = 1 - alpha + last = values[0] ) if Float64IsNaN(last) { last = 0 diff --git a/stat/array.go b/stat/array.go new file mode 100644 index 0000000000000000000000000000000000000000..a41e45059da263eb3ac1f2b4da2dd34abf2e7de8 --- /dev/null +++ b/stat/array.go @@ -0,0 +1,13 @@ +package stat + +type NDArray []DType + +type Frame interface { + Len() int +} + +type Array[T Number] []T + +func (a Array[T]) Len() int { + return len(a) +} diff --git a/stat/array_test.go b/stat/array_test.go new file mode 100644 index 0000000000000000000000000000000000000000..be63f3075bfe08de781e7854b47461f0890ea9dc --- /dev/null +++ b/stat/array_test.go @@ -0,0 +1,13 @@ +package stat + +import ( + "fmt" + "testing" +) + +func TestArray_Len(t *testing.T) { + f1 := []float64{1, 2, 3, 4, 5} + a1 := Array[float64](f1) + fmt.Println(a1) + fmt.Println(a1.Len()) +}