ok
This commit is contained in:
76
conv/conv.go
Normal file
76
conv/conv.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package conv
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// AnyToString 任意类型转字符串
|
||||
// in: 输入值
|
||||
// 返回: 转换后的字符串
|
||||
func AnyToString(in any) (s string) {
|
||||
if in == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return in.(string)
|
||||
}
|
||||
|
||||
// AnyToInt 将动态类型转为 int(两仓库 internal 中逻辑一致,此处合并分支)。
|
||||
func AnyToInt(v any) int {
|
||||
switch val := v.(type) {
|
||||
case int:
|
||||
return val
|
||||
case int8:
|
||||
return int(val)
|
||||
case int16:
|
||||
return int(val)
|
||||
case int32:
|
||||
return int(val)
|
||||
case int64:
|
||||
return int(val)
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
return int(reflect.ValueOf(val).Uint())
|
||||
case float32:
|
||||
return int(val)
|
||||
case float64:
|
||||
return int(val)
|
||||
case string:
|
||||
i, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return i
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// AnyToFloat64 将动态类型转为 float64(合并 stock 对 int/uint 等分支与 gostock 的 string 分支)。
|
||||
func AnyToFloat64(v any) float64 {
|
||||
switch val := v.(type) {
|
||||
case float64:
|
||||
return val
|
||||
case string:
|
||||
return String2Float64(val)
|
||||
case float32:
|
||||
return float64(val)
|
||||
case int:
|
||||
return float64(val)
|
||||
case uint:
|
||||
return float64(val)
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// String2Float64 字符串转Float64
|
||||
// floatStr: 小数点数字的字符串
|
||||
// 返回: 转换后的64位浮点数,转换失败返回0
|
||||
func String2Float64(floatStr string) (floatNum float64) {
|
||||
floatNum, err := strconv.ParseFloat(floatStr, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return
|
||||
}
|
||||
13
day/ymd.go
Normal file
13
day/ymd.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package day
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.apinb.com/bsm-sdk/core/utils"
|
||||
)
|
||||
|
||||
// TodayYmd 返回本地日期的 YYYYMMDD 整数(gostock internal/models/query.GetYmd)。
|
||||
func TodayYmd() int {
|
||||
ymd := time.Now().Format("20060102")
|
||||
return utils.String2Int(ymd)
|
||||
}
|
||||
31
go.mod
Normal file
31
go.mod
Normal file
@@ -0,0 +1,31 @@
|
||||
module git.apinb.com/quant/qsdk
|
||||
|
||||
go 1.26.1
|
||||
|
||||
require (
|
||||
git.apinb.com/bsm-sdk/core v0.1.9
|
||||
github.com/jedib0t/go-pretty/v6 v6.7.9
|
||||
gorm.io/gorm v1.31.1
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.6.0 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/oklog/ulid/v2 v2.1.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
|
||||
golang.org/x/crypto v0.31.0 // indirect
|
||||
golang.org/x/sync v0.11.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
gorm.io/driver/mysql v1.6.0 // indirect
|
||||
gorm.io/driver/postgres v1.6.0 // indirect
|
||||
)
|
||||
60
go.sum
Normal file
60
go.sum
Normal file
@@ -0,0 +1,60 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
git.apinb.com/bsm-sdk/core v0.1.9 h1:Pp0zpSeX7OnFb3JQdXdJHR74EvU02HnMauk4wI0/gVg=
|
||||
git.apinb.com/bsm-sdk/core v0.1.9/go.mod h1:R5Rm/Ep4D3mJ97dL6sLRi3jtfQxi2ftekp2E3frts/8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
|
||||
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jedib0t/go-pretty/v6 v6.7.9 h1:frarzQWmkZd97syT81+TH8INKPpzoxQnk+Mk5EIHSrM=
|
||||
github.com/jedib0t/go-pretty/v6 v6.7.9/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
|
||||
github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
|
||||
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg=
|
||||
gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo=
|
||||
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
|
||||
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
|
||||
gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
|
||||
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
||||
83
markdown/builder.go
Normal file
83
markdown/builder.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package markdown
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Builder 用于拼接 Markdown 文本(原 stock internal/logic/a、gostock internal/logic/libs 中重复实现)。
|
||||
type Builder struct {
|
||||
buf bytes.Buffer
|
||||
}
|
||||
|
||||
// MarkdownBuilder 兼容旧项目中的类型名。
|
||||
type MarkdownBuilder = Builder
|
||||
|
||||
func NewBuilder() *Builder {
|
||||
return &Builder{}
|
||||
}
|
||||
|
||||
// NewMarkdownBuilder 兼容旧项目中的构造函数名。
|
||||
func NewMarkdownBuilder() *Builder {
|
||||
return NewBuilder()
|
||||
}
|
||||
|
||||
func (m *Builder) Title(title string) {
|
||||
m.buf.WriteString("# " + title + "\n\n")
|
||||
}
|
||||
|
||||
func (m *Builder) Catalog(text string) {
|
||||
m.buf.WriteString("## " + text + "\n\n")
|
||||
}
|
||||
|
||||
func (m *Builder) Text(text string) {
|
||||
m.buf.WriteString(text + "\n\n")
|
||||
}
|
||||
|
||||
func (m *Builder) KvText(key, val string) {
|
||||
m.buf.WriteString(key + " :" + val + " \n")
|
||||
}
|
||||
|
||||
func (m *Builder) BR() {
|
||||
m.buf.WriteString("\n")
|
||||
}
|
||||
|
||||
func (m *Builder) Code(lang, code string) {
|
||||
m.buf.WriteString("```" + lang + "\n")
|
||||
m.buf.WriteString(code + "\n")
|
||||
m.buf.WriteString("```\n\n")
|
||||
}
|
||||
|
||||
// Table 生成 Markdown 表格。
|
||||
func (m *Builder) Table(catalog string, headers []string, rows [][]string) {
|
||||
if catalog != "" {
|
||||
m.buf.WriteString("## " + catalog + "\n")
|
||||
}
|
||||
m.buf.WriteString("| " + strings.Join(headers, " | ") + " |\n")
|
||||
|
||||
m.buf.WriteString("| ")
|
||||
for _, header := range headers {
|
||||
m.buf.WriteString(strings.Repeat("-", len(header)) + "|")
|
||||
}
|
||||
m.buf.WriteString("\n")
|
||||
for _, row := range rows {
|
||||
m.buf.WriteString("| " + strings.Join(row, " | ") + " |\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Builder) Build() string {
|
||||
return m.buf.String()
|
||||
}
|
||||
|
||||
func (m *Builder) SaveToFile(filePath string) error {
|
||||
rf, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rf.Close()
|
||||
|
||||
_, err = io.Copy(rf, &m.buf)
|
||||
return err
|
||||
}
|
||||
28
schema/blocks_index.go
Normal file
28
schema/blocks_index.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package schema
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
// BlocksIndex 板块索引(采用 dataset/stock 的 code 唯一约束)。
|
||||
type BlocksIndex struct {
|
||||
gorm.Model
|
||||
Code string `gorm:"type:varchar(50);not null;default:'';comment:板块代码;uniqueIndex:uq_blocks_index_code" json:"code"`
|
||||
Name string `gorm:"type:varchar(50);not null;default:'';comment:板块名称" json:"name"`
|
||||
IsRecommend bool `gorm:"type:bool;not null;default:false;comment:是否推荐" json:"is_recommend"`
|
||||
}
|
||||
|
||||
func (BlocksIndex) TableName() string {
|
||||
return "blocks_index"
|
||||
}
|
||||
|
||||
// Key 板块业务主键:code。
|
||||
func (b *BlocksIndex) Key() string {
|
||||
return b.Code
|
||||
}
|
||||
|
||||
// DisplayName 展示名称:非空 name,否则回退 code。
|
||||
func (b *BlocksIndex) DisplayName() string {
|
||||
if b.Name != "" {
|
||||
return b.Name
|
||||
}
|
||||
return b.Code
|
||||
}
|
||||
28
schema/blocks_member.go
Normal file
28
schema/blocks_member.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package schema
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
// BlocksMember 板块成分股。
|
||||
type BlocksMember struct {
|
||||
gorm.Model
|
||||
TiCode string `gorm:"type:varchar(50);not null;default:'';comment:板块代码;index" json:"ti_code"`
|
||||
StockCode string `gorm:"type:varchar(50);not null;default:'';comment:股票代码;index" json:"stock_code"`
|
||||
Weight float64 `gorm:"type:float;not null;default:0;comment:权重" json:"weight"`
|
||||
}
|
||||
|
||||
func (BlocksMember) TableName() string {
|
||||
return "blocks_member"
|
||||
}
|
||||
|
||||
// Key 成分在板块内的键:ti_code + stock_code。
|
||||
func (b *BlocksMember) Key() string {
|
||||
if b.TiCode == "" && b.StockCode == "" {
|
||||
return ""
|
||||
}
|
||||
return b.TiCode + "/" + b.StockCode
|
||||
}
|
||||
|
||||
// HasWeight 是否带权重量化成分。
|
||||
func (b *BlocksMember) HasWeight() bool {
|
||||
return b.Weight > 0
|
||||
}
|
||||
31
schema/money_total.go
Normal file
31
schema/money_total.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package schema
|
||||
|
||||
// MoneyTotal 资金流汇总(采用 dataset/stock 的索引定义)。
|
||||
type MoneyTotal struct {
|
||||
ID uint `gorm:"primarykey"`
|
||||
Code string `gorm:"type:varchar(20);not null;uniqueIndex:uq_money_total_code"`
|
||||
Last1DayMfAmount float64
|
||||
Last3DayMfAmount float64
|
||||
Last1DayTotalAmount float64
|
||||
Last3DayTotalAmount float64
|
||||
IsGreaterPervious bool
|
||||
}
|
||||
|
||||
func (MoneyTotal) TableName() string {
|
||||
return "money_total"
|
||||
}
|
||||
|
||||
// Key 与唯一索引 uq_money_total_code 一致。
|
||||
func (m *MoneyTotal) Key() string {
|
||||
return m.Code
|
||||
}
|
||||
|
||||
// NetFlow1Day 最近 1 日主力净流入(万元),与字段语义一致。
|
||||
func (m *MoneyTotal) NetFlow1Day() float64 {
|
||||
return m.Last1DayMfAmount
|
||||
}
|
||||
|
||||
// NetFlow3Day 最近 3 日主力净流入(万元)。
|
||||
func (m *MoneyTotal) NetFlow3Day() float64 {
|
||||
return m.Last3DayMfAmount
|
||||
}
|
||||
30
schema/pledge_stat.go
Normal file
30
schema/pledge_stat.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package schema
|
||||
|
||||
// PledgeStat 股权质押统计(表 pledge_stat;dataset/stock 中原为 PledgeStatModel,业务层 Save 请留在各应用内)。
|
||||
type PledgeStat struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
TsCode string `gorm:"type:varchar(50);not null;default:'';comment:股票代码;uniqueIndex:uq_pledge_stat_ts_code" json:"ts_code"`
|
||||
EndDate int `gorm:"type:int;not null;default:0;comment:截止日期" json:"end_date"`
|
||||
PledgeCount float64 `json:"pledge_count"`
|
||||
UnrestPledge float64 `json:"unrest_pledge"`
|
||||
RestPledge float64 `json:"rest_pledge"`
|
||||
TotalShare float64 `json:"total_share"`
|
||||
PledgeRatio float64 `json:"pledge_ratio"`
|
||||
}
|
||||
|
||||
func (PledgeStat) TableName() string {
|
||||
return "pledge_stat"
|
||||
}
|
||||
|
||||
// Key 与唯一约束 uq_pledge_stat_ts_code 一致:ts_code。
|
||||
func (p *PledgeStat) Key() string {
|
||||
return p.TsCode
|
||||
}
|
||||
|
||||
// HasPledgeFacts 是否具备任一质押统计字段(比例、次数或股本)。
|
||||
func (p *PledgeStat) HasPledgeFacts() bool {
|
||||
return p.PledgeRatio > 0 || p.PledgeCount > 0 || p.TotalShare > 0
|
||||
}
|
||||
|
||||
// PledgeStatModel 兼容 dataset/stock 中的类型名。
|
||||
type PledgeStatModel = PledgeStat
|
||||
19
schema/register.go
Normal file
19
schema/register.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package schema
|
||||
|
||||
import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// RegisterAutoMigrate 将本包内与 stock/gostock 共用的表注册到 bsm-sdk 的迁移列表(可选;也可在各应用 init 中自行 AppendMigrate)。
|
||||
func RegisterAutoMigrate() {
|
||||
for _, t := range []any{
|
||||
&StockBasic{},
|
||||
&StockDaily{},
|
||||
&BlocksIndex{},
|
||||
&BlocksMember{},
|
||||
&MoneyTotal{},
|
||||
&PledgeStat{},
|
||||
&StockIndicator{},
|
||||
&StockFinaIndicator{},
|
||||
} {
|
||||
database.AppendMigrate(t)
|
||||
}
|
||||
}
|
||||
107
schema/scopes.go
Normal file
107
schema/scopes.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package schema
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
// ScopeTsCode 按 ts_code 精确过滤;空字符串则不加条件。
|
||||
func ScopeTsCode(tsCode string) func(*gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
if tsCode == "" {
|
||||
return db
|
||||
}
|
||||
return db.Where("ts_code = ?", tsCode)
|
||||
}
|
||||
}
|
||||
|
||||
// ScopeTsCodes 按 ts_code IN (...);nil 或空切片不加条件。
|
||||
func ScopeTsCodes(tsCodes []string) func(*gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
if len(tsCodes) == 0 {
|
||||
return db
|
||||
}
|
||||
return db.Where("ts_code IN ?", tsCodes)
|
||||
}
|
||||
}
|
||||
|
||||
// ScopeTradeDateEQ 按 trade_date 等于;0 表示不加条件。
|
||||
func ScopeTradeDateEQ(tradeDate int) func(*gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
if tradeDate == 0 {
|
||||
return db
|
||||
}
|
||||
return db.Where("trade_date = ?", tradeDate)
|
||||
}
|
||||
}
|
||||
|
||||
// ScopeTradeDateBetween trade_date 区间 [start,end];仅传一侧时做单边约束;均为 0 不加条件。
|
||||
func ScopeTradeDateBetween(start, end int) func(*gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
switch {
|
||||
case start > 0 && end > 0:
|
||||
return db.Where("trade_date BETWEEN ? AND ?", start, end)
|
||||
case start > 0:
|
||||
return db.Where("trade_date >= ?", start)
|
||||
case end > 0:
|
||||
return db.Where("trade_date <= ?", end)
|
||||
default:
|
||||
return db
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ScopeStockDailyTsDate 日线:ts_code + 交易日(任一为空则该项不限制)。
|
||||
func ScopeStockDailyTsDate(tsCode string, tradeDate int) func(*gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Scopes(ScopeTsCode(tsCode), ScopeTradeDateEQ(tradeDate))
|
||||
}
|
||||
}
|
||||
|
||||
// ScopeStockIndicatorTsDate 指标表:ts_code + trade_date。
|
||||
func ScopeStockIndicatorTsDate(tsCode string, tradeDate int) func(*gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Scopes(ScopeTsCode(tsCode), ScopeTradeDateEQ(tradeDate))
|
||||
}
|
||||
}
|
||||
|
||||
// ScopeFinaTsPeriod 财务指标:ts_code + period(与 uniqueIndex un_fi_code_date 一致);period 为 0 时不限制 period。
|
||||
func ScopeFinaTsPeriod(tsCode string, period int) func(*gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
db = db.Scopes(ScopeTsCode(tsCode))
|
||||
if period != 0 {
|
||||
db = db.Where("period = ?", period)
|
||||
}
|
||||
return db
|
||||
}
|
||||
}
|
||||
|
||||
// ScopeBlocksIndexCode 板块 code。
|
||||
func ScopeBlocksIndexCode(code string) func(*gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
if code == "" {
|
||||
return db
|
||||
}
|
||||
return db.Where("code = ?", code)
|
||||
}
|
||||
}
|
||||
|
||||
// ScopeBlocksMemberPair 板块 ti_code + 成分 stock_code。
|
||||
func ScopeBlocksMemberPair(tiCode, stockCode string) func(*gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
if tiCode != "" {
|
||||
db = db.Where("ti_code = ?", tiCode)
|
||||
}
|
||||
if stockCode != "" {
|
||||
db = db.Where("stock_code = ?", stockCode)
|
||||
}
|
||||
return db
|
||||
}
|
||||
}
|
||||
|
||||
// ScopeMoneyTotalCode 资金流 code。
|
||||
func ScopeMoneyTotalCode(code string) func(*gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
if code == "" {
|
||||
return db
|
||||
}
|
||||
return db.Where("code = ?", code)
|
||||
}
|
||||
}
|
||||
44
schema/stock_basic.go
Normal file
44
schema/stock_basic.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package schema
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
// StockBasic 股票基本信息表(合并 dataset/stock 与 gostock 字段;gostock 独有 Level、Desc)。
|
||||
type StockBasic struct {
|
||||
gorm.Model
|
||||
TsCode string `gorm:"type:varchar(50);not null;index;comment:TS代码"`
|
||||
Symbol string `gorm:"type:varchar(50);not null;comment:股票代码"`
|
||||
Name string `gorm:"type:varchar(50);not null;comment:股票名称"`
|
||||
Area string `gorm:"type:varchar(50);not null;default:'';comment:地域"`
|
||||
Industry string `gorm:"type:varchar(50);not null;default:'';comment:所属行业"`
|
||||
FullName string `gorm:"type:varchar(500);comment:股票全称"`
|
||||
EnName string `gorm:"type:varchar(200);comment:英文全称"`
|
||||
CnSpell string `gorm:"type:varchar(50);not null;default:'';comment:拼音缩写"`
|
||||
Market string `gorm:"type:varchar(50);not null;comment:市场类型(主板/创业板/科创板/CDR)"`
|
||||
Exchange string `gorm:"type:varchar(50);comment:交易所代码"`
|
||||
ListDate string `gorm:"type:varchar(50);not null;comment:上市日期"`
|
||||
IsHS string `gorm:"type:varchar(2);default:'N';comment:是否沪深港通标的,N否 H沪股通 S深股通"`
|
||||
ActName string `gorm:"type:varchar(500);not null;default:'';comment:实控人名称"`
|
||||
ActEntType string `gorm:"type:varchar(50);not null;default:'';comment:实控人企业性质"`
|
||||
}
|
||||
|
||||
func (StockBasic) TableName() string {
|
||||
return "stock_basic"
|
||||
}
|
||||
|
||||
// Key 业务主键:TS 代码。
|
||||
func (s *StockBasic) Key() string {
|
||||
return s.TsCode
|
||||
}
|
||||
|
||||
// DisplaySymbol 展示用代码:有 symbol 用 symbol,否则用 ts_code。
|
||||
func (s *StockBasic) DisplaySymbol() string {
|
||||
if s.Symbol != "" {
|
||||
return s.Symbol
|
||||
}
|
||||
return s.TsCode
|
||||
}
|
||||
|
||||
// IsNorthbound 是否沪深港通标的(H 沪股通 / S 深股通)。
|
||||
func (s *StockBasic) IsNorthbound() bool {
|
||||
return s.IsHS == "H" || s.IsHS == "S"
|
||||
}
|
||||
58
schema/stock_daily.go
Normal file
58
schema/stock_daily.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package schema
|
||||
|
||||
import "strconv"
|
||||
|
||||
// StockDaily 股票日线数据(两仓库结构一致)。
|
||||
type StockDaily struct {
|
||||
ID uint `gorm:"primarykey;autoIncrement" json:"id"`
|
||||
TsCode string `gorm:"type:varchar(20);not null;index:idx_ts_code;uniqueIndex:un_code_date;comment:股票代码" json:"ts_code"`
|
||||
TradeDate int `gorm:"index:idx_trade_date;uniqueIndex:un_code_date;comment:交易日期" json:"trade_date"`
|
||||
Open float64 `gorm:"type:decimal(10,4);comment:开盘价" json:"open"`
|
||||
High float64 `gorm:"type:decimal(10,4);comment:最高价" json:"high"`
|
||||
Low float64 `gorm:"type:decimal(10,4);comment:最低价" json:"low"`
|
||||
Close float64 `gorm:"type:decimal(10,4);comment:收盘价" json:"close"`
|
||||
PreClose float64 `gorm:"type:decimal(10,4);comment:昨收价(除权价)" json:"pre_close"`
|
||||
Change float64 `gorm:"type:decimal(10,4);comment:涨跌额" json:"change"`
|
||||
PctChg float64 `gorm:"type:decimal(10,6);comment:涨跌幅(%)" json:"pct_chg"`
|
||||
DayChg float64 `gorm:"type:decimal(6,2);comment:日均振幅(%)" json:"day_chg"`
|
||||
Vol float64 `gorm:"type:decimal(15,2);comment:成交量(手)" json:"vol"`
|
||||
Amount float64 `gorm:"type:decimal(20,2);comment:成交额(千元)" json:"amount"`
|
||||
}
|
||||
|
||||
func (StockDaily) TableName() string {
|
||||
return "stock_daily"
|
||||
}
|
||||
|
||||
// Key 业务主键:ts_code + 交易日。
|
||||
func (d *StockDaily) Key() string {
|
||||
if d.TsCode == "" && d.TradeDate == 0 {
|
||||
return ""
|
||||
}
|
||||
return d.TsCode + "#" + strconv.Itoa(d.TradeDate)
|
||||
}
|
||||
|
||||
// IsRising 是否收涨(昨收有效且收盘高于昨收)。
|
||||
func (d *StockDaily) IsRising() bool {
|
||||
return d.PreClose > 0 && d.Close > d.PreClose
|
||||
}
|
||||
|
||||
// IsFalling 是否收跌。
|
||||
func (d *StockDaily) IsFalling() bool {
|
||||
return d.PreClose > 0 && d.Close < d.PreClose
|
||||
}
|
||||
|
||||
// PctChangeFromPre 由昨收计算的涨跌幅(%);昨收无效时返回 0。
|
||||
func (d *StockDaily) PctChangeFromPre() float64 {
|
||||
if d.PreClose <= 0 {
|
||||
return 0
|
||||
}
|
||||
return (d.Close - d.PreClose) / d.PreClose * 100
|
||||
}
|
||||
|
||||
// AmplitudePct 振幅(相对昨收,%):(最高-最低)/昨收*100。
|
||||
func (d *StockDaily) AmplitudePct() float64 {
|
||||
if d.PreClose <= 0 {
|
||||
return 0
|
||||
}
|
||||
return (d.High - d.Low) / d.PreClose * 100
|
||||
}
|
||||
226
schema/stock_fina_indicator.go
Normal file
226
schema/stock_fina_indicator.go
Normal file
@@ -0,0 +1,226 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// StockFinaIndicator 财务指标模型
|
||||
type StockFinaIndicator struct {
|
||||
gorm.Model
|
||||
TsCode string `gorm:"type:varchar(20);not null;index:fi_ts_code;uniqueIndex:un_fi_code_date;comment:TS代码"`
|
||||
Period int `gorm:"index:idx_period;uniqueIndex:un_fi_code_date;comment:报告期数"`
|
||||
AnnDate string `gorm:"index:idx_ann_date;comment:公告日期"`
|
||||
EndDate string `gorm:"index:idx_end_date;comment:报告期"`
|
||||
|
||||
// 每股指标
|
||||
Eps float64 `gorm:"type:decimal(20,4);comment:基本每股收益"`
|
||||
DtEps float64 `gorm:"type:decimal(20,4);comment:稀释每股收益"`
|
||||
TotalRevenuePs float64 `gorm:"type:decimal(20,4);comment:每股营业总收入"`
|
||||
RevenuePs float64 `gorm:"type:decimal(20,4);comment:每股营业收入"`
|
||||
CapitalResePs float64 `gorm:"type:decimal(20,4);comment:每股资本公积"`
|
||||
SurplusResePs float64 `gorm:"type:decimal(20,4);comment:每股盈余公积"`
|
||||
UndistProfitPs float64 `gorm:"type:decimal(20,4);comment:每股未分配利润"`
|
||||
Diluted2Eps float64 `gorm:"type:decimal(20,4);comment:期末摊薄每股收益"`
|
||||
Bps float64 `gorm:"type:decimal(20,4);comment:每股净资产"`
|
||||
Ocfps float64 `gorm:"type:decimal(20,4);comment:每股经营活动产生的现金流量净额"`
|
||||
Retainedps float64 `gorm:"type:decimal(20,4);comment:每股留存收益"`
|
||||
Cfps float64 `gorm:"type:decimal(20,4);comment:每股现金流量净额"`
|
||||
EbitPs float64 `gorm:"type:decimal(20,4);comment:每股息税前利润"`
|
||||
FcffPs float64 `gorm:"type:decimal(20,4);comment:每股企业自由现金流量"`
|
||||
FcfePs float64 `gorm:"type:decimal(20,4);comment:每股股东自由现金流量"`
|
||||
|
||||
// 利润表相关
|
||||
ExtraItem float64 `gorm:"type:decimal(20,4);comment:非经常性损益"`
|
||||
ProfitDedt float64 `gorm:"type:decimal(20,4);comment:扣除非经常性损益后的净利润"`
|
||||
GrossMargin float64 `gorm:"type:decimal(20,4);comment:毛利"`
|
||||
OpIncome float64 `gorm:"type:decimal(20,4);comment:经营活动净收益"`
|
||||
ValuechangeIncome float64 `gorm:"type:decimal(20,4);comment:价值变动净收益"`
|
||||
InterstIncome float64 `gorm:"type:decimal(20,4);comment:利息费用"`
|
||||
Daa float64 `gorm:"type:decimal(20,4);comment:折旧与摊销"`
|
||||
Ebit float64 `gorm:"type:decimal(20,4);comment:息税前利润"`
|
||||
Ebitda float64 `gorm:"type:decimal(20,4);comment:息税折旧摊销前利润"`
|
||||
Fcff float64 `gorm:"type:decimal(20,4);comment:企业自由现金流量"`
|
||||
Fcfe float64 `gorm:"type:decimal(20,4);comment:股权自由现金流量"`
|
||||
RdExp float64 `gorm:"type:decimal(20,4);comment:研发费用"`
|
||||
FixedAssets float64 `gorm:"type:decimal(20,4);comment:固定资产合计"`
|
||||
ProfitPrefinExp float64 `gorm:"type:decimal(20,4);comment:扣除财务费用前营业利润"`
|
||||
NonOpProfit float64 `gorm:"type:decimal(20,4);comment:非营业利润"`
|
||||
|
||||
// 资产负债表相关
|
||||
CurrentExint float64 `gorm:"type:decimal(20,4);comment:无息流动负债"`
|
||||
NoncurrentExint float64 `gorm:"type:decimal(20,4);comment:无息非流动负债"`
|
||||
Interestdebt float64 `gorm:"type:decimal(20,4);comment:带息债务"`
|
||||
Netdebt float64 `gorm:"type:decimal(20,4);comment:净债务"`
|
||||
TangibleAsset float64 `gorm:"type:decimal(20,4);comment:有形资产"`
|
||||
WorkingCapital float64 `gorm:"type:decimal(20,4);comment:营运资金"`
|
||||
NetworkingCapital float64 `gorm:"type:decimal(20,4);comment:营运流动资本"`
|
||||
InvestCapital float64 `gorm:"type:decimal(20,4);comment:全部投入资本"`
|
||||
RetainedEarnings float64 `gorm:"type:decimal(20,4);comment:留存收益"`
|
||||
|
||||
// 偿债能力指标
|
||||
CurrentRatio float64 `gorm:"type:decimal(20,4);comment:流动比率"`
|
||||
QuickRatio float64 `gorm:"type:decimal(20,4);comment:速动比率"`
|
||||
CashRatio float64 `gorm:"type:decimal(20,4);comment:保守速动比率"`
|
||||
DebtToAssets float64 `gorm:"type:decimal(20,4);comment:资产负债率"`
|
||||
AssetsToEqt float64 `gorm:"type:decimal(20,4);comment:权益乘数"`
|
||||
DpAssetsToEqt float64 `gorm:"type:decimal(20,4);comment:权益乘数(杜邦分析)"`
|
||||
DebtToEqt float64 `gorm:"type:decimal(20,4);comment:产权比率"`
|
||||
EqtToDebt float64 `gorm:"type:decimal(20,4);comment:归属于母公司的股东权益/负债合计"`
|
||||
OcfToShortdebt float64 `gorm:"type:decimal(20,4);comment:经营活动产生的现金流量净额/流动负债"`
|
||||
EbitToInterest float64 `gorm:"type:decimal(20,4);comment:已获利息倍数"`
|
||||
|
||||
// 运营能力指标
|
||||
InvturnDays float64 `gorm:"type:decimal(20,4);comment:存货周转天数"`
|
||||
ArturnDays float64 `gorm:"type:decimal(20,4);comment:应收账款周转天数"`
|
||||
InvTurn float64 `gorm:"type:decimal(20,4);comment:存货周转率"`
|
||||
ArTurn float64 `gorm:"type:decimal(20,4);comment:应收账款周转率"`
|
||||
CaTurn float64 `gorm:"type:decimal(20,4);comment:流动资产周转率"`
|
||||
FaTurn float64 `gorm:"type:decimal(20,4);comment:固定资产周转率"`
|
||||
AssetsTurn float64 `gorm:"type:decimal(20,4);comment:总资产周转率"`
|
||||
TurnDays float64 `gorm:"type:decimal(20,4);comment:营业周期"`
|
||||
TotalFaTrun float64 `gorm:"type:decimal(20,4);comment:固定资产合计周转率"`
|
||||
|
||||
// 盈利能力指标
|
||||
NetprofitMargin float64 `gorm:"type:decimal(20,4);comment:销售净利率"`
|
||||
GrossprofitMargin float64 `gorm:"type:decimal(20,4);comment:销售毛利率"`
|
||||
CogsOfSales float64 `gorm:"type:decimal(20,4);comment:销售成本率"`
|
||||
ExpenseOfSales float64 `gorm:"type:decimal(20,4);comment:销售期间费用率"`
|
||||
Roe float64 `gorm:"type:decimal(20,4);comment:净资产收益率"`
|
||||
RoeWaa float64 `gorm:"type:decimal(20,4);comment:加权平均净资产收益率"`
|
||||
RoeDt float64 `gorm:"type:decimal(20,4);comment:净资产收益率(扣除非经常损益)"`
|
||||
Roa float64 `gorm:"type:decimal(20,4);comment:总资产报酬率"`
|
||||
Npta float64 `gorm:"type:decimal(20,4);comment:总资产净利润"`
|
||||
Roic float64 `gorm:"type:decimal(20,4);comment:投入资本回报率"`
|
||||
RoaDp float64 `gorm:"type:decimal(20,4);comment:总资产净利率(杜邦分析)"`
|
||||
|
||||
// 结构指标
|
||||
CaToAssets float64 `gorm:"type:decimal(20,4);comment:流动资产/总资产"`
|
||||
NcaToAssets float64 `gorm:"type:decimal(20,4);comment:非流动资产/总资产"`
|
||||
TbassetsToTotalassets float64 `gorm:"type:decimal(20,4);comment:有形资产/总资产"`
|
||||
IntToTalcap float64 `gorm:"type:decimal(20,4);comment:带息债务/全部投入资本"`
|
||||
EqtToTalcapital float64 `gorm:"type:decimal(20,4);comment:归属于母公司的股东权益/全部投入资本"`
|
||||
CurrentdebtToDebt float64 `gorm:"type:decimal(20,4);comment:流动负债/负债合计"`
|
||||
LongdebToDebt float64 `gorm:"type:decimal(20,4);comment:非流动负债/负债合计"`
|
||||
TangibleassetToDebt float64 `gorm:"type:decimal(20,4);comment:有形资产/负债合计"`
|
||||
|
||||
// 单季度指标
|
||||
QOpincome float64 `gorm:"type:decimal(20,4);comment:经营活动单季度净收益"`
|
||||
QInvestincome float64 `gorm:"type:decimal(20,4);comment:价值变动单季度净收益"`
|
||||
QDtprofit float64 `gorm:"type:decimal(20,4);comment:扣除非经常损益后的单季度净利润"`
|
||||
QEps float64 `gorm:"type:decimal(20,4);comment:每股收益(单季度)"`
|
||||
QNetprofitMargin float64 `gorm:"type:decimal(20,4);comment:销售净利率(单季度)"`
|
||||
QGscaleprofitMargin float64 `gorm:"type:decimal(20,4);comment:销售毛利率(单季度)"`
|
||||
QExpToSales float64 `gorm:"type:decimal(20,4);comment:销售期间费用率(单季度)"`
|
||||
QRoe float64 `gorm:"type:decimal(20,4);comment:净资产收益率(单季度)"`
|
||||
QDtRoe float64 `gorm:"type:decimal(20,4);comment:净资产单季度收益率(扣除非经常损益)"`
|
||||
QNpta float64 `gorm:"type:decimal(20,4);comment:总资产净利润(单季度)"`
|
||||
|
||||
// 同比增长率
|
||||
BasicEpsYoy float64 `gorm:"type:decimal(20,4);comment:基本每股收益同比增长率(%)"`
|
||||
DtEpsYoy float64 `gorm:"type:decimal(20,4);comment:稀释每股收益同比增长率(%)"`
|
||||
CfpsYoy float64 `gorm:"type:decimal(20,4);comment:每股经营活动产生的现金流量净额同比增长率(%)"`
|
||||
OpYoy float64 `gorm:"type:decimal(20,4);comment:营业利润同比增长率(%)"`
|
||||
EbtYoy float64 `gorm:"type:decimal(20,4);comment:利润总额同比增长率(%)"`
|
||||
NetprofitYoy float64 `gorm:"type:decimal(20,4);comment:归属母公司股东的净利润同比增长率(%)"`
|
||||
DtNetprofitYoy float64 `gorm:"type:decimal(20,4);comment:归属母公司股东的净利润-扣除非经常损益同比增长率(%)"`
|
||||
OcfYoy float64 `gorm:"type:decimal(20,4);comment:经营活动产生的现金流量净额同比增长率(%)"`
|
||||
RoeYoy float64 `gorm:"type:decimal(20,4);comment:净资产收益率(摊薄)同比增长率(%)"`
|
||||
BpsYoy float64 `gorm:"type:decimal(20,4);comment:每股净资产相对年初增长率(%)"`
|
||||
AssetsYoy float64 `gorm:"type:decimal(20,4);comment:资产总计相对年初增长率(%)"`
|
||||
EqtYoy float64 `gorm:"type:decimal(20,4);comment:归属母公司的股东权益相对年初增长率(%)"`
|
||||
TrYoy float64 `gorm:"type:decimal(20,4);comment:营业总收入同比增长率(%)"`
|
||||
OrYoy float64 `gorm:"type:decimal(20,4);comment:营业收入同比增长率(%)"`
|
||||
EquityYoy float64 `gorm:"type:decimal(20,4);comment:净资产同比增长率"`
|
||||
|
||||
// 其他比率指标
|
||||
ProfitToGr float64 `gorm:"type:decimal(20,4);comment:净利润/营业总收入"`
|
||||
SaleexpToGr float64 `gorm:"type:decimal(20,4);comment:销售费用/营业总收入"`
|
||||
AdminexpOfGr float64 `gorm:"type:decimal(20,4);comment:管理费用/营业总收入"`
|
||||
FinaexpOfGr float64 `gorm:"type:decimal(20,4);comment:财务费用/营业总收入"`
|
||||
ImpaiTtm float64 `gorm:"type:decimal(20,4);comment:资产减值损失/营业总收入"`
|
||||
GcOfGr float64 `gorm:"type:decimal(20,4);comment:营业总成本/营业总收入"`
|
||||
OpOfGr float64 `gorm:"type:decimal(20,4);comment:营业利润/营业总收入"`
|
||||
EbitOfGr float64 `gorm:"type:decimal(20,4);comment:息税前利润/营业总收入"`
|
||||
OpincomeOfEbt float64 `gorm:"type:decimal(20,4);comment:经营活动净收益/利润总额"`
|
||||
InvestincomeOfEbt float64 `gorm:"type:decimal(20,4);comment:价值变动净收益/利润总额"`
|
||||
NOpProfitOfEbt float64 `gorm:"type:decimal(20,4);comment:营业外收支净额/利润总额"`
|
||||
TaxToEbt float64 `gorm:"type:decimal(20,4);comment:所得税/利润总额"`
|
||||
DtprofitToProfit float64 `gorm:"type:decimal(20,4);comment:扣除非经常损益后的净利润/净利润"`
|
||||
SalescashToOr float64 `gorm:"type:decimal(20,4);comment:销售商品提供劳务收到的现金/营业收入"`
|
||||
OcfToOr float64 `gorm:"type:decimal(20,4);comment:经营活动产生的现金流量净额/营业收入"`
|
||||
OcfToOpincome float64 `gorm:"type:decimal(20,4);comment:经营活动产生的现金流量净额/经营活动净收益"`
|
||||
CapitalizedToDa float64 `gorm:"type:decimal(20,4);comment:资本支出/折旧和摊销"`
|
||||
OcfToDebt float64 `gorm:"type:decimal(20,4);comment:经营活动产生的现金流量净额/负债合计"`
|
||||
OcfToInterestdebt float64 `gorm:"type:decimal(20,4);comment:经营活动产生的现金流量净额/带息债务"`
|
||||
OcfToNetdebt float64 `gorm:"type:decimal(20,4);comment:经营活动产生的现金流量净额/净债务"`
|
||||
LongdebtToWorkingcapital float64 `gorm:"type:decimal(20,4);comment:长期债务与营运资金比率"`
|
||||
EbitdaToDebt float64 `gorm:"type:decimal(20,4);comment:息税折旧摊销前利润/负债合计"`
|
||||
OpToEbt float64 `gorm:"type:decimal(20,4);comment:营业利润/利润总额"`
|
||||
NopToEbt float64 `gorm:"type:decimal(20,4);comment:非营业利润/利润总额"`
|
||||
OcfToProfit float64 `gorm:"type:decimal(20,4);comment:经营活动产生的现金流量净额/营业利润"`
|
||||
CashToLiqdebt float64 `gorm:"type:decimal(20,4);comment:货币资金/流动负债"`
|
||||
CashToLiqdebtWithinterest float64 `gorm:"type:decimal(20,4);comment:货币资金/带息流动负债"`
|
||||
OpToLiqdebt float64 `gorm:"type:decimal(20,4);comment:营业利润/流动负债"`
|
||||
OpToDebt float64 `gorm:"type:decimal(20,4);comment:营业利润/负债合计"`
|
||||
ProfitToOp float64 `gorm:"type:decimal(20,4);comment:利润总额/营业收入"`
|
||||
|
||||
// 年度化指标
|
||||
RoeYearly float64 `gorm:"type:decimal(20,4);comment:年化净资产收益率"`
|
||||
Roa2Yearly float64 `gorm:"type:decimal(20,4);comment:年化总资产报酬率"`
|
||||
RoaYearly float64 `gorm:"type:decimal(20,4);comment:年化总资产净利率"`
|
||||
RoicYearly float64 `gorm:"type:decimal(20,4);comment:年化投入资本回报率"`
|
||||
RoeAvg float64 `gorm:"type:decimal(20,4);comment:平均净资产收益率(增发条件)"`
|
||||
|
||||
// 单季度增长比率
|
||||
QGrYoy float64 `gorm:"type:decimal(20,4);comment:营业总收入同比增长率(%)(单季度)"`
|
||||
QGrQoq float64 `gorm:"type:decimal(20,4);comment:营业总收入环比增长率(%)(单季度)"`
|
||||
QSalesYoy float64 `gorm:"type:decimal(20,4);comment:营业收入同比增长率(%)(单季度)"`
|
||||
QSalesQoq float64 `gorm:"type:decimal(20,4);comment:营业收入环比增长率(%)(单季度)"`
|
||||
QOpYoy float64 `gorm:"type:decimal(20,4);comment:营业利润同比增长率(%)(单季度)"`
|
||||
QOpQoq float64 `gorm:"type:decimal(20,4);comment:营业利润环比增长率(%)(单季度)"`
|
||||
QProfitYoy float64 `gorm:"type:decimal(20,4);comment:净利润同比增长率(%)(单季度)"`
|
||||
QProfitQoq float64 `gorm:"type:decimal(20,4);comment:净利润环比增长率(%)(单季度)"`
|
||||
QNetprofitYoy float64 `gorm:"type:decimal(20,4);comment:归属母公司股东的净利润同比增长率(%)(单季度)"`
|
||||
QNetprofitQoq float64 `gorm:"type:decimal(20,4);comment:归属母公司股东的净利润环比增长率(%)(单季度)"`
|
||||
|
||||
// 单季度比率指标
|
||||
QProfitToGr float64 `gorm:"type:decimal(20,4);comment:净利润/营业总收入(单季度)"`
|
||||
QSaleexpToGr float64 `gorm:"type:decimal(20,4);comment:销售费用/营业总收入 (单季度)"`
|
||||
QAdminexpToGr float64 `gorm:"type:decimal(20,4);comment:管理费用/营业总收入 (单季度)"`
|
||||
QFinaexpToGr float64 `gorm:"type:decimal(20,4);comment:财务费用/营业总收入 (单季度)"`
|
||||
QImpairToGrTtm float64 `gorm:"type:decimal(20,4);comment:资产减值损失/营业总收入(单季度)"`
|
||||
QGcToGr float64 `gorm:"type:decimal(20,4);comment:营业总成本/营业总收入 (单季度)"`
|
||||
QOpToGr float64 `gorm:"type:decimal(20,4);comment:营业利润/营业总收入(单季度)"`
|
||||
QOpincomeToEbt float64 `gorm:"type:decimal(20,4);comment:经营活动净收益/利润总额(单季度)"`
|
||||
QInvestincomeToEbt float64 `gorm:"type:decimal(20,4);comment:价值变动净收益/利润总额(单季度)"`
|
||||
QDtprofitToProfit float64 `gorm:"type:decimal(20,4);comment:扣除非经常损益后的净利润/净利润(单季度)"`
|
||||
QSalescashToOr float64 `gorm:"type:decimal(20,4);comment:销售商品提供劳务收到的现金/营业收入(单季度)"`
|
||||
QOcfToSales float64 `gorm:"type:decimal(20,4);comment:经营活动产生的现金流量净额/营业收入(单季度)"`
|
||||
QOcfToOr float64 `gorm:"type:decimal(20,4);comment:经营活动产生的现金流量净额/经营活动净收益(单季度)"`
|
||||
|
||||
// 其他
|
||||
UpdateFlag string `gorm:"type:varchar(1);comment:更新标识"`
|
||||
}
|
||||
|
||||
// TableName 设置表名
|
||||
func (StockFinaIndicator) TableName() string {
|
||||
return "fina_indicator"
|
||||
}
|
||||
|
||||
// Key 与表 uniqueIndex un_fi_code_date 一致:ts_code + period。
|
||||
func (f *StockFinaIndicator) Key() string {
|
||||
if f.TsCode == "" && f.Period == 0 {
|
||||
return ""
|
||||
}
|
||||
return f.TsCode + "#" + strconv.Itoa(f.Period)
|
||||
}
|
||||
|
||||
// RowLabel 便于日志/调试:ts_code + 报告期 end_date + 公告 ann_date。
|
||||
func (f *StockFinaIndicator) RowLabel() string {
|
||||
if f.EndDate != "" || f.AnnDate != "" {
|
||||
return f.TsCode + " end=" + f.EndDate + " ann=" + f.AnnDate
|
||||
}
|
||||
return f.Key()
|
||||
}
|
||||
49
schema/stock_indicator.go
Normal file
49
schema/stock_indicator.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package schema
|
||||
|
||||
import "strconv"
|
||||
|
||||
// StockIndicator 每日基本面指标(采用 dataset/stock 的 decimal 定义,与采集端迁移一致)。
|
||||
type StockIndicator struct {
|
||||
ID uint `gorm:"primarykey;autoIncrement"`
|
||||
TsCode string `gorm:"type:varchar(20);not null;index:si_ts_code;uniqueIndex:un_si_code_date;comment:股票代码" json:"ts_code"`
|
||||
TradeDate int `gorm:"index:si_trade_date;uniqueIndex:un_si_code_date;comment:交易日期" json:"trade_date"`
|
||||
Close float64 `gorm:"type:decimal(20,4);comment:当日收盘价"`
|
||||
TurnoverRate float64 `gorm:"type:decimal(20,4);comment:换手率(%)"`
|
||||
TurnoverRateF float64 `gorm:"type:decimal(20,4);comment:换手率(自由流通股)"`
|
||||
VolumeRatio float64 `gorm:"type:decimal(20,4);comment:量比"`
|
||||
Pe float64 `gorm:"type:decimal(20,4);comment:市盈率(总市值/净利润)"`
|
||||
PeTtm float64 `gorm:"type:decimal(20,4);comment:市盈率(TTM)"`
|
||||
Pb float64 `gorm:"type:decimal(20,4);comment:市净率"`
|
||||
Ps float64 `gorm:"type:decimal(20,4);comment:市销率"`
|
||||
PsTtm float64 `gorm:"type:decimal(20,4);comment:市销率(TTM)"`
|
||||
DvRatio float64 `gorm:"type:decimal(20,4);comment:股息率(%)"`
|
||||
DvTtm float64 `gorm:"type:decimal(20,4);comment:股息率(TTM)(%)"`
|
||||
TotalShare float64 `gorm:"type:decimal(20,4);comment:总股本(万股)"`
|
||||
FloatShare float64 `gorm:"type:decimal(20,4);comment:流通股本(万股)"`
|
||||
FreeShare float64 `gorm:"type:decimal(20,4);comment:自由流通股本(万)"`
|
||||
TotalMv float64 `gorm:"type:decimal(20,4);comment:总市值(万元)"`
|
||||
CircMv float64 `gorm:"type:decimal(20,4);comment:流通市值(万元)"`
|
||||
Roe float64 `gorm:"type:decimal(20,4);comment:ROE(%) 净利润/股本"`
|
||||
}
|
||||
|
||||
func (StockIndicator) TableName() string {
|
||||
return "stock_indicator"
|
||||
}
|
||||
|
||||
// Key 业务主键:ts_code + 交易日。
|
||||
func (s *StockIndicator) Key() string {
|
||||
if s.TsCode == "" && s.TradeDate == 0 {
|
||||
return ""
|
||||
}
|
||||
return s.TsCode + "#" + strconv.Itoa(s.TradeDate)
|
||||
}
|
||||
|
||||
// HasTotalMV 总市值是否已填充(大于 0)。
|
||||
func (s *StockIndicator) HasTotalMV() bool {
|
||||
return s.TotalMv > 0
|
||||
}
|
||||
|
||||
// HasCircMV 流通市值是否已填充。
|
||||
func (s *StockIndicator) HasCircMV() bool {
|
||||
return s.CircMv > 0
|
||||
}
|
||||
141
tushare/board.go
Normal file
141
tushare/board.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package tushare
|
||||
|
||||
/*
|
||||
LimitCptList 获取限板板块列表
|
||||
|
||||
trade_date: 交易日,格式:YYYYMMDD
|
||||
ts_code: 板块代码
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) LimitCptList(trade_date, ts_code, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "limit_cpt_list",
|
||||
Params: params,
|
||||
}
|
||||
fields := []map[string]string{
|
||||
{"rank": "排名"},
|
||||
{"ts_code": "板块代码"},
|
||||
{"name": "板块名称"},
|
||||
{"pct_chg": "涨跌幅%"},
|
||||
{"up_stat": "连板高度"},
|
||||
{"days": "上榜天数"},
|
||||
{"up_nums": "涨停标的数"},
|
||||
{"cons_nums": "连板标的数"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
LimitListD 获取涨跌停列表(新)
|
||||
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
ts_code: 股票代码
|
||||
limit_type: 涨跌停类型,U 涨停 D 跌停 Z 炸板
|
||||
exchange: 交易所,SH 上交所 SZ 深交所 BJ 北交所
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) LimitListD(trade_date, ts_code, limit_type, exchange, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if limit_type != "" {
|
||||
params["limit_type"] = limit_type
|
||||
}
|
||||
if exchange != "" {
|
||||
params["exchange"] = exchange
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "limit_list_d",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"trade_date": "交易日期"},
|
||||
{"ts_code": "股票代码"},
|
||||
{"industry": "所属行业"},
|
||||
{"name": "股票名称"},
|
||||
{"close": "收盘价"},
|
||||
{"pct_chg": "涨跌幅%"},
|
||||
{"amount": "成交额"},
|
||||
{"limit_amount": "板上成交金额"},
|
||||
{"float_mv": "流通市值"},
|
||||
{"total_mv": "总市值"},
|
||||
{"turnover_ratio": "换手率%"},
|
||||
{"fd_amount": "封单金额"},
|
||||
{"first_time": "首次封板时间"},
|
||||
{"last_time": "最后封板时间"},
|
||||
{"open_times": "炸板次数"},
|
||||
{"up_stat": "涨停统计"},
|
||||
{"limit_times": "连板数"},
|
||||
{"limit": "涨跌停类型"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
LimitU 获取涨停股票列表
|
||||
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
ts_code: 股票代码
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) LimitU(trade_date, ts_code, start_date, end_date string) (*TushareRespData, error) {
|
||||
return cli.LimitListD(trade_date, ts_code, "U", "", start_date, end_date)
|
||||
}
|
||||
|
||||
/*
|
||||
LimitD 获取跌停股票列表
|
||||
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
ts_code: 股票代码
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) LimitD(trade_date, ts_code, start_date, end_date string) (*TushareRespData, error) {
|
||||
return cli.LimitListD(trade_date, ts_code, "D", "", start_date, end_date)
|
||||
}
|
||||
|
||||
/*
|
||||
LimitZ 获取炸板股票列表
|
||||
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
ts_code: 股票代码
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) LimitZ(trade_date, ts_code, start_date, end_date string) (*TushareRespData, error) {
|
||||
return cli.LimitListD(trade_date, ts_code, "Z", "", start_date, end_date)
|
||||
}
|
||||
|
||||
254
tushare/fina.go
Normal file
254
tushare/fina.go
Normal file
@@ -0,0 +1,254 @@
|
||||
package tushare
|
||||
|
||||
/*
|
||||
Income 获取利润表
|
||||
|
||||
ts_code: 股票代码,支持多个,逗号分隔
|
||||
ann_date: 公告日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
report_type: 报表类型,1:合并报表,2:母公司报表
|
||||
*/
|
||||
func (cli *TushareClient) Income(ts_code, ann_date, start_date, end_date, report_type string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if ann_date != "" {
|
||||
params["ann_date"] = ann_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
if report_type != "" {
|
||||
params["report_type"] = report_type
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "income",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "股票代码"},
|
||||
{"ann_date": "公告日期"},
|
||||
{"f_ann_date": "实际公告日期"},
|
||||
{"end_date": "报告期"},
|
||||
{"basic_eps": "基本每股收益"},
|
||||
{"diluted_eps": "稀释每股收益"},
|
||||
{"total_revenue": "营业总收入"},
|
||||
{"revenue": "营业收入"},
|
||||
{"total_profit": "利润总额"},
|
||||
{"net_profit": "净利润"},
|
||||
{"net_profit_attr_sh": "归属于母公司所有者的净利润"},
|
||||
{"operating_expense": "营业总成本"},
|
||||
{"operating_cost": "营业成本"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
Balancesheet 获取资产负债表
|
||||
|
||||
ts_code: 股票代码,支持多个,逗号分隔
|
||||
ann_date: 公告日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
report_type: 报表类型,1:合并报表,2:母公司报表
|
||||
*/
|
||||
func (cli *TushareClient) Balancesheet(ts_code, ann_date, start_date, end_date, report_type string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if ann_date != "" {
|
||||
params["ann_date"] = ann_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
if report_type != "" {
|
||||
params["report_type"] = report_type
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "balancesheet",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "股票代码"},
|
||||
{"ann_date": "公告日期"},
|
||||
{"f_ann_date": "实际公告日期"},
|
||||
{"end_date": "报告期"},
|
||||
{"total_assets": "资产总计"},
|
||||
{"total_liab": "负债合计"},
|
||||
{"total_hldr_eqy_exc_min_int": "股东权益合计"},
|
||||
{"total_hldr_eqy_inc_min_int": "股东权益合计 (含少数股东权益)"},
|
||||
{"total_share_capital": "股本"},
|
||||
{"cap_rsrv": "资本公积"},
|
||||
{"surplus_rsrv": "盈余公积"},
|
||||
{"undist_prft": "未分配利润"},
|
||||
{"monetary_cap": "货币资金"},
|
||||
{"total_current_assets": "流动资产合计"},
|
||||
{"total_non_current_assets": "非流动资产合计"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
Cashflow 获取现金流量表
|
||||
|
||||
ts_code: 股票代码,支持多个,逗号分隔
|
||||
ann_date: 公告日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
report_type: 报表类型,1:合并报表,2:母公司报表
|
||||
*/
|
||||
func (cli *TushareClient) Cashflow(ts_code, ann_date, start_date, end_date, report_type string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if ann_date != "" {
|
||||
params["ann_date"] = ann_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
if report_type != "" {
|
||||
params["report_type"] = report_type
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "cashflow",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "股票代码"},
|
||||
{"ann_date": "公告日期"},
|
||||
{"f_ann_date": "实际公告日期"},
|
||||
{"end_date": "报告期"},
|
||||
{"net_cash_invest_act": "投资活动产生的现金流量净额"},
|
||||
{"net_cash_financing_act": "筹资活动产生的现金流量净额"},
|
||||
{"net_cash_oper_act": "经营活动产生的现金流量净额"},
|
||||
{"cash_equivalents_end": "现金及现金等价物期末余额"},
|
||||
{"cash_equivalents_begin": "现金及现金等价物期初余额"},
|
||||
{"net_increase_cash": "现金及现金等价物净增加额"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
FinaIndicator 获取财务指标
|
||||
|
||||
ts_code: 股票代码,支持多个,逗号分隔
|
||||
ann_date: 公告日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) FinaIndicator(ts_code, ann_date, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if ann_date != "" {
|
||||
params["ann_date"] = ann_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "fina_indicator",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "股票代码"},
|
||||
{"ann_date": "公告日期"},
|
||||
{"end_date": "报告期"},
|
||||
{"eps_basic": "基本每股收益"},
|
||||
{"eps_diluted": "稀释每股收益"},
|
||||
{"roe": "净资产收益率%"},
|
||||
{"roe_wa": "净资产收益率 (加权)%"},
|
||||
{"roa": "总资产净利率%"},
|
||||
{"gross_margin": "销售毛利率%"},
|
||||
{"net_profit_margin": "销售净利率%"},
|
||||
{"current_ratio": "流动比率"},
|
||||
{"quick_ratio": "速动比率"},
|
||||
{"debt_to_assets": "资产负债率%"},
|
||||
{"turnover_days": "存货周转天数"},
|
||||
{"receivables_turnover": "应收账款周转率"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
Forecast 获取业绩预告
|
||||
|
||||
ts_code: 股票代码,支持多个,逗号分隔
|
||||
ann_date: 公告日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
type: 预告类型,预增/预减/扭亏/续盈/首亏/略增/略减
|
||||
*/
|
||||
func (cli *TushareClient) Forecast(ts_code, ann_date, start_date, end_date, forecast_type string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if ann_date != "" {
|
||||
params["ann_date"] = ann_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
if forecast_type != "" {
|
||||
params["type"] = forecast_type
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "forecast",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "股票代码"},
|
||||
{"ann_date": "公告日期"},
|
||||
{"end_date": "报告期"},
|
||||
{"type": "预告类型"},
|
||||
{"net_profit_min": "净利润下限 (万元)"},
|
||||
{"net_profit_max": "净利润上限 (万元)"},
|
||||
{"parent_netprofit_min": "归母净利润下限 (万元)"},
|
||||
{"parent_netprofit_max": "归母净利润上限 (万元)"},
|
||||
{"summary": "业绩预告摘要"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
206
tushare/finance.go
Normal file
206
tushare/finance.go
Normal file
@@ -0,0 +1,206 @@
|
||||
package tushare
|
||||
|
||||
/*
|
||||
DailyBasic 获取股票日线指标
|
||||
|
||||
ts_code: 股票代码,支持多个,逗号分隔
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) DailyBasic(ts_code, trade_date, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "daily_basic",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "股票代码"},
|
||||
{"trade_date": "交易日期"},
|
||||
{"close": "收盘价"},
|
||||
{"turnover_rate": "换手率%"},
|
||||
{"turnover_rate_f": "换手率% (自由流通股本)"},
|
||||
{"volume_ratio": "量比"},
|
||||
{"pe": "市盈率"},
|
||||
{"pe_ttm": "市盈率 TTM"},
|
||||
{"pb": "市净率"},
|
||||
{"ps": "市销率"},
|
||||
{"ps_ttm": "市销率 TTM"},
|
||||
{"dv_ratio": "股息率%"},
|
||||
{"total_mv": "总市值"},
|
||||
{"circ_mv": "流通市值"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
AdjFactor 获取复权因子
|
||||
|
||||
ts_code: 股票代码,支持多个,逗号分隔
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) AdjFactor(ts_code, trade_date, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "adj_factor",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "股票代码"},
|
||||
{"trade_date": "交易日期"},
|
||||
{"adj_factor": "复权因子"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
Moneyflow 获取个股资金流向
|
||||
|
||||
ts_code: 股票代码,支持多个,逗号分隔
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) Moneyflow(ts_code, trade_date, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "moneyflow",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "股票代码"},
|
||||
{"trade_date": "交易日期"},
|
||||
{"buy_sm_amount": "小单买入金额 (千元)"},
|
||||
{"sell_sm_amount": "小单卖出金额 (千元)"},
|
||||
{"buy_md_amount": "中单买入金额 (千元)"},
|
||||
{"sell_md_amount": "中单卖出金额 (千元)"},
|
||||
{"buy_lg_amount": "大单买入金额 (千元)"},
|
||||
{"sell_lg_amount": "大单卖出金额 (千元)"},
|
||||
{"buy_elg_amount": "特大单买入金额 (千元)"},
|
||||
{"sell_elg_amount": "特大单卖出金额 (千元)"},
|
||||
{"net_mf_amount": "净流入金额 (千元)"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
SuspendList 获取停牌股票列表
|
||||
|
||||
suspend_type: 停牌类型,1:盘中停牌,2:盘中临时停牌,3:全天停牌
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) SuspendList(suspend_type, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if suspend_type != "" {
|
||||
params["suspend_type"] = suspend_type
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "suspend_list",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "股票代码"},
|
||||
{"name": "股票名称"},
|
||||
{"suspend_type": "停牌类型"},
|
||||
{"suspend_start": "停牌起始日"},
|
||||
{"suspend_end": "停牌结束日"},
|
||||
{"reason": "停牌原因"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
RealtimeQuote 获取实时行情
|
||||
|
||||
ts_code: 股票代码,支持多个,逗号分隔
|
||||
*/
|
||||
func (cli *TushareClient) RealtimeQuote(ts_code string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "realtime_quote",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "股票代码"},
|
||||
{"price": "最新价"},
|
||||
{"open": "开盘价"},
|
||||
{"high": "最高价"},
|
||||
{"low": "最低价"},
|
||||
{"pre_close": "昨收价"},
|
||||
{"vol": "成交量 (手)"},
|
||||
{"amount": "成交额 (千元)"},
|
||||
{"buy_vol": "买总量 (手)"},
|
||||
{"sell_vol": "卖总量 (手)"},
|
||||
{"buy_amount": "买总额 (千元)"},
|
||||
{"sell_amount": "卖总额 (千元)"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
213
tushare/index.go
Normal file
213
tushare/index.go
Normal file
@@ -0,0 +1,213 @@
|
||||
package tushare
|
||||
|
||||
/*
|
||||
IndexBasic 获取大盘指数基本信息
|
||||
|
||||
ts_code: 指数代码,支持多个,逗号分隔
|
||||
exchange: 交易所代码,SSE 上交所,SZSE 深交所
|
||||
*/
|
||||
func (cli *TushareClient) IndexBasic(ts_code, exchange string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if exchange != "" {
|
||||
params["exchange"] = exchange
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "index_basic",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "指数代码"},
|
||||
{"name": "指数名称"},
|
||||
{"market": "市场类别"},
|
||||
{"publisher": "发布方"},
|
||||
{"category": "指数类别"},
|
||||
{"base_date": "基日"},
|
||||
{"base_point": "基点"},
|
||||
{"list_date": "发布日期"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
IndexWeight 获取指数成分和权重
|
||||
|
||||
index_code: 指数代码,如 000300.SH(沪深 300)
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) IndexWeight(index_code, trade_date, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if index_code != "" {
|
||||
params["index_code"] = index_code
|
||||
}
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "index_weight",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"index_code": "指数代码"},
|
||||
{"trade_date": "交易日期"},
|
||||
{"ts_code": "成分股票代码"},
|
||||
{"weight": "权重%"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
IndexClassify 获取指数分类信息
|
||||
|
||||
level: 指数级别,L1/L2/L3/L4
|
||||
src: 指数来源,SW 申万,ZJW 证监会,ICS iFinD
|
||||
parent_code: 父级代码
|
||||
*/
|
||||
func (cli *TushareClient) IndexClassify(level, src, parent_code string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if level != "" {
|
||||
params["level"] = level
|
||||
}
|
||||
if src != "" {
|
||||
params["src"] = src
|
||||
}
|
||||
if parent_code != "" {
|
||||
params["parent_code"] = parent_code
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "index_classify",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"index_code": "指数代码"},
|
||||
{"industry_name": "行业名称"},
|
||||
{"industry_code": "行业代码"},
|
||||
{"parent_code": "父级代码"},
|
||||
{"level": "级别"},
|
||||
{"src": "来源"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
IndexMember 获取指数成分股
|
||||
|
||||
index_code: 指数代码,如 000300.SH(沪深 300)
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) IndexMember(index_code, trade_date, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if index_code != "" {
|
||||
params["index_code"] = index_code
|
||||
}
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "index_member",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"index_code": "指数代码"},
|
||||
{"trade_date": "交易日期"},
|
||||
{"ts_code": "成分股票代码"},
|
||||
{"symbol": "成分股票代码"},
|
||||
{"name": "成分股票名称"},
|
||||
{"is_new": "是否新增"},
|
||||
{"in_date": "纳入日期"},
|
||||
{"out_date": "剔除日期"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
Concept 获取概念板块信息
|
||||
|
||||
ts_code: 板块代码,支持多个,逗号分隔
|
||||
name: 板块名称,支持模糊匹配
|
||||
*/
|
||||
func (cli *TushareClient) Concept(ts_code, name string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if name != "" {
|
||||
params["name"] = name
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "concept",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "板块代码"},
|
||||
{"name": "板块名称"},
|
||||
{"src": "来源"},
|
||||
{"pub_date": "发布日期"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
ConceptDetail 获取概念板块详情
|
||||
|
||||
ts_code: 板块代码
|
||||
*/
|
||||
func (cli *TushareClient) ConceptDetail(ts_code string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "concept_detail",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "板块代码"},
|
||||
{"name": "板块名称"},
|
||||
{"concept_name": "概念名称"},
|
||||
{"stock_count": "成分股票数量"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
24
tushare/indicator.go
Normal file
24
tushare/indicator.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package tushare
|
||||
|
||||
func (cli *TushareClient) StkFactorPro(ts_code string, tradeDate string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if tradeDate != "" {
|
||||
params["trade_date"] = tradeDate
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "stk_factor_pro",
|
||||
Params: params,
|
||||
}
|
||||
fields := []map[string]string{
|
||||
{"trade_date": "trade_date"},
|
||||
{"rsi_bfq_24": "rsi_bfq_24"},
|
||||
{"rsi_hfq_24": "rsi_hfq_24"},
|
||||
{"rsi_qfq_24": "rsi_qfq_24"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
209
tushare/margin.go
Normal file
209
tushare/margin.go
Normal file
@@ -0,0 +1,209 @@
|
||||
package tushare
|
||||
|
||||
/*
|
||||
HkHold 获取沪深股通持股明细
|
||||
|
||||
ts_code: 股票代码
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) HkHold(ts_code, trade_date, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "hk_hold",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "股票代码"},
|
||||
{"trade_date": "交易日期"},
|
||||
{"holding_sh": "沪股通持股数量 (股)"},
|
||||
{"holding_sz": "深股通持股数量 (股)"},
|
||||
{"holding_total": "沪深股通持股总量 (股)"},
|
||||
{"ratio_sh": "沪股通持股比例%"},
|
||||
{"ratio_sz": "深股通持股比例%"},
|
||||
{"ratio_total": "沪深股通持股比例合计%"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
MarginDetail 获取融资融券明细
|
||||
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
exchange: 交易所代码,SSE 上交所,SZSE 深交所
|
||||
*/
|
||||
func (cli *TushareClient) MarginDetail(trade_date, start_date, end_date, exchange string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
if exchange != "" {
|
||||
params["exchange"] = exchange
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "margin_detail",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"trade_date": "交易日期"},
|
||||
{"ts_code": "股票代码"},
|
||||
{"buy_value": "融资买入额 (元)"},
|
||||
{"buy_repay_value": "融资偿还额 (元)"},
|
||||
{"buy_bal": "融资余额 (元)"},
|
||||
{"sell_value": "融券卖出量 (股)"},
|
||||
{"sell_repay_value": "融券偿还量 (股)"},
|
||||
{"sell_bal": "融券余量 (股)"},
|
||||
{"sell_amount": "融券余量金额 (元)"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
TopList 获取龙虎榜数据
|
||||
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) TopList(trade_date, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "top_list",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"trade_date": "交易日期"},
|
||||
{"ts_code": "股票代码"},
|
||||
{"name": "股票名称"},
|
||||
{"close": "收盘价"},
|
||||
{"pct_chg": "涨跌幅%"},
|
||||
{"turnover_rate": "换手率%"},
|
||||
{"total_value": "成交总额 (万元)"},
|
||||
{"net_value": "净额 (万元)"},
|
||||
{"buy_value": "买入总额 (万元)"},
|
||||
{"sell_value": "卖出总额 (万元)"},
|
||||
{"reason": "上榜原因"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
TopInst 获取龙虎榜机构席位数据
|
||||
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) TopInst(trade_date, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "top_inst",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"trade_date": "交易日期"},
|
||||
{"ts_code": "股票代码"},
|
||||
{"name": "股票名称"},
|
||||
{"buy_value": "机构买入总额 (万元)"},
|
||||
{"buy_count": "机构买入次数"},
|
||||
{"sell_value": "机构卖出总额 (万元)"},
|
||||
{"sell_count": "机构卖出次数"},
|
||||
{"net_value": "机构净买入额 (万元)"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
BlockTrade 获取大宗交易数据
|
||||
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) BlockTrade(trade_date, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "block_trade",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"trade_date": "交易日期"},
|
||||
{"ts_code": "股票代码"},
|
||||
{"name": "证券简称"},
|
||||
{"price": "成交价"},
|
||||
{"vol": "成交量 (万股)"},
|
||||
{"amount": "成交额 (万元)"},
|
||||
{"buyer": "买方营业部"},
|
||||
{"seller": "卖方营业部"},
|
||||
{"premium_rate": "溢价率%"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
168
tushare/new.go
Normal file
168
tushare/new.go
Normal file
@@ -0,0 +1,168 @@
|
||||
package tushare
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
)
|
||||
|
||||
// TushareClient Tushare API 客户端
|
||||
type TushareClient struct {
|
||||
Token string `json:"token"` // API 访问令牌
|
||||
BaseUrl string `json:"base_url"` // API 基础 URL
|
||||
}
|
||||
|
||||
// TushareReq Tushare API 请求结构
|
||||
type TushareReq struct {
|
||||
APIName string `json:"api_name"` // API 接口名称
|
||||
Token string `json:"token"` // API 访问令牌
|
||||
Params map[string]any `json:"params"` // 请求参数
|
||||
Fields []string `json:"fields"` // 返回字段列表
|
||||
}
|
||||
|
||||
// TushareResp Tushare API 响应结构
|
||||
type TushareResp struct {
|
||||
RequestID string `json:"request_id"` // 请求 ID
|
||||
Code int `json:"code"` // 响应码 (0 表示成功)
|
||||
Data *TushareRespData `json:"data"` // 响应数据
|
||||
Msg string `json:"msg"` // 响应消息
|
||||
}
|
||||
|
||||
// TushareRespData Tushare API 响应数据结构
|
||||
type TushareRespData struct {
|
||||
Fields []string `json:"fields"` // 字段列表
|
||||
Headers []string `json:"headers"` // 表头(中文描述)
|
||||
Items [][]any `json:"items"` // 数据项(二维数组)
|
||||
HasMore bool `json:"has_more"` // 是否有更多数据
|
||||
Count int `json:"count"` // 返回数据条数
|
||||
}
|
||||
|
||||
// NewClient 创建并初始化 Tushare 客户端
|
||||
// 返回配置好 Token 和基础 URL 的客户端实例
|
||||
func NewClient(token string) *TushareClient {
|
||||
if token == "" {
|
||||
token = os.Getenv("TUSHARE_TOKEN")
|
||||
}
|
||||
return &TushareClient{
|
||||
Token: token,
|
||||
BaseUrl: "http://api.tushare.pro",
|
||||
}
|
||||
}
|
||||
|
||||
// Do 执行 Tushare API 请求
|
||||
// req: 请求参数,包含 API 名称、参数等
|
||||
// fieldsVals: 字段配置列表,每个元素是一个 map,key 为字段名,value 为字段中文描述
|
||||
// 返回:响应数据和错误信息
|
||||
func (c *TushareClient) Do(req TushareReq, fieldsVals []map[string]string) (*TushareRespData, error) {
|
||||
// 构建请求体
|
||||
payload := TushareReq{
|
||||
APIName: req.APIName,
|
||||
Token: c.Token,
|
||||
Params: req.Params,
|
||||
}
|
||||
|
||||
// 提取字段名和对应的中文表头
|
||||
var fields []string
|
||||
var headers []string
|
||||
for _, setting := range fieldsVals {
|
||||
for key, value := range setting {
|
||||
fields = append(fields, key)
|
||||
headers = append(headers, value)
|
||||
}
|
||||
}
|
||||
payload.Fields = fields
|
||||
|
||||
// 序列化请求体为 JSON
|
||||
reqBytes, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("#100 请求序列化失败:%w", err)
|
||||
}
|
||||
|
||||
// 创建 HTTP 请求
|
||||
client := &http.Client{
|
||||
Timeout: 30 * time.Second, // 设置 30 秒超时
|
||||
}
|
||||
resp, err := client.Post(c.BaseUrl, "application/json", bytes.NewReader(reqBytes))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("#100 发送请求失败:%w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("#101 读取响应失败:%w", err)
|
||||
}
|
||||
|
||||
// 解析响应 JSON
|
||||
var tushareResp TushareResp
|
||||
if err := json.Unmarshal(body, &tushareResp); err != nil {
|
||||
return nil, fmt.Errorf("#101 响应解析失败:%v - %s", err, string(body))
|
||||
}
|
||||
|
||||
// 检查响应码
|
||||
if tushareResp.Code != 0 {
|
||||
return nil, fmt.Errorf("#102 API 返回错误:%s", tushareResp.Msg)
|
||||
}
|
||||
|
||||
// 设置表头信息
|
||||
if tushareResp.Data != nil {
|
||||
tushareResp.Data.Headers = headers
|
||||
}
|
||||
return tushareResp.Data, nil
|
||||
}
|
||||
|
||||
// Map 将响应数据转换为 map 切片
|
||||
// 每个 map 代表一行数据,key 为字段名,value 为对应的值
|
||||
func (c *TushareRespData) Map() []map[string]any {
|
||||
result := make([]map[string]any, 0)
|
||||
if c == nil || len(c.Items) == 0 || len(c.Fields) == 0 {
|
||||
return result
|
||||
}
|
||||
|
||||
for _, item := range c.Items {
|
||||
rowMap := make(map[string]any, len(c.Fields))
|
||||
for idx, fn := range c.Fields {
|
||||
if idx < len(item) {
|
||||
rowMap[fn] = item[idx]
|
||||
}
|
||||
}
|
||||
result = append(result, rowMap)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Json 将响应数据转换为 JSON 字节数组
|
||||
// 返回:JSON 格式的字节数据和错误信息
|
||||
func (c *TushareRespData) Json() ([]byte, error) {
|
||||
data := c.Map()
|
||||
return json.MarshalIndent(data, "", " ")
|
||||
}
|
||||
|
||||
// Output 将响应数据格式化为表格输出
|
||||
// title: 表格标题
|
||||
// 返回:格式化的表格写入器
|
||||
func (c *TushareRespData) Output(title string) table.Writer {
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(table.StyleLight)
|
||||
tw.SetTitle(title)
|
||||
|
||||
// 构建表头行
|
||||
headerRow := make(table.Row, 0, len(c.Headers))
|
||||
for idx, header := range c.Headers {
|
||||
headerRow = append(headerRow, header+"("+c.Fields[idx]+")")
|
||||
}
|
||||
tw.AppendHeader(headerRow)
|
||||
|
||||
// 添加数据行
|
||||
for _, item := range c.Items {
|
||||
tw.AppendRow(item)
|
||||
}
|
||||
return tw
|
||||
}
|
||||
241
tushare/stock.go
Normal file
241
tushare/stock.go
Normal file
@@ -0,0 +1,241 @@
|
||||
package tushare
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
TradeCal 获取交易日历
|
||||
|
||||
exchange: 交易所代码,SSE 上交所,SZSE 深交所,BSE 北交所,空字符串代表所有
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
is_open: 是否开盘,'0'休市,'1'交易,空字符串代表所有
|
||||
*/
|
||||
func (cli *TushareClient) TradeCal(exchange, start_date, end_date, is_open string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if exchange != "" {
|
||||
params["exchange"] = exchange
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
if is_open != "" {
|
||||
params["is_open"] = is_open
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "trade_cal",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"exchange": "交易所代码"},
|
||||
{"cal_date": "日历日期"},
|
||||
{"is_open": "是否开盘"},
|
||||
{"pretrade_date": "上一交易日"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
func (cli *TushareClient) ReturnLastTradeDay() string {
|
||||
result, err := cli.TradeCal("SSE", time.Now().AddDate(0, 0, -15).Format("20060102"), time.Now().Format("20060102"), "1")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
cal := result.Map()
|
||||
return cal[0]["cal_date"].(string)
|
||||
}
|
||||
|
||||
/*
|
||||
StockBasic 获取股票列表
|
||||
|
||||
ts_code: 股票代码,支持多个,如"000002.SZ,000001.SZ"
|
||||
exchange: 交易所代码,SSE 上交所,SZSE 深交所
|
||||
is_shsc: 是否在沪股通或深港通范围内,0:否;1:沪股通;2:深股通
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) StockBasic(ts_code, exchange, is_shsc, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if exchange != "" {
|
||||
params["exchange"] = exchange
|
||||
}
|
||||
if is_shsc != "" {
|
||||
params["is_shsc"] = is_shsc
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "stock_basic",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "TS 代码"},
|
||||
{"symbol": "股票交易代码"},
|
||||
{"name": "证券简称"},
|
||||
{"area": "地区"},
|
||||
{"industry": "所属行业"},
|
||||
{"market": "市场类别"},
|
||||
{"list_status": "上市状态"},
|
||||
{"list_date": "上市日期"},
|
||||
{"delist_date": "退市日期"},
|
||||
{"is_shsc": "是否沪股通或深股通"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
Daily 获取日线行情
|
||||
|
||||
ts_code: 股票代码,格式:000001.SZ 或 600000.SH
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) Daily(ts_code, trade_date, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "daily",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "股票代码"},
|
||||
{"trade_date": "交易日期"},
|
||||
{"open": "开盘价"},
|
||||
{"high": "最高价"},
|
||||
{"low": "最低价"},
|
||||
{"close": "收盘价"},
|
||||
{"pre_close": "昨收价"},
|
||||
{"change": "涨跌额"},
|
||||
{"pct_chg": "涨跌幅%"},
|
||||
{"vol": "成交量 (手)"},
|
||||
{"amount": "成交额 (千元)"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
Min 获取分钟线行情
|
||||
|
||||
ts_code: 股票代码,格式:000001.SZ 或 600000.SH
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
minute: 分钟类型,1/5/15/30/60 分钟
|
||||
start_time: 开始时间,格式:HHmmss
|
||||
end_time: 结束时间,格式:HHmmss
|
||||
*/
|
||||
func (cli *TushareClient) Min(ts_code, trade_date, minute, start_time, end_time string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
if minute != "" {
|
||||
params["minute"] = minute
|
||||
}
|
||||
if start_time != "" {
|
||||
params["start_time"] = start_time
|
||||
}
|
||||
if end_time != "" {
|
||||
params["end_time"] = end_time
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "min",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "股票代码"},
|
||||
{"trade_time": "交易时间"},
|
||||
{"open": "开盘价"},
|
||||
{"high": "最高价"},
|
||||
{"low": "最低价"},
|
||||
{"close": "收盘价"},
|
||||
{"vol": "成交量 (手)"},
|
||||
{"amount": "成交额 (千元)"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
IndexDaily 获取大盘指数日线行情
|
||||
|
||||
ts_code: 指数代码,如 000001.SH(上证指数),399001.SZ(深证成指)
|
||||
trade_date: 交易日期,格式:YYYYMMDD
|
||||
start_date: 开始日期,格式:YYYYMMDD
|
||||
end_date: 结束日期,格式:YYYYMMDD
|
||||
*/
|
||||
func (cli *TushareClient) IndexDaily(ts_code, trade_date, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "index_daily",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "指数代码"},
|
||||
{"trade_date": "交易日期"},
|
||||
{"close": "收盘点位"},
|
||||
{"open": "开盘点位"},
|
||||
{"high": "最高点位"},
|
||||
{"low": "最低点位"},
|
||||
{"pre_close": "昨收点位"},
|
||||
{"change": "涨跌额"},
|
||||
{"pct_chg": "涨跌幅%"},
|
||||
{"vol": "成交量 (手)"},
|
||||
{"amount": "成交额 (千元)"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
213
tushare/ths.go
Normal file
213
tushare/ths.go
Normal file
@@ -0,0 +1,213 @@
|
||||
package tushare
|
||||
|
||||
/*
|
||||
ThsHot 同花顺热榜
|
||||
|
||||
trade_date str N 交易日期
|
||||
ts_code str N TS代码
|
||||
market str N 热榜类型(热股、ETF、可转债、行业板块、概念板块、期货、港股、热基、美股)
|
||||
is_new str N 是否最新(默认Y,如果为N则为盘中和盘后阶段采集,具体时间可参考rank_time字段,状态N每小时更新一次,状态Y更新时间为22:30)
|
||||
*/
|
||||
func (cli *TushareClient) ThsHot(trade_date, ts_code, market, is_new string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if market != "" {
|
||||
params["market"] = market
|
||||
}
|
||||
if is_new != "" {
|
||||
params["is_new"] = is_new
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "ths_hot",
|
||||
Params: params,
|
||||
}
|
||||
/*
|
||||
trade_date str Y 交易日期
|
||||
data_type str Y 数据类型
|
||||
ts_code str Y 股票代码
|
||||
ts_name str Y 股票名称
|
||||
rank int Y 排行
|
||||
pct_change float Y 涨跌幅%
|
||||
current_price float Y 当前价格
|
||||
concept str Y 标签
|
||||
rank_reason str Y 上榜解读
|
||||
hot float Y 热度值
|
||||
rank_time str Y 排行榜获取时间
|
||||
*/
|
||||
fields := []map[string]string{
|
||||
{"trade_date": "交易日期"},
|
||||
{"data_type": "数据类型"},
|
||||
{"ts_code": "TS代码"},
|
||||
{"ts_name": "股票名称"},
|
||||
{"rank": "排行"},
|
||||
{"pct_change": "涨跌幅%"},
|
||||
{"current_price": "当前价格"},
|
||||
{"concept": "标签"},
|
||||
{"rank_reason": "上榜解读"},
|
||||
{"hot": "热度值"},
|
||||
{"rank_time": "排行榜获取时间"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
ThsIndex 同花顺概念和行业指数
|
||||
|
||||
接口说明:
|
||||
- 描述:获取同花顺板块指数,包括概念、行业、特色指数
|
||||
- 权限:本接口需有6000积分,单次最大返回5000行数据,一次可提取全部数据,请勿循环提取
|
||||
- 注意事项:数据版权归属同花顺,如做商业用途,请主动联系同花顺
|
||||
|
||||
输入参数:
|
||||
- ts_code: 指数代码(可选)
|
||||
- exchange: 市场类型,A-a股 HK-港股 US-美股(可选)
|
||||
- type: 指数类型,N-概念指数 I-行业指数 R-地域指数 S-同花顺特色指数 ST-同花顺风格指数 TH-同花顺主题指数 BB-同花顺宽基指数(可选)
|
||||
|
||||
输出参数:
|
||||
- ts_code: 代码
|
||||
- name: 名称
|
||||
- count: 成分个数
|
||||
- exchange: 交易所
|
||||
- list_date: 上市日期
|
||||
- type: N概念指数S特色指数
|
||||
*/
|
||||
func (cli *TushareClient) ThsIndex(ts_code, exchange, typ string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if exchange != "" {
|
||||
params["exchange"] = exchange
|
||||
}
|
||||
if typ != "" {
|
||||
params["type"] = typ
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "ths_index",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "代码"},
|
||||
{"name": "名称"},
|
||||
{"count": "成分个数"},
|
||||
{"exchange": "交易所"},
|
||||
{"list_date": "上市日期"},
|
||||
{"type": "类型"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
ThsDaily 同花顺板块指数行情
|
||||
|
||||
接口说明:
|
||||
- 描述:获取同花顺板块指数行情
|
||||
- 限量:单次最大3000行数据(需6000积分),可根据指数代码、日期参数循环提取
|
||||
- 注意事项:数据版权归属同花顺,如做商业用途,请主动联系同花顺
|
||||
|
||||
输入参数:
|
||||
- ts_code: 指数代码(可选)
|
||||
- trade_date: 交易日期(YYYYMMDD格式)(可选)
|
||||
- start_date: 开始日期(YYYYMMDD格式)(可选)
|
||||
- end_date: 结束日期(YYYYMMDD格式)(可选)
|
||||
|
||||
输出参数:
|
||||
- ts_code: TS指数代码
|
||||
- trade_date: 交易日
|
||||
- close: 收盘点位
|
||||
- open: 开盘点位
|
||||
- high: 最高点位
|
||||
- low: 最低点位
|
||||
- pre_close: 昨日收盘点
|
||||
- avg_price: 平均价
|
||||
- change: 涨跌点位
|
||||
- pct_change: 涨跌幅
|
||||
- vol: 成交量(手)
|
||||
- turnover_rate: 换手率(%)
|
||||
- total_mv: 总市值(元)
|
||||
- float_mv: 流通市值(元)
|
||||
*/
|
||||
func (cli *TushareClient) ThsDaily(ts_code, trade_date, start_date, end_date string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if trade_date != "" {
|
||||
params["trade_date"] = trade_date
|
||||
}
|
||||
if start_date != "" {
|
||||
params["start_date"] = start_date
|
||||
}
|
||||
if end_date != "" {
|
||||
params["end_date"] = end_date
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "ths_daily",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "TS指数代码"},
|
||||
{"trade_date": "交易日"},
|
||||
{"close": "收盘点位"},
|
||||
{"open": "开盘点位"},
|
||||
{"high": "最高点位"},
|
||||
{"low": "最低点位"},
|
||||
{"pre_close": "昨日收盘点"},
|
||||
{"avg_price": "平均价"},
|
||||
{"change": "涨跌点位"},
|
||||
{"pct_change": "涨跌幅"},
|
||||
{"vol": "成交量(手)"},
|
||||
{"turnover_rate": "换手率(%)"},
|
||||
{"total_mv": "总市值(元)"},
|
||||
{"float_mv": "流通市值(元)"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
|
||||
/*
|
||||
ThsMember 获取同花顺概念板块成分
|
||||
|
||||
ts_code: 板块指数代码
|
||||
con_code: 股票代码
|
||||
*/
|
||||
func (cli *TushareClient) ThsMember(ts_code, con_code string) (*TushareRespData, error) {
|
||||
params := map[string]any{}
|
||||
|
||||
if ts_code != "" {
|
||||
params["ts_code"] = ts_code
|
||||
}
|
||||
if con_code != "" {
|
||||
params["con_code"] = con_code
|
||||
}
|
||||
|
||||
req := TushareReq{
|
||||
APIName: "ths_member",
|
||||
Params: params,
|
||||
}
|
||||
|
||||
fields := []map[string]string{
|
||||
{"ts_code": "指数代码"},
|
||||
{"con_code": "股票代码"},
|
||||
{"con_name": "股票名称"},
|
||||
{"weight": "权重"},
|
||||
{"in_date": "纳入日期"},
|
||||
{"out_date": "剔除日期"},
|
||||
{"is_new": "是否最新"},
|
||||
}
|
||||
|
||||
return cli.Do(req, fields)
|
||||
}
|
||||
Reference in New Issue
Block a user