feat(backend): 优化股票数据获取逻辑

- 修改 GetStockCodeRealTimeData 方法,支持批量获取多个股票代码的实时数据
- 新增 GetStockInfos 函数,用于获取关注股票的实时信息- 重构 getStockInfo 函数,提高代码复用性
- 优化数据处理逻辑,提高程序运行效率
This commit is contained in:
spark 2025-01-09 14:45:25 +08:00
parent ad428f83f8
commit 7e27996f17
4 changed files with 97 additions and 22 deletions

62
app.go
View File

@ -8,6 +8,7 @@ import (
"github.com/coocood/freecache"
"github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/mathutil"
"github.com/duke-git/lancet/v2/slice"
"github.com/getlantern/systray"
"github.com/wailsapp/wails/v2/pkg/runtime"
"go-stock/backend/data"
@ -50,7 +51,7 @@ func (a *App) domReady(ctx context.Context) {
// Add your action here
//定时更新数据
go func() {
ticker := time.NewTicker(time.Second * 2)
ticker := time.NewTicker(time.Second * 1)
defer ticker.Stop()
for range ticker.C {
if isTradingTime(time.Now()) {
@ -97,26 +98,64 @@ func MonitorStockPrices(a *App) {
dest := &[]data.FollowedStock{}
db.Dao.Model(&data.FollowedStock{}).Find(dest)
total := float64(0)
for _, follow := range *dest {
stockData := getStockInfo(follow)
total += stockData.ProfitAmountToday
price, _ := convertor.ToFloat(stockData.Price)
if stockData.PrePrice != price {
go runtime.EventsEmit(a.ctx, "stock_price", stockData)
//for _, follow := range *dest {
// stockData := getStockInfo(follow)
// total += stockData.ProfitAmountToday
// price, _ := convertor.ToFloat(stockData.Price)
// if stockData.PrePrice != price {
// go runtime.EventsEmit(a.ctx, "stock_price", stockData)
// }
//}
stockInfos := GetStockInfos(*dest...)
for _, stockInfo := range *stockInfos {
total += stockInfo.ProfitAmountToday
price, _ := convertor.ToFloat(stockInfo.Price)
if stockInfo.PrePrice != price {
go runtime.EventsEmit(a.ctx, "stock_price", stockInfo)
}
}
title := "go-stock " + time.Now().Format(time.DateTime) + fmt.Sprintf(" %.2f¥", total)
runtime.WindowSetTitle(a.ctx, title)
systray.SetTooltip(title)
}
func getStockInfo(follow data.FollowedStock) *data.StockInfo {
stockCode := follow.StockCode
stockData, err := data.NewStockDataApi().GetStockCodeRealTimeData(stockCode)
func GetStockInfos(follows ...data.FollowedStock) *[]data.StockInfo {
stockCodes := make([]string, 0)
for _, follow := range follows {
stockCodes = append(stockCodes, follow.StockCode)
}
stockData, err := data.NewStockDataApi().GetStockCodeRealTimeData(stockCodes...)
if err != nil {
logger.SugaredLogger.Errorf("get stock code real time data error:%s", err.Error())
return nil
}
stockInfos := make([]data.StockInfo, 0)
for _, info := range *stockData {
v, ok := slice.FindBy(follows, func(idx int, follow data.FollowedStock) bool {
return follow.StockCode == info.Code
})
if ok {
addStockFollowData(v, &info)
stockInfos = append(stockInfos, info)
}
}
return &stockInfos
}
func getStockInfo(follow data.FollowedStock) *data.StockInfo {
stockCode := follow.StockCode
stockDatas, err := data.NewStockDataApi().GetStockCodeRealTimeData(stockCode)
if err != nil {
logger.SugaredLogger.Errorf("get stock code real time data error:%s", err.Error())
return nil
}
stockData := (*stockDatas)[0]
addStockFollowData(follow, &stockData)
return &stockData
}
func addStockFollowData(follow data.FollowedStock, stockData *data.StockInfo) {
stockData.PrePrice = follow.Price //上次当前价格
stockData.Sort = follow.Sort
stockData.CostPrice = follow.CostPrice //成本价
@ -164,11 +203,10 @@ func getStockInfo(follow data.FollowedStock) *data.StockInfo {
//logger.SugaredLogger.Debugf("stockData:%+v", stockData)
if follow.Price != price {
go db.Dao.Model(follow).Where("stock_code = ?", stockCode).Updates(map[string]interface{}{
go db.Dao.Model(follow).Where("stock_code = ?", follow.StockCode).Updates(map[string]interface{}{
"price": stockData.Price,
})
}
return stockData
}
// beforeClose is called when the application is about to quit,

View File

@ -273,17 +273,29 @@ func (receiver StockDataApi) GetStockBaseInfo() {
}
func (receiver StockDataApi) GetStockCodeRealTimeData(StockCode string) (*StockInfo, error) {
func (receiver StockDataApi) GetStockCodeRealTimeData(StockCodes ...string) (*[]StockInfo, error) {
resp, err := receiver.client.R().
SetHeader("Host", "hq.sinajs.cn").
SetHeader("Referer", "https://finance.sina.com.cn/").
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0").
Get(fmt.Sprintf(sina_stook_url, time.Now().Unix(), StockCode))
Get(fmt.Sprintf(sina_stook_url, time.Now().Unix(), slice.Join(StockCodes, ",")))
if err != nil {
logger.SugaredLogger.Error(err.Error())
return &StockInfo{}, nil
return &[]StockInfo{}, nil
}
stockInfos := make([]StockInfo, 0)
str := GB18030ToUTF8(resp.Body())
dataStr := strutil.SplitEx(str, "\n", true)
for _, data := range dataStr {
//logger.SugaredLogger.Info(data)
stockData, err := ParseFullSingleStockData(data)
if err != nil {
logger.SugaredLogger.Error(err.Error())
continue
}
stockInfos = append(stockInfos, *stockData)
}
stockData, err := ParseFullSingleStockData(GB18030ToUTF8(resp.Body()))
//var count int64
//db.Dao.Model(&StockInfo{}).Where("code = ?", StockCode).Count(&count)
//if count == 0 {
@ -291,16 +303,17 @@ func (receiver StockDataApi) GetStockCodeRealTimeData(StockCode string) (*StockI
//} else {
// go db.Dao.Model(&StockInfo{}).Where("code = ?", StockCode).Updates(stockData)
//}
return stockData, err
return &stockInfos, err
}
func (receiver StockDataApi) Follow(stockCode string) string {
logger.SugaredLogger.Infof("Follow %s", stockCode)
stockInfo, err := receiver.GetStockCodeRealTimeData(stockCode)
stockInfos, err := receiver.GetStockCodeRealTimeData(stockCode)
if err != nil {
logger.SugaredLogger.Error(err.Error())
return "关注失败"
}
stockInfo := (*stockInfos)[0]
price, _ := convertor.ToFloat(stockInfo.Price)
db.Dao.Model(&FollowedStock{}).FirstOrCreate(&FollowedStock{
StockCode: stockCode,

View File

@ -2,11 +2,16 @@ package data
import (
"encoding/json"
"fmt"
"github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/strutil"
"github.com/go-resty/resty/v2"
"go-stock/backend/db"
"go-stock/backend/logger"
"io/ioutil"
"strings"
"testing"
"time"
)
// @Author spark
@ -14,9 +19,28 @@ import (
// @Desc
//-----------------------------------------------------------------------------------
func TestParseFullSingleStockData(t *testing.T) {
resp, err := resty.New().R().
SetHeader("Host", "hq.sinajs.cn").
SetHeader("Referer", "https://finance.sina.com.cn/").
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0").
Get(fmt.Sprintf(sina_stook_url, time.Now().Unix(), "sh600859,sh600745"))
if err != nil {
logger.SugaredLogger.Error(err.Error())
}
data := GB18030ToUTF8(resp.Body())
strs := strutil.SplitEx(data, "\n", true)
for _, str := range strs {
logger.SugaredLogger.Info(str)
}
}
func TestNewStockDataApi(t *testing.T) {
stockDataApi := NewStockDataApi()
t.Log(stockDataApi.GetStockCodeRealTimeData("sh600859"))
datas, _ := stockDataApi.GetStockCodeRealTimeData("sh600859", "sh600745")
for _, data := range *datas {
t.Log(data)
}
}
func TestGetStockBaseInfo(t *testing.T) {
@ -74,7 +98,7 @@ func TestReadFile(t *testing.T) {
func TestFollowedList(t *testing.T) {
db.Init("../../data/stock.db")
stockDataApi := NewStockDataApi()
t.Log(stockDataApi.GetFollowList())
stockDataApi.GetFollowList()
}

View File

@ -47,7 +47,7 @@ const data = reactive({
})
const sortedResults = computed(() => {
console.log("computed",sortedResults.value)
//console.log("computed",sortedResults.value)
const sortedKeys =Object.keys(results.value).sort();
const sortedObject = {};
sortedKeys.forEach(key => {
@ -104,7 +104,7 @@ EventsOn("showSearch",(data)=>{
})
EventsOn("stock_price",(data)=>{
console.log("stock_price",data['股票代码'])
//console.log("stock_price",data[''])
updateData(data)
})