diff --git a/formula/README.md b/formula/README.md index d3ba96b204a3d3de69de26316aa20c7b9404b536..b1e72bbb3b3a7ecdffea5f2b33b5c67da1ca1604 100644 --- a/formula/README.md +++ b/formula/README.md @@ -27,7 +27,7 @@ formula | 0 | STD | 计算N周期内的标准差 | STD(CLOSE,20) | [√] | [√] | | 0 | SUM | 求总和, 如果N=0则从第一个有效值开始 | SUM(CLOSE,5) | [√] | [√] | | 0 | CONST | 返回序列S最后的值组成常量序列 | CONST(CLOSE) | [√] | [ ] | -| 0 | AVEDEV | 平均绝对差,序列与其平均值的绝对差的平均值 | AVEDEV(CLOSE,5) | [X] | [X] | +| 0 | AVEDEV | 平均绝对差,序列与其平均值的绝对差的平均值 | AVEDEV(CLOSE,5) | [√] | [√] | | 0 | SLOPE | S序列N周期回线性回归斜率 | SLOPE(CLOSE,5) | [√] | [√] | | 0 | FORCAST | S序列N周期回线性回归后的预测值 | FORCAST(CLOSE,5) | [X] | [X] | | 0 | LAST | 从前A日到前B日一直满足S条件,要求A>B & A>0 & B>=0 | LAST(CLOSE>REF(CLOSE,1),LOW,HIGH) | [√] | [√] | diff --git a/formula/avedev.go b/formula/avedev.go new file mode 100644 index 0000000000000000000000000000000000000000..f0f1bf0351523f9c4bb6616bf703445f028f171e --- /dev/null +++ b/formula/avedev.go @@ -0,0 +1,19 @@ +package formula + +import ( + "gitee.com/quant1x/pandas" + "gitee.com/quant1x/pandas/stat" +) + +// AVEDEV 平均绝对偏差, (序列与其平均值的绝对差的平均值) +// +// AVEDEV(S,N) 返回平均绝对偏差 +func AVEDEV(S pandas.Series, N any) any { + return S.Rolling(N).Apply(func(X pandas.Series, W stat.DType) stat.DType { + x := X.DTypes() + x1 := X.Mean() + r := stat.Sub(x, x1) + r = stat.Abs(r) + return stat.Mean(r) + }).Values() +} diff --git a/formula/avedev_test.go b/formula/avedev_test.go new file mode 100644 index 0000000000000000000000000000000000000000..4959cadd7f171e85c7e2cd9ee462c45f9bf3cae2 --- /dev/null +++ b/formula/avedev_test.go @@ -0,0 +1,30 @@ +package formula + +import ( + "fmt" + "gitee.com/quant1x/pandas" + "testing" +) + +func TestAVEDEV(t *testing.T) { + x := []float64{0.0, 0.1, 0.2, 0.3, 0.5, 0.8, 1.0} + y := []float64{1.0, 0.41, 0.50, 0.61, 0.91, 2.02, 2.46} + X := pandas.NewSeriesWithoutType("x", x) + Y := pandas.NewSeriesWithoutType("y", y) + fmt.Println(AVEDEV(Y, 5)) + + 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) + fmt.Println(df.Names()) + df.SetName("收盘", "close") + CLOSE := df.Col("close") + + c1 := AVEDEV(CLOSE, 5) + C := pandas.NewSeriesWithoutType("c1", c1) + df = pandas.NewDataFrame(C) + fmt.Println(df) + + _ = X +} diff --git a/stat/mean.go b/stat/mean.go new file mode 100644 index 0000000000000000000000000000000000000000..ca01badebe68bbd3a6e7fcb94a12d8a90c7e6cf6 --- /dev/null +++ b/stat/mean.go @@ -0,0 +1,25 @@ +package stat + +import ( + "github.com/viterin/vek" + "github.com/viterin/vek/vek32" +) + +// Mean 求均值 +func Mean[T StatType](x []T) T { + var d any + var s any = x + switch vs := s.(type) { + case []float32: + d = vek32.Mean(vs) + case []float64: + d = vek.Mean(vs) + default: + d = __mean(x) + } + return d.(T) +} + +func __mean[T StatType](x []T) T { + return __sum(x) / T(len(x)) +} diff --git a/stat/mean_test.go b/stat/mean_test.go new file mode 100644 index 0000000000000000000000000000000000000000..ded618310bb590a631e748a37a4f063accd24a12 --- /dev/null +++ b/stat/mean_test.go @@ -0,0 +1,17 @@ +package stat + +import ( + "fmt" + "testing" +) + +func TestMean(t *testing.T) { + d1 := []float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + d2 := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + d3 := []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + d4 := []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + fmt.Println(Mean(d1)) + fmt.Println(Mean(d2)) + fmt.Println(Mean(d3)) + fmt.Println(Mean(d4)) +} diff --git a/stat/params.go b/stat/params.go index 826450bc1b6e194a61d6af8ae835cac9358d43e2..c815844748dcd93f6f34d955f9b6c77689041d18 100644 --- a/stat/params.go +++ b/stat/params.go @@ -11,3 +11,17 @@ func detectParam[T StatType](v any) (T, []T, error) { } return base, slice, nil } + +// AnyToSlice any转切片 +func AnyToSlice[T StatType](A any, n int) []T { + switch v := A.(type) { + case /*nil, */ int8, uint8, int16, uint16, int32, uint32, int64, uint64, int, uint, float32, float64 /*, bool, string*/ : + //x := S.EWM(pandas.EW{Alpha: 1 / stat.Any2DType(N), Adjust: false}).Mean().DTypes() + //return x + return Repeat[T](v.(T), n) + case []T: + return Align(v, T(0), n) + default: + panic(ErrUnsupportedType) + } +} diff --git a/stat/params_test.go b/stat/params_test.go new file mode 100644 index 0000000000000000000000000000000000000000..9ec9bd948c9d503685a0ec525a449cd12cc5cf78 --- /dev/null +++ b/stat/params_test.go @@ -0,0 +1,13 @@ +package stat + +import ( + "fmt" + "testing" +) + +func TestAnyToSlice(t *testing.T) { + d1 := []float64{1, 2, 3, 4} + fmt.Println(AnyToSlice[float64](float64(1), 5)) + fmt.Println(AnyToSlice[float64](d1, 3)) + fmt.Println(AnyToSlice[int32](d1, 5)) +} diff --git a/stat/sub.go b/stat/sub.go new file mode 100644 index 0000000000000000000000000000000000000000..75a7cbaf597838c77defcf78c28e7b801e32f513 --- /dev/null +++ b/stat/sub.go @@ -0,0 +1,34 @@ +package stat + +import ( + "github.com/viterin/vek" + "github.com/viterin/vek/vek32" + "golang.org/x/exp/slices" +) + +// Sub 减法 +func Sub[T StatType](x []T, y any) []T { + var d any + xLen := len(x) + var s any = x + switch vs := s.(type) { + case []float32: + f32s := AnyToSlice[float32](y, xLen) + d = vek32.Sub(vs, f32s) + case []float64: + f64s := AnyToSlice[float64](y, xLen) + d = vek.Sub(vs, f64s) + default: + ts := AnyToSlice[T](y, xLen) + d = __sub(x, ts) + } + return d.([]T) +} + +func __sub[T StatType](x, y []T) []T { + x = slices.Clone(x) + for i := 0; i < len(x); i++ { + x[i] -= y[i] + } + return x +} diff --git a/stat/sub_test.go b/stat/sub_test.go new file mode 100644 index 0000000000000000000000000000000000000000..6c20172c0808af4eddb1fc133fd2a36f319687c8 --- /dev/null +++ b/stat/sub_test.go @@ -0,0 +1,18 @@ +package stat + +import ( + "fmt" + "testing" +) + +func TestSub(t *testing.T) { + f1 := []float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + f2 := []float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + d2 := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + d3 := []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + d4 := []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + fmt.Println(Sub(f1, f2)) + fmt.Println(Sub(d2, float64(1))) + fmt.Println(Sub(d3, int32(2))) + fmt.Println(Sub(d4, int64(3))) +} diff --git a/stat/sum.go b/stat/sum.go index 851ddfb26e5ee5a8e20778fbaf26b2ade2f12148..03818320d0365e086baccfd8bbf5cf76d69430e1 100644 --- a/stat/sum.go +++ b/stat/sum.go @@ -19,13 +19,16 @@ func Sum[T StatType](f []T) T { case []float64: d = vek.Sum(fs) default: - // 剩下的就是int32和int64, 循环吧 - m := T(0) - for _, v := range f { - m += v - } - d = m + d = __sum(fs.([]T)) } return d.(T) } + +func __sum[T StatType](x []T) T { + sum := T(0) + for i := 0; i < len(x); i++ { + sum += x[i] + } + return sum +}