feat(data): 添加指数信息获取功能

- 在 StockDataApi 中新增 GetIndexBasic 方法,用于获取指数信息
- 在数据库中添加 index_basic 表并进行自动迁移- 优化 GetStockBaseInfo 方法,使用 map 结构处理字段- 增加 GetIndexBasic 的单元测试
This commit is contained in:
spark 2025-01-02 17:52:25 +08:00
parent 15120c98da
commit f35847823b
3 changed files with 93 additions and 19 deletions

View File

@ -9,6 +9,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/duke-git/lancet/v2/convertor" "github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/slice"
"github.com/duke-git/lancet/v2/strutil" "github.com/duke-git/lancet/v2/strutil"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
"go-stock/backend/db" "go-stock/backend/db"
@ -162,15 +163,63 @@ func NewStockDataApi() *StockDataApi {
client: resty.New(), client: resty.New(),
} }
} }
// GetIndexBasic 获取指数信息
func (receiver StockDataApi) GetIndexBasic() {
res := &TushareStockBasicResponse{}
fields := "ts_code,name,market,publisher,category,base_date,base_point,list_date,fullname,index_type,weight_rule,desc"
resp, err := receiver.client.R().
SetHeader("content-type", "application/json").
SetBody(&TushareRequest{
ApiName: "index_basic",
Token: TushareToken,
Params: nil,
Fields: fields}).
SetResult(res).
Post(tushare_api_url)
if err != nil {
logger.SugaredLogger.Error(err.Error())
return
}
if res.Code != 0 {
logger.SugaredLogger.Error(res.Msg)
return
}
ioutil.WriteFile("index_basic.json", resp.Body(), 0666)
for _, item := range res.Data.Items {
data := map[string]any{}
for _, field := range strings.Split(fields, ",") {
logger.SugaredLogger.Infof("field: %s", field)
idx := slice.IndexOf(res.Data.Fields, field)
if idx == -1 {
continue
}
data[field] = item[idx]
}
index := &IndexBasic{}
jsonData, _ := json.Marshal(data)
err := json.Unmarshal(jsonData, index)
if err != nil {
continue
}
db.Dao.Model(&IndexBasic{}).FirstOrCreate(index, &IndexBasic{TsCode: index.TsCode}).Updates(index)
}
}
// map转换为结构体
func (receiver StockDataApi) GetStockBaseInfo() { func (receiver StockDataApi) GetStockBaseInfo() {
res := &TushareStockBasicResponse{} res := &TushareStockBasicResponse{}
fields := "ts_code,symbol,name,area,industry,cnspell,market,list_date,act_name,act_ent_type,fullname,exchange,list_status,curr_type,enname,delist_date,is_hs"
resp, err := receiver.client.R(). resp, err := receiver.client.R().
SetHeader("content-type", "application/json"). SetHeader("content-type", "application/json").
SetBody(&TushareRequest{ SetBody(&TushareRequest{
ApiName: "stock_basic", ApiName: "stock_basic",
Token: TushareToken, Token: TushareToken,
Params: nil, Params: nil,
Fields: "*", Fields: fields,
}). }).
SetResult(res). SetResult(res).
Post(tushare_api_url) Post(tushare_api_url)
@ -187,25 +236,21 @@ func (receiver StockDataApi) GetStockBaseInfo() {
return return
} }
for _, item := range res.Data.Items { for _, item := range res.Data.Items {
ID, _ := convertor.ToInt(item[6])
stock := &StockBasic{} stock := &StockBasic{}
stock.Exchange = convertor.ToString(item[0]) data := map[string]any{}
stock.IsHs = convertor.ToString(item[1]) for _, field := range strings.Split(fields, ",") {
stock.Name = convertor.ToString(item[2]) logger.SugaredLogger.Infof("field: %s", field)
stock.Industry = convertor.ToString(item[3]) idx := slice.IndexOf(res.Data.Fields, field)
stock.ListStatus = convertor.ToString(item[4]) if idx == -1 {
stock.ActName = convertor.ToString(item[5]) continue
stock.ID = uint(ID) }
stock.CurrType = convertor.ToString(item[7]) data[field] = item[idx]
stock.Area = convertor.ToString(item[8]) }
stock.ListDate = convertor.ToString(item[9]) jsonData, _ := json.Marshal(data)
stock.DelistDate = convertor.ToString(item[10]) err := json.Unmarshal(jsonData, stock)
stock.ActEntType = convertor.ToString(item[11]) if err != nil {
stock.TsCode = convertor.ToString(item[12]) continue
stock.Symbol = convertor.ToString(item[13]) }
stock.Cnspell = convertor.ToString(item[14])
stock.Fullname = convertor.ToString(item[20])
stock.Ename = convertor.ToString(item[21])
db.Dao.Model(&StockBasic{}).FirstOrCreate(stock, &StockBasic{TsCode: stock.TsCode}).Updates(stock) db.Dao.Model(&StockBasic{}).FirstOrCreate(stock, &StockBasic{TsCode: stock.TsCode}).Updates(stock)
} }
@ -372,3 +417,24 @@ func ParseFullSingleStockData(data string) (*StockInfo, error) {
return stockInfo, nil return stockInfo, nil
} }
type IndexBasic struct {
gorm.Model
TsCode string `json:"ts_code" gorm:"index"`
Symbol string `json:"symbol" gorm:"index"`
Name string `json:"name" gorm:"index"`
FullName string `json:"fullname"`
IndexType string `json:"index_type"`
IndexCategory string `json:"category"`
Market string `json:"market"`
ListDate string `json:"list_date"`
BaseDate string `json:"base_date"`
BasePoint float64 `json:"base_point"`
Publisher string `json:"publisher"`
WeightRule string `json:"weight_rule"`
DESC string `json:"desc"`
}
func (IndexBasic) TableName() string {
return "tushare_index_basic"
}

View File

@ -77,3 +77,9 @@ func TestFollowedList(t *testing.T) {
t.Log(stockDataApi.GetFollowList()) t.Log(stockDataApi.GetFollowList())
} }
func TestStockDataApi_GetIndexBasic(t *testing.T) {
db.Init("../../data/stock.db")
stockDataApi := NewStockDataApi()
stockDataApi.GetIndexBasic()
}

View File

@ -35,11 +35,13 @@ func main() {
db.Dao.AutoMigrate(&data.StockInfo{}) db.Dao.AutoMigrate(&data.StockInfo{})
db.Dao.AutoMigrate(&data.StockBasic{}) db.Dao.AutoMigrate(&data.StockBasic{})
db.Dao.AutoMigrate(&data.FollowedStock{}) db.Dao.AutoMigrate(&data.FollowedStock{})
db.Dao.AutoMigrate(&data.IndexBasic{})
if stocksBin != nil && len(stocksBin) > 0 { if stocksBin != nil && len(stocksBin) > 0 {
go initStockData() go initStockData()
} }
go data.NewStockDataApi().GetStockBaseInfo() go data.NewStockDataApi().GetStockBaseInfo()
go data.NewStockDataApi().GetIndexBasic()
// Create an instance of the app structure // Create an instance of the app structure
app := NewApp() app := NewApp()