diff --git a/dataframe_csv_test.go b/dataframe_csv_test.go index 9315d84e7096fb8fca2cf5d15cb03f89f9c82752..b6faa2f1228f1c336a6ea871e1e0d7b4bf43a18b 100644 --- a/dataframe_csv_test.go +++ b/dataframe_csv_test.go @@ -33,7 +33,7 @@ Spain,2012-02-01,66,555.42,00241,1.23 //fmt.Println(s1) // //closes := df.Col("d") - //ma5 := closes.Rolling(5).Mean() + //ma5 := closes.RollingV1(5).Mean() //dframe.NewSeries(closes, dframe.Float, "") //fmt.Println(ma5) d := df.Col("d") @@ -72,7 +72,7 @@ func TestEwm(t *testing.T) { //df = dframe.NewFrame(s1) //fmt.Println(df) //xs := df.Col("x") - //r1 := xs.Rolling(5).Mean() + //r1 := xs.RollingV1(5).Mean() //fmt.Println(r1) // //e1 := xs.EWM(dframe.Alpha{Span: 5, At: dframe.AlphaSpan}, false, false).Mean() diff --git a/formula/README.md b/formula/README.md new file mode 100644 index 0000000000000000000000000000000000000000..cdd22941a376e9628132c8211f5b6da57353c8e5 --- /dev/null +++ b/formula/README.md @@ -0,0 +1,23 @@ +formula +=== + +***通达信指标函数实现*** + +- [通达信指标公式函数大全](https://www.chanluns.com/tdxfun/) + +| 函数名 | 功能 | 示例 | 固定参数 | 序列参数 | +|:---------|:---------------------|:------------------|:-----|:-----| +| ABS | 绝对值 | ABS(X) | [√] | [√] | +| REF | 引用N周期前的值 | REF(CLOSE, 5) | [√] | [√] | +| IF | 逻辑判断 | IF(CLOSE>10,1,0) | [√] | [√] | +| IFF | 逻辑判断 | IFF(CLOSE>10,1,2) | [√] | [√] | +| IFN | 逻辑判断 | IFN(CLOSE>10,1,2) | [√] | [√] | +| HHV | 计算N周期内最高 | HHV(HIGH,5) | [√] | [√] | +| LLV | 计算N周期内最低 | LLV(HLOW,5) | [√] | [√] | +| MAX | 计算AB最大值 | MAX(CLOSE,HIGH) | [√] | [√] | +| MIN | 计算AB最小值 | MIN(CLOSE,HIGH) | [√] | [√] | +| MA | 计算N周期的移动平均值, 简称均线 | MA(CLOSE,5) | [√] | [√] | +| SMA | 计算N周期的简单移动平均值 | SMA(CLOSE,5, 1) | [X] | [X] | +| STD | 计算N周期内的标准差 | STD(CLOSE,N) | [√] | [√] | +| SUM | 求总和, 如果N=0则从第一个有效值开始 | SUM(CLOSE,N) | [X] | [X] | +| BARSLAST | 上一次条件成立到当前的周期数 | BARSLAST(X) | [X] | [X] | diff --git a/formula/hhv.go b/formula/hhv.go index 385c92275b2af2a3b60a0c9359d2a63dd727f010..ec4faa093fa7c85798ee38279736bfa825b69ab0 100644 --- a/formula/hhv.go +++ b/formula/hhv.go @@ -4,5 +4,5 @@ import "gitee.com/quant1x/pandas" // HHV 最近N周期的S最大值 func HHV(S pandas.Series, N any) pandas.Series { - return S.Rolling2(N).Max() + return S.Rolling(N).Max() } diff --git a/formula/llv.go b/formula/llv.go index 734996db4dc97be8eb84873f152ade211e3202b9..b26a7fe65e3c84e5f7d5c67ec87df463176a045a 100644 --- a/formula/llv.go +++ b/formula/llv.go @@ -4,5 +4,5 @@ import "gitee.com/quant1x/pandas" // LLV 最近N周期的S最小值 func LLV(S pandas.Series, N any) pandas.Series { - return S.Rolling2(N).Min() + return S.Rolling(N).Min() } diff --git a/formula/ma.go b/formula/ma.go index 0bada9442108bc93a94461e5a003ad4f0781a8a9..f593f6767dba359fdbdcac90400c709a550099ad 100644 --- a/formula/ma.go +++ b/formula/ma.go @@ -20,5 +20,5 @@ func MA(S pandas.Series, N any) any { default: panic(exception.New(1, "error window")) } - return S.Rolling2(X).Mean().Values() + return S.Rolling(X).Mean().Values() } diff --git a/formula/std.go b/formula/std.go index bcc473cc3fd68167ba7a947979b7a2afe6b59882..4612c708c417a8c2d981a03bb3884db083298564 100644 --- a/formula/std.go +++ b/formula/std.go @@ -4,5 +4,5 @@ import "gitee.com/quant1x/pandas" // STD 序列的N日标准差 func STD(S pandas.Series, N any) pandas.Series { - return S.Rolling2(N).Std() + return S.Rolling(N).Std() } diff --git a/formula/sum.go b/formula/sum.go new file mode 100644 index 0000000000000000000000000000000000000000..3d1da45945c87b523faa2bcde2ce556bdb7a44c1 --- /dev/null +++ b/formula/sum.go @@ -0,0 +1,25 @@ +package formula + +import ( + "gitee.com/quant1x/pandas" + "gitee.com/quant1x/pandas/exception" + "gitee.com/quant1x/pandas/stat" +) + +// SUM 求累和 +// 如果N=0, 则从第一个有效值累加到当前 +// 下一步再统一返回值 +func SUM(S pandas.Series, N any) any { + var X []float32 + switch v := N.(type) { + case int: + X = stat.Repeat[float32](float32(v), S.Len()) + case pandas.Series: + vs := v.Values() + X = pandas.SliceToFloat32(vs) + X = stat.Align(X, pandas.Nil2Float32, S.Len()) + default: + panic(exception.New(1, "error window")) + } + return S.Rolling(X).Sum().Values() +} diff --git a/formula/sum_test.go b/formula/sum_test.go new file mode 100644 index 0000000000000000000000000000000000000000..b291a54c5ea3e9eb5d760997206c7c1596c4acef --- /dev/null +++ b/formula/sum_test.go @@ -0,0 +1,20 @@ +package formula + +import ( + "fmt" + "gitee.com/quant1x/pandas" + "testing" +) + +func TestSUM(t *testing.T) { + f0 := []float64{1.1, 2.2, 1.3, 1.4} + f1 := []float64{70, 80, 75, 83, 86} + f2 := []float64{90, 69, 60, 88, 87} + + s0 := pandas.NewSeriesWithoutType("f0", f0) + s1 := pandas.NewSeriesWithoutType("f1", f1) + s2 := pandas.NewSeriesWithoutType("f2", f2) + fmt.Println(SUM(s0, 4)) + fmt.Println(SUM(s1, 5)) + fmt.Println(SUM(s2, 5)) +} diff --git a/generic_rolling.go b/generic_rolling.go index 3c1eb6e21839a21e8d8ef0611210bf2592835088..251c81f1309ec39af7b69b87e120ef152c31cb16 100644 --- a/generic_rolling.go +++ b/generic_rolling.go @@ -5,9 +5,9 @@ import ( "gitee.com/quant1x/pandas/stat" ) -// Rolling 滑动窗口 -func (self *NDFrame) Rolling(window int) RollingWindow { - return RollingWindow{ +// RollingV1 滑动窗口 +func (self *NDFrame) RollingV1(window int) RollingWindowV1 { + return RollingWindowV1{ window: window, series: self, } @@ -19,8 +19,8 @@ type RollingAndExpandingMixin struct { series Series } -// Rolling2 RollingAndExpandingMixin -func (self *NDFrame) Rolling2(param any) RollingAndExpandingMixin { +// Rolling RollingAndExpandingMixin +func (self *NDFrame) Rolling(param any) RollingAndExpandingMixin { var N []float32 switch v := param.(type) { case int: diff --git a/generic_sum.go b/generic_sum.go new file mode 100644 index 0000000000000000000000000000000000000000..426695660078950e88b96d00b061493e527b4b33 --- /dev/null +++ b/generic_sum.go @@ -0,0 +1,8 @@ +package pandas + +import "gitee.com/quant1x/pandas/stat" + +func (self *NDFrame) Sum() float64 { + fs := ToFloat64(self) + return stat.Sum(fs) +} diff --git a/generic_test.go b/generic_test.go index de9869e050c6917dcd35bfa4fe94ec8c0badd23f..381e43ad64ee96e8cead9e8fadffb44527a8f950 100644 --- a/generic_test.go +++ b/generic_test.go @@ -42,23 +42,23 @@ func TestNDFrameNew(t *testing.T) { nd11 := nd1.Subset(1, 2, true) fmt.Println(nd11.Records()) fmt.Println(nd1.Max()) - fmt.Println(nd1.Rolling(5).Max()) - fmt.Println(nd1.Rolling(5).Min()) + fmt.Println(nd1.RollingV1(5).Max()) + fmt.Println(nd1.RollingV1(5).Min()) - nd12 := nd1.Rolling(5).Mean() + nd12 := nd1.RollingV1(5).Mean() d12 := nd12.Values() fmt.Println(d12) nd13 := nd1.Shift(3) fmt.Println(nd13.Values()) - nd14 := nd1.Rolling(5).StdDev() + nd14 := nd1.RollingV1(5).StdDev() fmt.Println(nd14.Values()) // string d2 := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "nan", "12"} nd2 := NewNDFrame[string]("x", d2...) fmt.Println(nd2) - nd21 := nd2.Rolling(5).Max() + nd21 := nd2.RollingV1(5).Max() fmt.Println(nd21) nd2.FillNa(0, true) fmt.Println(nd2) @@ -75,12 +75,12 @@ func TestRolling2(t *testing.T) { N := 5 fmt.Println("固定的参数, N =", N) - r1 := df.Col("x").Rolling2(5).Mean().Values() + r1 := df.Col("x").Rolling(5).Mean().Values() fmt.Println("序列化结果:", r1) fmt.Println("------------------------------------------------------------") d2 := []float64{1, 2, 3, 4, 3, 3, 2, 1, Nil2Float64, Nil2Float64, Nil2Float64, Nil2Float64} s2 := NewSeries(SERIES_TYPE_FLOAT64, "x", d2) fmt.Printf("序列化参数: %+v\n", s2.Values()) - r2 := df.Col("x").Rolling2(s2).Mean().Values() + r2 := df.Col("x").Rolling(s2).Mean().Values() fmt.Println("序列化结果:", r2) } diff --git a/roling_std.go b/rolling_std.go similarity index 100% rename from roling_std.go rename to rolling_std.go diff --git a/rolling_sum.go b/rolling_sum.go new file mode 100644 index 0000000000000000000000000000000000000000..3e4d479db1775e175e79209beb4a643ff50bd828 --- /dev/null +++ b/rolling_sum.go @@ -0,0 +1,10 @@ +package pandas + +func (r RollingAndExpandingMixin) Sum() Series { + var d []float64 + for _, block := range r.getBlocks() { + d = append(d, block.Sum()) + } + s := NewSeries(SERIES_TYPE_FLOAT64, r.series.Name(), d) + return s +} diff --git a/series_rolling.go b/rolling_v1.go similarity index 81% rename from series_rolling.go rename to rolling_v1.go index 7ef31fb18fc7b6475a7a7808b1ef9f42614ebfba..cb10d224f7c479c82047e9c3cccb403799bde4c1 100644 --- a/series_rolling.go +++ b/rolling_v1.go @@ -1,12 +1,12 @@ package pandas -// RollingWindow is used for rolling window calculations. -type RollingWindow struct { +// RollingWindowV1 is used for rolling window calculations. +type RollingWindowV1 struct { window int series Series } -func (r RollingWindow) getBlocks() (blocks []Series) { +func (r RollingWindowV1) getBlocks() (blocks []Series) { for i := 1; i <= r.series.Len(); i++ { if i < r.window { blocks = append(blocks, r.series.Empty()) @@ -22,7 +22,7 @@ func (r RollingWindow) getBlocks() (blocks []Series) { } // Mean returns the rolling mean. -func (r RollingWindow) Mean() (s Series) { +func (r RollingWindowV1) Mean() (s Series) { var d []float64 for _, block := range r.getBlocks() { d = append(d, block.Mean()) @@ -32,7 +32,7 @@ func (r RollingWindow) Mean() (s Series) { } // StdDev returns the rolling mean. -func (r RollingWindow) StdDev() (s Series) { +func (r RollingWindowV1) StdDev() (s Series) { var d []float64 for _, block := range r.getBlocks() { d = append(d, block.StdDev()) @@ -42,7 +42,7 @@ func (r RollingWindow) StdDev() (s Series) { return } -func (r RollingWindow) Max() any { +func (r RollingWindowV1) Max() any { var fs []float64 var is []int64 var ss []string @@ -67,7 +67,7 @@ func (r RollingWindow) Max() any { } } -func (r RollingWindow) Min() any { +func (r RollingWindowV1) Min() any { var fs []float64 var is []int64 var ss []string diff --git a/series.go b/series.go index ec0d6980c7b31d14b08c195f583782618d9bbf73..c776e874191b699f3a42dfc7446b4c3c66ac1b7d 100644 --- a/series.go +++ b/series.go @@ -62,10 +62,10 @@ type Series interface { // Shift index by desired number of periods with an optional time freq. // 使用可选的时间频率按所需的周期数移动索引. Shift(periods int) Series - // Rolling creates new RollingWindow - Rolling(window int) RollingWindow - // Rolling2 序列化版本 - Rolling2(param any) RollingAndExpandingMixin + // RollingV1 creates new RollingWindowV1 + RollingV1(window int) RollingWindowV1 + // Rolling 序列化版本 + Rolling(param any) RollingAndExpandingMixin // Mean calculates the average value of a series Mean() float64 // StdDev calculates the standard deviation of a series @@ -88,6 +88,8 @@ type Series interface { Ref(param any) (s Series) // Std 计算标准差 Std() float64 + // Sum 计算累和 + Sum() float64 } // NewSeries 指定类型创建序列 diff --git a/series_bool.go b/series_bool.go index aae892a102392ca2ea2cc02746f3b5cad2e4c60a..49d809184eabf74526f5203ffa67c91a90f7bf73 100644 --- a/series_bool.go +++ b/series_bool.go @@ -145,7 +145,7 @@ func (self *SeriesBool) Shift(periods int) Series { }) } -func (self *SeriesBool) Rolling(window int) RollingWindow { +func (self *SeriesBool) RollingV1(window int) RollingWindowV1 { //TODO implement me panic("implement me") } diff --git a/series_bool_test.go b/series_bool_test.go index 09b83f6af52177f4defbede3aa1902a05b44d5ae..f9899f14a52f4d6d925b56b5af9bf22d2ee3b31d 100644 --- a/series_bool_test.go +++ b/series_bool_test.go @@ -23,6 +23,6 @@ func TestNewSeriesBool(t *testing.T) { fmt.Println(s3.Values()) //s4 := NewSeriesBool("x", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) - //d4 := s4.Rolling(5).Mean() + //d4 := s4.RollingV1(5).Mean() //fmt.Printf("d4 = %+v\n", d4.Values()) } diff --git a/series_float32.go b/series_float32.go index 8457cce32387a317b4b7e211f7fdab26dd80558d..07809d7fed60786e758de95d7f523339eca86b39 100644 --- a/series_float32.go +++ b/series_float32.go @@ -59,7 +59,7 @@ func (self *SeriesFloat32) Shift(periods int) Series { panic("implement me") } -func (self *SeriesFloat32) Rolling(window int) RollingWindow { +func (self *SeriesFloat32) RollingV1(window int) RollingWindowV1 { //TODO implement me panic("implement me") } diff --git a/series_float64.go b/series_float64.go index 8d5661fce3a1f01af46e186b02ddc7a2b9cd6c69..cf18de5d0740235ebd23855df89463c0d89925a1 100644 --- a/series_float64.go +++ b/series_float64.go @@ -195,9 +195,9 @@ func (self *SeriesFloat64) Subset(start, end int, opt ...any) Series { return d } -// Rolling creates new RollingWindow -func (self *SeriesFloat64) Rolling(window int) RollingWindow { - return RollingWindow{ +// Rolling creates new RollingWindowV1 +func (self *SeriesFloat64) RollingV1(window int) RollingWindowV1 { + return RollingWindowV1{ window: window, series: self, } diff --git a/series_float64_test.go b/series_float64_test.go index 2d918b5c1f0c0475cedc6ec98d019e5079ada0e6..131b0c8a85761b59e4cde3e42f750f527925d6d8 100644 --- a/series_float64_test.go +++ b/series_float64_test.go @@ -22,10 +22,10 @@ func TestNewSeriesFloat64(t *testing.T) { fmt.Println(s3.Values()) s4 := NewSeriesFloat64("x", []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) - d4 := s4.Rolling(5).Mean() + d4 := s4.RollingV1(5).Mean() fmt.Printf("d4 = %+v\n", d4.Values()) - d5 := s4.Rolling(5).StdDev() + d5 := s4.RollingV1(5).StdDev() fmt.Printf("d5 = %+v\n", d5.Values()) s5 := NewSeriesFloat64("x", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}) diff --git a/series_int64.go b/series_int64.go index 1219919ddc33c03321bbaf8cf56619d6a32ba1cf..d16c9266b00402874aa1243b41afcf8d8fb0359a 100644 --- a/series_int64.go +++ b/series_int64.go @@ -150,8 +150,8 @@ func (self *SeriesInt64) Subset(start, end int, opt ...any) Series { return d } -func (self *SeriesInt64) Rolling(window int) RollingWindow { - return RollingWindow{ +func (self *SeriesInt64) RollingV1(window int) RollingWindowV1 { + return RollingWindowV1{ window: window, series: self, } diff --git a/series_int64_test.go b/series_int64_test.go index 1dfbe652b6652cb67ed2a9da2173921419011a89..9cf91bb039860f29a00de69aea8ecdcb107128ad 100644 --- a/series_int64_test.go +++ b/series_int64_test.go @@ -21,6 +21,6 @@ func TestNewSeriesInt64(t *testing.T) { fmt.Println(s3.Values()) s4 := NewSeriesInt64("x", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) - d4 := s4.Rolling(5).Mean() + d4 := s4.RollingV1(5).Mean() fmt.Printf("d4 = %+v\n", d4.Values()) } diff --git a/series_xstring.go b/series_xstring.go index 063c4c2cfe08e42e0c1bb96103eec5466210b0b4..eee9a6dd9363639c632188392deef4c14a594747 100644 --- a/series_xstring.go +++ b/series_xstring.go @@ -150,7 +150,7 @@ func (self *SeriesString) Shift(periods int) Series { }) } -func (self *SeriesString) Rolling(window int) RollingWindow { +func (self *SeriesString) RollingV1(window int) RollingWindowV1 { //TODO implement me panic("implement me") } diff --git a/series_xstring_test.go b/series_xstring_test.go index 8c9f32a0d8d1ac320eb35d615e30483222214f22..597b9606b9ee6183e93d61a237e9a69ee4cedaf4 100644 --- a/series_xstring_test.go +++ b/series_xstring_test.go @@ -30,6 +30,6 @@ func TestNewSeriesString(t *testing.T) { //fmt.Println(s3) // //s4 := NewSeriesInt64("x", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) - //d4 := s4.Rolling(5).Mean() + //d4 := s4.RollingV1(5).Mean() //fmt.Printf("d4 = %+v\n", d4.Values()) } diff --git a/stat/sum.go b/stat/sum.go new file mode 100644 index 0000000000000000000000000000000000000000..7ab37ff2d413ee27890277c154f7d88c76da8b82 --- /dev/null +++ b/stat/sum.go @@ -0,0 +1,32 @@ +package stat + +import ( + "github.com/viterin/vek" + "github.com/viterin/vek/vek32" + "unsafe" +) + +// Sum 计算累和 +func Sum[T StatType](f []T) T { + if len(f) == 0 { + return T(0) + } + var d any + var s any + s = f + bitSize := unsafe.Sizeof(f[0]) + if bitSize == 4 { + d = vek32.Sum(s.([]float32)) + } else if bitSize == 8 { + d = vek.Sum(s.([]float64)) + } else { + // 剩下的就是int32和int64, 循环吧 + m := T(0) + for _, v := range f { + m += v + } + d = m + } + + return d.(T) +}