From 6d258ab5c62620496581913c5fd7547fb1d7e56a Mon Sep 17 00:00:00 2001 From: wangfeng Date: Fri, 10 Feb 2023 12:45:51 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8E=9Fselect=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E8=AE=B0=E5=BD=95=E7=9A=84=E6=96=B9=E6=B3=95=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dataframe_subset.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dataframe_subset.go b/dataframe_subset.go index b2c7987..8da8937 100644 --- a/dataframe_subset.go +++ b/dataframe_subset.go @@ -23,7 +23,7 @@ func (self DataFrame) Subset(start, end int) DataFrame { } // Select 选择一段记录 -func (self DataFrame) Select(p Range) DataFrame { +func (self DataFrame) SelectRows(p Range) DataFrame { columns := []Series{} for i := range self.columns { columns = append(columns, self.columns[i].Select(p)) -- Gitee From 6af968b607160035dd622943574b9a38f53c01dd Mon Sep 17 00:00:00 2001 From: wangfeng Date: Fri, 10 Feb 2023 12:46:31 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=B4=A2=E5=BC=95?= =?UTF-8?q?=E5=AF=B9=E8=B1=A1=E5=92=8C=E9=80=89=E6=8B=A9=E5=88=97=E7=9A=84?= =?UTF-8?q?=E5=A4=84=E7=90=86=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dataframe_indexes.go | 110 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 dataframe_indexes.go diff --git a/dataframe_indexes.go b/dataframe_indexes.go new file mode 100644 index 0000000..160d4f0 --- /dev/null +++ b/dataframe_indexes.go @@ -0,0 +1,110 @@ +package pandas + +import "fmt" + +func parseSelectIndexes(l int, indexes SelectIndexes, colnames []string) ([]int, error) { + var idx []int + switch indexes.(type) { + case []int: + idx = indexes.([]int) + case int: + idx = []int{indexes.(int)} + case []bool: + bools := indexes.([]bool) + if len(bools) != l { + return nil, fmt.Errorf("indexing error: index dimensions mismatch") + } + for i, b := range bools { + if b { + idx = append(idx, i) + } + } + case string: + s := indexes.(string) + i := findInStringSlice(s, colnames) + if i < 0 { + return nil, fmt.Errorf("can't select columns: column name %q not found", s) + } + idx = append(idx, i) + case []string: + xs := indexes.([]string) + for _, s := range xs { + i := findInStringSlice(s, colnames) + if i < 0 { + return nil, fmt.Errorf("can't select columns: column name %q not found", s) + } + idx = append(idx, i) + } + //case Series: + // s := indexes.(Series) + // //if err := s.Err; err != nil { + // // return nil, fmt.Errorf("indexing error: new values has errors: %v", err) + // //} + // //if s.HasNaN() { + // // return nil, fmt.Errorf("indexing error: indexes contain NaN") + // //} + // switch s.Type() { + // case SERIES_TYPE_INT64: + // return s.AsInt() + // case series.Bool: + // bools, err := s.Bool() + // if err != nil { + // return nil, fmt.Errorf("indexing error: %v", err) + // } + // return parseSelectIndexes(l, bools, colnames) + // case series.String: + // xs := indexes.(series.Series).Records() + // return parseSelectIndexes(l, xs, colnames) + // default: + // return nil, fmt.Errorf("indexing error: unknown indexing mode") + // } + default: + return nil, fmt.Errorf("indexing error: unknown indexing mode") + } + return idx, nil +} + +// SelectIndexes are the supported indexes used for the DataFrame.Select method. Currently supported are: +// +// int // Matches the given index number +// []int // Matches all given index numbers +// []bool // Matches all columns marked as true +// string // Matches the column with the matching column name +// []string // Matches all columns with the matching column names +// Series [Int] // Same as []int +// Series [Bool] // Same as []bool +// Series [String] // Same as []string +type SelectIndexes interface{} + +// Select the given DataFrame columns +func (df DataFrame) Select(indexes SelectIndexes) DataFrame { + if df.Err != nil { + return df + } + idx, err := parseSelectIndexes(df.ncols, indexes, df.Names()) + if err != nil { + return DataFrame{Err: fmt.Errorf("can't select columns: %v", err)} + } + columns := make([]Series, len(idx)) + for k, i := range idx { + if i < 0 || i >= df.ncols { + return DataFrame{Err: fmt.Errorf("can't select columns: index out of range")} + } + columns[k] = df.columns[i].Copy() + } + nrows, ncols, err := checkColumnsDimensions(columns...) + if err != nil { + return DataFrame{Err: err} + } + df = DataFrame{ + columns: columns, + ncols: ncols, + nrows: nrows, + } + colnames := df.Names() + fixColnames(colnames) + for i, colname := range colnames { + df.columns[i].Rename(colname) + } + return df +} -- Gitee From 204b61631e02bf328466d07e84ddf560a201a19c Mon Sep 17 00:00:00 2001 From: wangfeng Date: Fri, 10 Feb 2023 12:47:39 +0800 Subject: [PATCH 3/3] =?UTF-8?q?#I6CYOF=20=E5=AE=9E=E7=8E=B0=E4=BA=86?= =?UTF-8?q?=E9=80=9A=E8=BE=BE=E4=BF=A1=E6=95=B0=E6=8D=AE=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=AF=B9=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dataframe_xstring.go | 2 +- go.mod | 6 +- go.sum | 8 +-- stat/params_test.go | 3 +- tdx/tdx.go | 131 +++++++++++++++++++++++++++++++++++++++++++ tdx/tdx_test.go | 30 ++++++++++ 6 files changed, 171 insertions(+), 9 deletions(-) create mode 100644 tdx/tdx.go create mode 100644 tdx/tdx_test.go diff --git a/dataframe_xstring.go b/dataframe_xstring.go index 56f03de..c5084e8 100644 --- a/dataframe_xstring.go +++ b/dataframe_xstring.go @@ -9,7 +9,7 @@ import ( // String implements the Stringer interface for DataFrame func (self DataFrame) String() (str string) { - return self.print(true, true, true, true, 10, 70, "DataFrame") + return self.print(true, false, true, true, 10, 70, "DataFrame") } func (self DataFrame) print( diff --git a/go.mod b/go.mod index dae8871..b03dde0 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,14 @@ module gitee.com/quant1x/pandas go 1.20 require ( + gitee.com/quant1x/gotdx v1.1.2 github.com/google/go-cmp v0.5.8 github.com/huandu/go-clone v1.4.1 github.com/mymmsc/gox v1.3.1 github.com/tealeg/xlsx v1.0.5 github.com/tealeg/xlsx/v3 v3.2.4 github.com/viterin/vek v0.4.0 + golang.org/x/exp v0.0.0-20220907003533-145caa8ea1d0 gonum.org/v1/gonum v0.12.0 ) @@ -18,13 +20,11 @@ require ( github.com/google/btree v1.0.0 // indirect github.com/kr/pretty v0.2.1 // indirect github.com/kr/text v0.1.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/rogpeppe/fastuuid v1.2.0 // indirect github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa // indirect github.com/viterin/partial v1.0.0 // indirect - golang.org/x/exp v0.0.0-20220907003533-145caa8ea1d0 // indirect golang.org/x/sys v0.4.0 // indirect golang.org/x/text v0.5.0 // indirect ) diff --git a/go.sum b/go.sum index 0799afd..a59d319 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +gitee.com/quant1x/gotdx v1.1.2 h1:iahnhbUYuuKHVxFqjYNOzBZJ53JHOU6Whc1I0a4tfKI= +gitee.com/quant1x/gotdx v1.1.2/go.mod h1:4FDJznsZfYH1kV00GMD/NxYdeYsSp7NE4RedUxritxs= github.com/chewxy/math32 v1.10.1 h1:LFpeY0SLJXeaiej/eIp2L40VYfscTvKh/FSEZ68uMkU= github.com/chewxy/math32 v1.10.1/go.mod h1:dOB2rcuFrCn6UHrze36WSLVPKtzPMRAQvBvUwkSsLqs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -20,10 +22,8 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mymmsc/gox v1.3.1 h1:CM6bGBuf5+UK/af06Dv8U8becBlh6jyZ0RP2kEsYT84= github.com/mymmsc/gox v1.3.1/go.mod h1:A67NVxiHB3ZBcRfZVjvDfIVTUe5JaUjuy/F70ucUtdk= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= diff --git a/stat/params_test.go b/stat/params_test.go index 9ec9bd9..83515fe 100644 --- a/stat/params_test.go +++ b/stat/params_test.go @@ -7,7 +7,8 @@ import ( func TestAnyToSlice(t *testing.T) { d1 := []float64{1, 2, 3, 4} + d2 := []int32{1, 2, 3, 4} fmt.Println(AnyToSlice[float64](float64(1), 5)) fmt.Println(AnyToSlice[float64](d1, 3)) - fmt.Println(AnyToSlice[int32](d1, 5)) + fmt.Println(AnyToSlice[int32](d2, 5)) } diff --git a/tdx/tdx.go b/tdx/tdx.go new file mode 100644 index 0000000..494e6f8 --- /dev/null +++ b/tdx/tdx.go @@ -0,0 +1,131 @@ +package tdx + +import ( + "gitee.com/quant1x/gotdx/proto" + "gitee.com/quant1x/gotdx/quotes" + "gitee.com/quant1x/pandas" + "gitee.com/quant1x/pandas/stat" + "strings" +) + +var ( + stdApi *quotes.StdApi = nil +) + +func prepare() *quotes.StdApi { + if stdApi == nil { + std_api, err := quotes.NewStdApi() + if err != nil { + return nil + } + stdApi = std_api + } + return stdApi +} + +func startsWith(str string, prefixs []string) bool { + if len(str) == 0 || len(prefixs) == 0 { + return false + } + for _, prefix := range prefixs { + if strings.HasPrefix(str, prefix) { + return true + } + } + return false +} + +// 判断股票ID对应的证券市场匹配规则 +// +// ['50', '51', '60', '90', '110'] 为 sh +// ['00', '12','13', '18', '15', '16', '18', '20', '30', '39', '115'] 为 sz +// ['5', '6', '9'] 开头的为 sh, 其余为 sz +func getStockMarket(symbol string) string { + //:param string: False 返回市场ID,否则市场缩写名称 + //:param symbol: 股票ID, 若以 'sz', 'sh' 开头直接返回对应类型,否则使用内置规则判断 + //:return 'sh' or 'sz' + + market := "sh" + if startsWith(symbol, []string{"sh", "sz", "SH", "SZ"}) { + market = strings.ToLower(symbol[0:2]) + } else if startsWith(symbol, []string{"50", "51", "60", "68", "90", "110", "113", "132", "204"}) { + market = "sh" + } else if startsWith(symbol, []string{"00", "12", "13", "18", "15", "16", "18", "20", "30", "39", "115", "1318"}) { + market = "sz" + } else if startsWith(symbol, []string{"5", "6", "9", "7"}) { + market = "sh" + } else if startsWith(symbol, []string{"4", "8"}) { + market = "bj" + } + return market +} + +func getStockMarketId(symbol string) uint8 { + market := getStockMarket(symbol) + marketId := proto.MarketShangHai + if market == "sh" { + marketId = proto.MarketShangHai + } else if market == "sz" { + marketId = proto.MarketShenZhen + } else if market == "bj" { + marketId = proto.MarketBeiJing + } + //# logger.debug(f"market => {market}") + + return marketId +} + +// GetKLine 获取日K线 +func GetKLine(code string, start uint16, count uint16) pandas.DataFrame { + api := prepare() + + marketId := getStockMarketId(code) + data, _ := api.GetKLine(marketId, code, proto.KLINE_TYPE_RI_K, start, count) + df := pandas.LoadStructs(data.List) + df = df.Select([]string{"Open", "Close", "High", "Low", "Vol", "Amount", "DateTime"}) + err := df.SetNames("open", "close", "high", "low", "vol", "amount", "date") + if err != nil { + return pandas.DataFrame{} + } + + return df +} + +// GetKLine 获取日K线 +func GetKLineAll(code string) pandas.DataFrame { + api := prepare() + + marketId := getStockMarketId(code) + history := make([]quotes.SecurityBar, 0) + count := uint16(800) + step := uint16(800) + start := uint16(0) + hs := make([]quotes.SecurityBarsReply, 0) + for { + data, err := api.GetKLine(marketId, code, proto.KLINE_TYPE_RI_K, uint16(start), uint16(count)) + if err != nil { + panic("接口异常") + } + hs = append(hs, (*data)) + if data.Count < count { + // 已经是最早的记录 + // 需要排序 + break + } + start += step + } + hs = stat.Reverse(hs) + for _, v := range hs { + history = append(history, v.List...) + } + + //data, _ := api.GetKLine(marketId, code, proto.KLINE_TYPE_RI_K, start, count) + df := pandas.LoadStructs(history) + df = df.Select([]string{"Open", "Close", "High", "Low", "Vol", "Amount", "DateTime"}) + err := df.SetNames("open", "close", "high", "low", "vol", "amount", "date") + if err != nil { + return pandas.DataFrame{} + } + + return df +} diff --git a/tdx/tdx_test.go b/tdx/tdx_test.go new file mode 100644 index 0000000..1c11c5e --- /dev/null +++ b/tdx/tdx_test.go @@ -0,0 +1,30 @@ +package tdx + +import ( + "fmt" + "testing" +) + +func TestGetKLine(t *testing.T) { + code := "000002" + data := GetKLine(code, 0, 5) + df := data + //date := df.Col("date") + //t1 := date.Map(func(element pandas.Element) pandas.Element { + // e := element.String()[0:10] + // element.Set(e) + // return element + //}) + //df = df.Mutate(t1) + fmt.Println(df) + len := df.Nrow() + df1 := df.Select([]int{0}) + df.Col("date") + fmt.Println(df1) + //df = df.Concat(df1) + fmt.Println(df) + + df = GetKLineAll(code) + fmt.Println(df) + _ = len +} -- Gitee