mirror of
https://github.com/ArvinLovegood/go-stock.git
synced 2025-07-19 00:00:09 +08:00
feat(backend): 实现股票价格实时监控功能
- 在 App 结构中添加定时更新股票价格的逻辑 - 实现 MonitorStockPrices 函数,用于更新关注股票的价格 - 在前端添加股票价格更新的事件处理 - 优化股票数据的获取和处理逻辑
This commit is contained in:
parent
e7560f3e9b
commit
1554d3309d
54
app.go
54
app.go
@ -12,6 +12,7 @@ import (
|
|||||||
"go-stock/backend/data"
|
"go-stock/backend/data"
|
||||||
"go-stock/backend/db"
|
"go-stock/backend/db"
|
||||||
"go-stock/backend/logger"
|
"go-stock/backend/logger"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// App struct
|
// App struct
|
||||||
@ -46,14 +47,51 @@ func (a *App) startup(ctx context.Context) {
|
|||||||
// domReady is called after front-end resources have been loaded
|
// domReady is called after front-end resources have been loaded
|
||||||
func (a *App) domReady(ctx context.Context) {
|
func (a *App) domReady(ctx context.Context) {
|
||||||
// Add your action here
|
// Add your action here
|
||||||
//ticker := time.NewTicker(time.Second)
|
|
||||||
//defer ticker.Stop()
|
//定时更新数据
|
||||||
////定时更新数据
|
go func() {
|
||||||
//go func() {
|
ticker := time.NewTicker(time.Second)
|
||||||
// for range ticker.C {
|
defer ticker.Stop()
|
||||||
// runtime.WindowSetTitle(ctx, "go-stock "+time.Now().Format("2006-01-02 15:04:05"))
|
for range ticker.C {
|
||||||
// }
|
runtime.WindowSetTitle(ctx, "go-stock "+time.Now().Format("2006-01-02 15:04:05"))
|
||||||
//}()
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
//定时更新数据
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(time.Second * 2)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for range ticker.C {
|
||||||
|
MonitorStockPrices(a)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
func MonitorStockPrices(a *App) {
|
||||||
|
dest := &[]data.FollowedStock{}
|
||||||
|
db.Dao.Model(&data.FollowedStock{}).Find(dest)
|
||||||
|
for _, item := range *dest {
|
||||||
|
follow := item
|
||||||
|
stockCode := follow.StockCode
|
||||||
|
go func() {
|
||||||
|
stockData, err := data.NewStockDataApi().GetStockCodeRealTimeData(stockCode)
|
||||||
|
if err != nil {
|
||||||
|
logger.SugaredLogger.Errorf("get stock code real time data error:%s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
price, err := convertor.ToFloat(stockData.Price)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if follow.Price != price {
|
||||||
|
runtime.EventsEmit(a.ctx, "stock_price", stockData)
|
||||||
|
go db.Dao.Model(follow).Where("stock_code = ?", stockCode).Updates(map[string]interface{}{
|
||||||
|
"price": stockData.Price,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// beforeClose is called when the application is about to quit,
|
// beforeClose is called when the application is about to quit,
|
||||||
|
@ -268,13 +268,13 @@ func (receiver StockDataApi) GetStockCodeRealTimeData(StockCode string) (*StockI
|
|||||||
return &StockInfo{}, nil
|
return &StockInfo{}, nil
|
||||||
}
|
}
|
||||||
stockData, err := ParseFullSingleStockData(GB18030ToUTF8(resp.Body()))
|
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 {
|
||||||
go db.Dao.Model(&StockInfo{}).Create(stockData)
|
// go db.Dao.Model(&StockInfo{}).Create(stockData)
|
||||||
} 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 stockData, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
ticker.value=setInterval(() => {
|
ticker.value=setInterval(() => {
|
||||||
if(isTradingTime()){
|
if(isTradingTime()){
|
||||||
monitor()
|
//monitor()
|
||||||
data.fenshiURL='http://image.sinajs.cn/newchart/min/n/'+data.code+'.gif'+"?t="+Date.now()
|
data.fenshiURL='http://image.sinajs.cn/newchart/min/n/'+data.code+'.gif'+"?t="+Date.now()
|
||||||
}
|
}
|
||||||
}, 3500)
|
}, 3500)
|
||||||
@ -103,6 +103,10 @@ EventsOn("showSearch",(data)=>{
|
|||||||
addBTN.value = data === 1;
|
addBTN.value = data === 1;
|
||||||
})
|
})
|
||||||
|
|
||||||
|
EventsOn("stock_price",(data)=>{
|
||||||
|
console.log("stock_price",data['股票代码'])
|
||||||
|
updateData(data)
|
||||||
|
})
|
||||||
|
|
||||||
EventsOn("refreshFollowList",(data)=>{
|
EventsOn("refreshFollowList",(data)=>{
|
||||||
|
|
||||||
@ -183,6 +187,60 @@ function getStockList(value){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updateData(result) {
|
||||||
|
if(result["当前价格"]<=0){
|
||||||
|
result["当前价格"]=result["卖一报价"]
|
||||||
|
}
|
||||||
|
|
||||||
|
let s=(result["当前价格"]-result["昨日收盘价"])*100/result["昨日收盘价"]
|
||||||
|
let roundedNum = s.toFixed(2); // 将数字转换为保留两位小数的字符串形式
|
||||||
|
result.s=roundedNum+"%"
|
||||||
|
|
||||||
|
result.highRate=((result["今日最高价"]-result["今日开盘价"])*100/result["今日开盘价"]).toFixed(2)+"%"
|
||||||
|
result.lowRate=((result["今日最低价"]-result["今日开盘价"])*100/result["今日开盘价"]).toFixed(2)+"%"
|
||||||
|
|
||||||
|
if (roundedNum>0) {
|
||||||
|
result.type="error"
|
||||||
|
result.color="#E88080"
|
||||||
|
}else if (roundedNum<0) {
|
||||||
|
result.type="success"
|
||||||
|
result.color="#63E2B7"
|
||||||
|
}else {
|
||||||
|
result.type="default"
|
||||||
|
result.color="#FFFFFF"
|
||||||
|
}
|
||||||
|
let res= followList.value.filter(item => item.StockCode===result['股票代码'])
|
||||||
|
if (res.length>0) {
|
||||||
|
result.Sort=res[0].Sort
|
||||||
|
result.costPrice=res[0].CostPrice
|
||||||
|
result.volume=res[0].Volume
|
||||||
|
result.profit=((result["当前价格"]-result.costPrice)*100/result.costPrice).toFixed(3)
|
||||||
|
result.profitAmountToday=(result.volume*(result["当前价格"]-result["昨日收盘价"])).toFixed(2)
|
||||||
|
result.profitAmount=(result.volume*(result["当前价格"]-result.costPrice)).toFixed(2)
|
||||||
|
if(result.profitAmount>0){
|
||||||
|
result.profitType="error"
|
||||||
|
}else if(result.profitAmount<0){
|
||||||
|
result.profitType="success"
|
||||||
|
}
|
||||||
|
if(result["当前价格"]){
|
||||||
|
if(res[0].AlarmChangePercent>0&&Math.abs(roundedNum)>=res[0].AlarmChangePercent){
|
||||||
|
SendMessage(result,1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(res[0].AlarmPrice>0&&result["当前价格"]>=res[0].AlarmPrice){
|
||||||
|
SendMessage(result,2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(res[0].CostPrice>0&&result["当前价格"]>=res[0].CostPrice){
|
||||||
|
SendMessage(result,3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.key=GetSortKey(result.Sort,result["股票代码"])
|
||||||
|
results.value[GetSortKey(result.Sort,result["股票代码"])]=result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async function monitor() {
|
async function monitor() {
|
||||||
for (let code of stocks.value) {
|
for (let code of stocks.value) {
|
||||||
// console.log(code)
|
// console.log(code)
|
||||||
|
9
main.go
9
main.go
@ -44,8 +44,7 @@ func main() {
|
|||||||
if stocksBin != nil && len(stocksBin) > 0 {
|
if stocksBin != nil && len(stocksBin) > 0 {
|
||||||
go initStockData()
|
go initStockData()
|
||||||
}
|
}
|
||||||
go data.NewStockDataApi().GetStockBaseInfo()
|
//updateBasicInfo()
|
||||||
go data.NewStockDataApi().GetIndexBasic()
|
|
||||||
|
|
||||||
// Create an instance of the app structure
|
// Create an instance of the app structure
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
@ -141,6 +140,12 @@ func main() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateBasicInfo() {
|
||||||
|
//更新基本信息
|
||||||
|
go data.NewStockDataApi().GetStockBaseInfo()
|
||||||
|
go data.NewStockDataApi().GetIndexBasic()
|
||||||
|
}
|
||||||
|
|
||||||
func initStockData() {
|
func initStockData() {
|
||||||
var count int64
|
var count int64
|
||||||
db.Dao.Model(&data.StockBasic{}).Count(&count)
|
db.Dao.Model(&data.StockBasic{}).Count(&count)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user