mirror of
https://github.com/ArvinLovegood/go-stock.git
synced 2025-07-19 00:00:09 +08:00
feat(backend): 优化股票数据获取逻辑
- 修改 GetStockCodeRealTimeData 方法,支持批量获取多个股票代码的实时数据 - 新增 GetStockInfos 函数,用于获取关注股票的实时信息- 重构 getStockInfo 函数,提高代码复用性 - 优化数据处理逻辑,提高程序运行效率
This commit is contained in:
parent
ad428f83f8
commit
7e27996f17
62
app.go
62
app.go
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/coocood/freecache"
|
"github.com/coocood/freecache"
|
||||||
"github.com/duke-git/lancet/v2/convertor"
|
"github.com/duke-git/lancet/v2/convertor"
|
||||||
"github.com/duke-git/lancet/v2/mathutil"
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
"github.com/getlantern/systray"
|
"github.com/getlantern/systray"
|
||||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||||
"go-stock/backend/data"
|
"go-stock/backend/data"
|
||||||
@ -50,7 +51,7 @@ func (a *App) domReady(ctx context.Context) {
|
|||||||
// Add your action here
|
// Add your action here
|
||||||
//定时更新数据
|
//定时更新数据
|
||||||
go func() {
|
go func() {
|
||||||
ticker := time.NewTicker(time.Second * 2)
|
ticker := time.NewTicker(time.Second * 1)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
if isTradingTime(time.Now()) {
|
if isTradingTime(time.Now()) {
|
||||||
@ -97,26 +98,64 @@ func MonitorStockPrices(a *App) {
|
|||||||
dest := &[]data.FollowedStock{}
|
dest := &[]data.FollowedStock{}
|
||||||
db.Dao.Model(&data.FollowedStock{}).Find(dest)
|
db.Dao.Model(&data.FollowedStock{}).Find(dest)
|
||||||
total := float64(0)
|
total := float64(0)
|
||||||
for _, follow := range *dest {
|
//for _, follow := range *dest {
|
||||||
stockData := getStockInfo(follow)
|
// stockData := getStockInfo(follow)
|
||||||
total += stockData.ProfitAmountToday
|
// total += stockData.ProfitAmountToday
|
||||||
price, _ := convertor.ToFloat(stockData.Price)
|
// price, _ := convertor.ToFloat(stockData.Price)
|
||||||
if stockData.PrePrice != price {
|
// if stockData.PrePrice != price {
|
||||||
go runtime.EventsEmit(a.ctx, "stock_price", stockData)
|
// 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)
|
title := "go-stock " + time.Now().Format(time.DateTime) + fmt.Sprintf(" %.2f¥", total)
|
||||||
runtime.WindowSetTitle(a.ctx, title)
|
runtime.WindowSetTitle(a.ctx, title)
|
||||||
systray.SetTooltip(title)
|
systray.SetTooltip(title)
|
||||||
|
|
||||||
}
|
}
|
||||||
func getStockInfo(follow data.FollowedStock) *data.StockInfo {
|
func GetStockInfos(follows ...data.FollowedStock) *[]data.StockInfo {
|
||||||
stockCode := follow.StockCode
|
stockCodes := make([]string, 0)
|
||||||
stockData, err := data.NewStockDataApi().GetStockCodeRealTimeData(stockCode)
|
for _, follow := range follows {
|
||||||
|
stockCodes = append(stockCodes, follow.StockCode)
|
||||||
|
}
|
||||||
|
stockData, err := data.NewStockDataApi().GetStockCodeRealTimeData(stockCodes...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.SugaredLogger.Errorf("get stock code real time data error:%s", err.Error())
|
logger.SugaredLogger.Errorf("get stock code real time data error:%s", err.Error())
|
||||||
return nil
|
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.PrePrice = follow.Price //上次当前价格
|
||||||
stockData.Sort = follow.Sort
|
stockData.Sort = follow.Sort
|
||||||
stockData.CostPrice = follow.CostPrice //成本价
|
stockData.CostPrice = follow.CostPrice //成本价
|
||||||
@ -164,11 +203,10 @@ func getStockInfo(follow data.FollowedStock) *data.StockInfo {
|
|||||||
|
|
||||||
//logger.SugaredLogger.Debugf("stockData:%+v", stockData)
|
//logger.SugaredLogger.Debugf("stockData:%+v", stockData)
|
||||||
if follow.Price != price {
|
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,
|
"price": stockData.Price,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return stockData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// beforeClose is called when the application is about to quit,
|
// beforeClose is called when the application is about to quit,
|
||||||
|
@ -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().
|
resp, err := receiver.client.R().
|
||||||
SetHeader("Host", "hq.sinajs.cn").
|
SetHeader("Host", "hq.sinajs.cn").
|
||||||
SetHeader("Referer", "https://finance.sina.com.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").
|
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 {
|
if err != nil {
|
||||||
logger.SugaredLogger.Error(err.Error())
|
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
|
//var count int64
|
||||||
//db.Dao.Model(&StockInfo{}).Where("code = ?", StockCode).Count(&count)
|
//db.Dao.Model(&StockInfo{}).Where("code = ?", StockCode).Count(&count)
|
||||||
//if count == 0 {
|
//if count == 0 {
|
||||||
@ -291,16 +303,17 @@ func (receiver StockDataApi) GetStockCodeRealTimeData(StockCode string) (*StockI
|
|||||||
//} else {
|
//} else {
|
||||||
// go db.Dao.Model(&StockInfo{}).Where("code = ?", StockCode).Updates(stockData)
|
// go db.Dao.Model(&StockInfo{}).Where("code = ?", StockCode).Updates(stockData)
|
||||||
//}
|
//}
|
||||||
return stockData, err
|
return &stockInfos, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (receiver StockDataApi) Follow(stockCode string) string {
|
func (receiver StockDataApi) Follow(stockCode string) string {
|
||||||
logger.SugaredLogger.Infof("Follow %s", stockCode)
|
logger.SugaredLogger.Infof("Follow %s", stockCode)
|
||||||
stockInfo, err := receiver.GetStockCodeRealTimeData(stockCode)
|
stockInfos, err := receiver.GetStockCodeRealTimeData(stockCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.SugaredLogger.Error(err.Error())
|
logger.SugaredLogger.Error(err.Error())
|
||||||
return "关注失败"
|
return "关注失败"
|
||||||
}
|
}
|
||||||
|
stockInfo := (*stockInfos)[0]
|
||||||
price, _ := convertor.ToFloat(stockInfo.Price)
|
price, _ := convertor.ToFloat(stockInfo.Price)
|
||||||
db.Dao.Model(&FollowedStock{}).FirstOrCreate(&FollowedStock{
|
db.Dao.Model(&FollowedStock{}).FirstOrCreate(&FollowedStock{
|
||||||
StockCode: stockCode,
|
StockCode: stockCode,
|
||||||
|
@ -2,11 +2,16 @@ package data
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"github.com/duke-git/lancet/v2/convertor"
|
"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/db"
|
||||||
|
"go-stock/backend/logger"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @Author spark
|
// @Author spark
|
||||||
@ -14,9 +19,28 @@ import (
|
|||||||
// @Desc
|
// @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) {
|
func TestNewStockDataApi(t *testing.T) {
|
||||||
stockDataApi := NewStockDataApi()
|
stockDataApi := NewStockDataApi()
|
||||||
t.Log(stockDataApi.GetStockCodeRealTimeData("sh600859"))
|
datas, _ := stockDataApi.GetStockCodeRealTimeData("sh600859", "sh600745")
|
||||||
|
for _, data := range *datas {
|
||||||
|
t.Log(data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetStockBaseInfo(t *testing.T) {
|
func TestGetStockBaseInfo(t *testing.T) {
|
||||||
@ -74,7 +98,7 @@ func TestReadFile(t *testing.T) {
|
|||||||
func TestFollowedList(t *testing.T) {
|
func TestFollowedList(t *testing.T) {
|
||||||
db.Init("../../data/stock.db")
|
db.Init("../../data/stock.db")
|
||||||
stockDataApi := NewStockDataApi()
|
stockDataApi := NewStockDataApi()
|
||||||
t.Log(stockDataApi.GetFollowList())
|
stockDataApi.GetFollowList()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ const data = reactive({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const sortedResults = computed(() => {
|
const sortedResults = computed(() => {
|
||||||
console.log("computed",sortedResults.value)
|
//console.log("computed",sortedResults.value)
|
||||||
const sortedKeys =Object.keys(results.value).sort();
|
const sortedKeys =Object.keys(results.value).sort();
|
||||||
const sortedObject = {};
|
const sortedObject = {};
|
||||||
sortedKeys.forEach(key => {
|
sortedKeys.forEach(key => {
|
||||||
@ -104,7 +104,7 @@ EventsOn("showSearch",(data)=>{
|
|||||||
})
|
})
|
||||||
|
|
||||||
EventsOn("stock_price",(data)=>{
|
EventsOn("stock_price",(data)=>{
|
||||||
console.log("stock_price",data['股票代码'])
|
//console.log("stock_price",data['股票代码'])
|
||||||
updateData(data)
|
updateData(data)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user