From b2cce596bf135a580436c3f96bf03f564db9aede Mon Sep 17 00:00:00 2001 From: wangfeng Date: Wed, 8 Feb 2023 21:55:54 +0800 Subject: [PATCH 1/2] =?UTF-8?q?NDFrame.DTypes=E7=9A=84=E5=85=8B=E9=9A=86?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=9C=A8EWM=E9=87=8C=E9=9D=A2=E5=AD=98?= =?UTF-8?q?=E5=9C=A8=E8=BF=99=E4=B8=AA,=20=E7=9B=AE=E5=89=8D=E4=B8=8D?= =?UTF-8?q?=E5=BD=B1=E5=93=8D=E4=BD=BF=E7=94=A8,=20=E5=90=8E=E7=BB=AD?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- generic_ewm.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/generic_ewm.go b/generic_ewm.go index 640cb8d..3ad3e36 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 -- Gitee From 2110fb901228c9747f325360d52ce9ebd7b1d52f Mon Sep 17 00:00:00 2001 From: wangfeng Date: Wed, 8 Feb 2023 21:57:43 +0800 Subject: [PATCH 2/2] =?UTF-8?q?#I6CYOT=20=E5=AE=9E=E7=8E=B0EMA=E5=87=BD?= =?UTF-8?q?=E6=95=B0.=20=E9=80=9A=E8=BE=BE=E4=BF=A1=E7=9A=84EMA=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E7=9A=84=E5=8F=82=E6=95=B0=E5=BA=8F=E5=88=97=E5=8C=96?= =?UTF-8?q?,=20=E9=AA=8C=E8=AF=81=E6=9C=89=E6=95=88.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- formula/README.md | 2 +- formula/ema.go | 83 +++++++++++++++++++++++++++++++++++++++++++++ formula/ema_test.go | 45 ++++++++++++++++++++++++ formula/sma.go | 6 ++-- formula/sma_test.go | 2 +- stat/array.go | 13 +++++++ stat/array_test.go | 13 +++++++ 7 files changed, 159 insertions(+), 5 deletions(-) create mode 100644 formula/ema.go create mode 100644 formula/ema_test.go create mode 100644 stat/array.go create mode 100644 stat/array_test.go diff --git a/formula/README.md b/formula/README.md index e4e9976..cb5f555 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 0000000..0b844a3 --- /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 0000000..2c06b41 --- /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 485317e..a836711 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 e373bd0..0ddc743 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/stat/array.go b/stat/array.go new file mode 100644 index 0000000..a41e450 --- /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 0000000..be63f30 --- /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()) +} -- Gitee