mirror of
https://github.com/ArvinLovegood/go-stock.git
synced 2025-07-19 00:00:09 +08:00
refactor(stock): 重构股票数据处理逻辑
- 移除定时更新标题的代码 - 优化股票数据获取和处理流程 - 增加更多股票相关信息的计算和展示 - 调整前端组件以适应新的数据结构 - 修复了一些潜在的数值计算问题
This commit is contained in:
parent
d3c6c1d570
commit
ad428f83f8
114
app.go
114
app.go
@ -4,6 +4,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/coocood/freecache"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
@ -47,16 +48,6 @@ func (a *App) startup(ctx context.Context) {
|
||||
// domReady is called after front-end resources have been loaded
|
||||
func (a *App) domReady(ctx context.Context) {
|
||||
// Add your action here
|
||||
|
||||
//定时更新数据
|
||||
go func() {
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
runtime.WindowSetTitle(ctx, "go-stock "+time.Now().Format("2006-01-02 15:04"))
|
||||
}
|
||||
}()
|
||||
|
||||
//定时更新数据
|
||||
go func() {
|
||||
ticker := time.NewTicker(time.Second * 2)
|
||||
@ -105,28 +96,79 @@ func isTradingTime(date time.Time) bool {
|
||||
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
|
||||
}
|
||||
stockData.PrePrice = follow.Price
|
||||
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,
|
||||
})
|
||||
}
|
||||
}()
|
||||
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)
|
||||
}
|
||||
}
|
||||
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)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("get stock code real time data error:%s", err.Error())
|
||||
return nil
|
||||
}
|
||||
stockData.PrePrice = follow.Price //上次当前价格
|
||||
stockData.Sort = follow.Sort
|
||||
stockData.CostPrice = follow.CostPrice //成本价
|
||||
stockData.CostVolume = follow.Volume //成本量
|
||||
stockData.AlarmChangePercent = follow.AlarmChangePercent
|
||||
stockData.AlarmPrice = follow.AlarmPrice
|
||||
|
||||
//当前价格
|
||||
price, _ := convertor.ToFloat(stockData.Price)
|
||||
//当前价格为0 时 使用卖一价格作为当前价格
|
||||
if price == 0 {
|
||||
price, _ = convertor.ToFloat(stockData.A1P)
|
||||
}
|
||||
//当前价格依然为0 时 使用买一报价作为当前价格
|
||||
if price == 0 {
|
||||
price, _ = convertor.ToFloat(stockData.B1P)
|
||||
}
|
||||
|
||||
//昨日收盘价
|
||||
preClosePrice, _ := convertor.ToFloat(stockData.PreClose)
|
||||
|
||||
//今日最高价
|
||||
highPrice, _ := convertor.ToFloat(stockData.High)
|
||||
if highPrice == 0 {
|
||||
highPrice, _ = convertor.ToFloat(stockData.Open)
|
||||
}
|
||||
|
||||
//今日最低价
|
||||
lowPrice, _ := convertor.ToFloat(stockData.Low)
|
||||
if lowPrice == 0 {
|
||||
lowPrice, _ = convertor.ToFloat(stockData.Open)
|
||||
}
|
||||
//开盘价
|
||||
//openPrice, _ := convertor.ToFloat(stockData.Open)
|
||||
|
||||
stockData.ChangePrice = mathutil.RoundToFloat(price-preClosePrice, 2)
|
||||
stockData.ChangePercent = mathutil.RoundToFloat(mathutil.Div(price-preClosePrice, preClosePrice)*100, 3)
|
||||
stockData.HighRate = mathutil.RoundToFloat(mathutil.Div(highPrice-preClosePrice, preClosePrice)*100, 3)
|
||||
stockData.LowRate = mathutil.RoundToFloat(mathutil.Div(lowPrice-preClosePrice, preClosePrice)*100, 3)
|
||||
if follow.CostPrice > 0 && follow.Volume > 0 {
|
||||
stockData.Profit = mathutil.RoundToFloat(mathutil.Div(price-follow.CostPrice, follow.CostPrice)*100, 3)
|
||||
stockData.ProfitAmount = mathutil.RoundToFloat((price-follow.CostPrice)*float64(follow.Volume), 2)
|
||||
stockData.ProfitAmountToday = mathutil.RoundToFloat((price-preClosePrice)*float64(follow.Volume), 2)
|
||||
}
|
||||
|
||||
//logger.SugaredLogger.Debugf("stockData:%+v", stockData)
|
||||
if follow.Price != price {
|
||||
go db.Dao.Model(follow).Where("stock_code = ?", stockCode).Updates(map[string]interface{}{
|
||||
"price": stockData.Price,
|
||||
})
|
||||
}
|
||||
return stockData
|
||||
}
|
||||
|
||||
// beforeClose is called when the application is about to quit,
|
||||
@ -161,8 +203,14 @@ func (a *App) shutdown(ctx context.Context) {
|
||||
}
|
||||
|
||||
// Greet returns a greeting for the given name
|
||||
func (a *App) Greet(name string) *data.StockInfo {
|
||||
stockInfo, _ := data.NewStockDataApi().GetStockCodeRealTimeData(name)
|
||||
func (a *App) Greet(stockCode string) *data.StockInfo {
|
||||
//stockInfo, _ := data.NewStockDataApi().GetStockCodeRealTimeData(stockCode)
|
||||
|
||||
follow := &data.FollowedStock{
|
||||
StockCode: stockCode,
|
||||
}
|
||||
db.Dao.Model(follow).Where("stock_code = ?", stockCode).First(follow)
|
||||
stockInfo := getStockInfo(*follow)
|
||||
return stockInfo
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,8 @@ type StockInfo struct {
|
||||
Amount string `json:"成交金额"`
|
||||
Open string `json:"今日开盘价"`
|
||||
PreClose string `json:"昨日收盘价"`
|
||||
High string `json:"今日最低价"`
|
||||
Low string `json:"今日最高价"`
|
||||
High string `json:"今日最高价"`
|
||||
Low string `json:"今日最低价"`
|
||||
Bid string `json:"竞买价"`
|
||||
Ask string `json:"竞卖价"`
|
||||
B1P string `json:"买一报价"`
|
||||
@ -67,6 +67,21 @@ type StockInfo struct {
|
||||
A4V string `json:"卖四申报"`
|
||||
A5P string `json:"卖五报价"`
|
||||
A5V string `json:"卖五申报"`
|
||||
|
||||
//以下是字段值需二次计算
|
||||
ChangePercent float64 `json:"changePercent"` //涨跌幅
|
||||
ChangePrice float64 `json:"changePrice"` //涨跌额
|
||||
HighRate float64 `json:"highRate"` //最高涨跌
|
||||
LowRate float64 `json:"lowRate"` //最低涨跌
|
||||
CostPrice float64 `json:"costPrice"` //成本价
|
||||
CostVolume int64 `json:"costVolume"` //持仓数量
|
||||
Profit float64 `json:"profit"` //总盈亏率
|
||||
ProfitAmount float64 `json:"profitAmount"` //总盈亏金额
|
||||
ProfitAmountToday float64 `json:"profitAmountToday"` //今日盈亏金额
|
||||
|
||||
Sort int64 `json:"sort"` //排序
|
||||
AlarmChangePercent float64 `json:"alarmChangePercent"`
|
||||
AlarmPrice float64 `json:"alarmPrice"`
|
||||
}
|
||||
|
||||
func (receiver StockInfo) TableName() string {
|
||||
|
@ -192,56 +192,36 @@ async function updateData(result) {
|
||||
result["当前价格"]=result["卖一报价"]
|
||||
}
|
||||
|
||||
let s=(result["当前价格"]-result["昨日收盘价"])*100/result["昨日收盘价"]
|
||||
let roundedNum = s.toFixed(2); // 将数字转换为保留两位小数的字符串形式
|
||||
|
||||
// let s2=(result["上次当前价格"]-result["昨日收盘价"])*100/result["昨日收盘价"]
|
||||
// let roundedNum2 = s2.toFixed(2); // 将数字转换为保留两位小数的字符串形式
|
||||
|
||||
result.rf=roundedNum
|
||||
// result.rf2=roundedNum2
|
||||
result.s=roundedNum+"%"
|
||||
|
||||
result.highRate=((result["今日最高价"]-result["今日开盘价"])*100/result["今日开盘价"]).toFixed(2)+"%"
|
||||
result.lowRate=((result["今日最低价"]-result["今日开盘价"])*100/result["今日开盘价"]).toFixed(2)+"%"
|
||||
|
||||
if (roundedNum>0) {
|
||||
if (result.changePercent>0) {
|
||||
result.type="error"
|
||||
result.color="#E88080"
|
||||
}else if (roundedNum<0) {
|
||||
}else if (result.changePercent<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){
|
||||
if(result.alarmChangePercent>0&&Math.abs(result.changePercent)>=result.alarmChangePercent){
|
||||
SendMessage(result,1)
|
||||
}
|
||||
|
||||
if(res[0].AlarmPrice>0&&result["当前价格"]>=res[0].AlarmPrice){
|
||||
if(result.alarmPrice>0&&result["当前价格"]>=result.alarmPrice){
|
||||
SendMessage(result,2)
|
||||
}
|
||||
|
||||
if(res[0].CostPrice>0&&result["当前价格"]>=res[0].CostPrice){
|
||||
if(result.costPrice>0&&result["当前价格"]>=result.costPrice){
|
||||
SendMessage(result,3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.key=GetSortKey(result.Sort,result["股票代码"])
|
||||
results.value[GetSortKey(result.Sort,result["股票代码"])]=result
|
||||
}
|
||||
@ -251,57 +231,7 @@ async function monitor() {
|
||||
for (let code of stocks.value) {
|
||||
// console.log(code)
|
||||
Greet(code).then(result => {
|
||||
if(result["当前价格"]<=0){
|
||||
result["当前价格"]=result["卖一报价"]
|
||||
}
|
||||
|
||||
let s=(result["当前价格"]-result["昨日收盘价"])*100/result["昨日收盘价"]
|
||||
let roundedNum = s.toFixed(2); // 将数字转换为保留两位小数的字符串形式
|
||||
result.s=roundedNum+"%"
|
||||
result.rf=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===code)
|
||||
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
|
||||
|
||||
updateData(result)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -456,20 +386,22 @@ function getHeight() {
|
||||
<n-grid :cols="1" :y-gap="6">
|
||||
<n-gi>
|
||||
<n-text :type="result.type" >
|
||||
<n-number-animation :precision="2" :from="result['上次当前价格']" :to="Number(result['当前价格'])" />
|
||||
<n-number-animation :duration="1000" :precision="2" :from="result['上次当前价格']" :to="Number(result['当前价格'])" />
|
||||
</n-text>
|
||||
<n-text style="padding-left: 10px;" :type="result.type">
|
||||
<n-number-animation :precision="2" :from="0" :to="result.rf" />%
|
||||
<n-number-animation :duration="1000" :precision="3" :from="0" :to="result.changePercent" />%
|
||||
</n-text>
|
||||
<n-text size="small" v-if="result.profitAmountToday>0" :type="result.type">{{result.profitAmountToday}}</n-text>
|
||||
<n-text size="small" v-if="result.costVolume>0" :type="result.type">
|
||||
<n-number-animation :duration="1000" :precision="2" :from="0" :to="result.profitAmountToday" />
|
||||
</n-text>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
<n-grid :cols="2" :y-gap="4" :x-gap="4" >
|
||||
<n-gi>
|
||||
<n-text :type="'info'">{{"最高 "+result["今日最高价"]+" "+result.highRate }}</n-text>
|
||||
<n-text :type="'info'">{{"最高 "+result["今日最高价"]+" "+result.highRate }}%</n-text>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-text :type="'info'">{{"最低 "+result["今日最低价"]+" "+result.lowRate }}</n-text>
|
||||
<n-text :type="'info'">{{"最低 "+result["今日最低价"]+" "+result.lowRate }}%</n-text>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-text :type="'info'">{{"昨收 "+result["昨日收盘价"]}}</n-text>
|
||||
@ -484,7 +416,7 @@ function getHeight() {
|
||||
<template #footer>
|
||||
<n-flex justify="center">
|
||||
<n-tag size="small" v-if="result.volume>0" :type="result.profitType">{{result.volume+"股"}}</n-tag>
|
||||
<n-tag size="small" v-if="result.costPrice>0" :type="result.profitType">{{"成本:"+result.costPrice+" "+result.profit+"%"+" ( "+result.profitAmount+" ¥ )"}}</n-tag>
|
||||
<n-tag size="small" v-if="result.costPrice>0" :type="result.profitType">{{"成本:"+result.costPrice+"*"+result.costVolume+" "+result.profit+"%"+" ( "+result.profitAmount+" ¥ )"}}</n-tag>
|
||||
</n-flex>
|
||||
</template>
|
||||
<template #action>
|
||||
|
@ -144,8 +144,8 @@ export namespace data {
|
||||
"成交金额": string;
|
||||
"今日开盘价": string;
|
||||
"昨日收盘价": string;
|
||||
"今日最低价": string;
|
||||
"今日最高价": string;
|
||||
"今日最低价": string;
|
||||
"竞买价": string;
|
||||
"竞卖价": string;
|
||||
"买一报价": string;
|
||||
@ -168,6 +168,18 @@ export namespace data {
|
||||
"卖四申报": string;
|
||||
"卖五报价": string;
|
||||
"卖五申报": string;
|
||||
changePercent: number;
|
||||
changePrice: number;
|
||||
highRate: number;
|
||||
lowRate: number;
|
||||
costPrice: number;
|
||||
costVolume: number;
|
||||
profit: number;
|
||||
profitAmount: number;
|
||||
profitAmountToday: number;
|
||||
sort: number;
|
||||
alarmChangePercent: number;
|
||||
alarmPrice: number;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new StockInfo(source);
|
||||
@ -189,8 +201,8 @@ export namespace data {
|
||||
this["成交金额"] = source["成交金额"];
|
||||
this["今日开盘价"] = source["今日开盘价"];
|
||||
this["昨日收盘价"] = source["昨日收盘价"];
|
||||
this["今日最低价"] = source["今日最低价"];
|
||||
this["今日最高价"] = source["今日最高价"];
|
||||
this["今日最低价"] = source["今日最低价"];
|
||||
this["竞买价"] = source["竞买价"];
|
||||
this["竞卖价"] = source["竞卖价"];
|
||||
this["买一报价"] = source["买一报价"];
|
||||
@ -213,6 +225,18 @@ export namespace data {
|
||||
this["卖四申报"] = source["卖四申报"];
|
||||
this["卖五报价"] = source["卖五报价"];
|
||||
this["卖五申报"] = source["卖五申报"];
|
||||
this.changePercent = source["changePercent"];
|
||||
this.changePrice = source["changePrice"];
|
||||
this.highRate = source["highRate"];
|
||||
this.lowRate = source["lowRate"];
|
||||
this.costPrice = source["costPrice"];
|
||||
this.costVolume = source["costVolume"];
|
||||
this.profit = source["profit"];
|
||||
this.profitAmount = source["profitAmount"];
|
||||
this.profitAmountToday = source["profitAmountToday"];
|
||||
this.sort = source["sort"];
|
||||
this.alarmChangePercent = source["alarmChangePercent"];
|
||||
this.alarmPrice = source["alarmPrice"];
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
|
Loading…
x
Reference in New Issue
Block a user