mirror of
https://github.com/ArvinLovegood/go-stock.git
synced 2025-07-19 00:00:09 +08:00
feat(stock):优化股票分时图表展示
- 新增 GetStockMinutePriceLineData 函数获取股票分时数据 - 在前端实现分时数据图表展示 - 后端增加 GetStockMinutePriceData接口获取分时数据 - 更新数据库模型,添加 MinuteData 结构体
This commit is contained in:
parent
11a1a47eca
commit
cf537ca695
11
app.go
11
app.go
@ -1065,6 +1065,17 @@ func (a *App) RemoveGroup(groupId int) string {
|
|||||||
func (a *App) GetStockKLine(stockCode, stockName string, days int64) *[]data.KLineData {
|
func (a *App) GetStockKLine(stockCode, stockName string, days int64) *[]data.KLineData {
|
||||||
return data.NewStockDataApi().GetHK_KLineData(stockCode, "day", days)
|
return data.NewStockDataApi().GetHK_KLineData(stockCode, "day", days)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) GetStockMinutePriceLineData(stockCode, stockName string) map[string]any {
|
||||||
|
res := make(map[string]any, 4)
|
||||||
|
priceData, date := data.NewStockDataApi().GetStockMinutePriceData(stockCode)
|
||||||
|
res["priceData"] = priceData
|
||||||
|
res["date"] = date
|
||||||
|
res["stockName"] = stockName
|
||||||
|
res["stockCode"] = stockCode
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) GetStockCommonKLine(stockCode, stockName string, days int64) *[]data.KLineData {
|
func (a *App) GetStockCommonKLine(stockCode, stockName string, days int64) *[]data.KLineData {
|
||||||
return data.NewStockDataApi().GetCommonKLineData(stockCode, "day", days)
|
return data.NewStockDataApi().GetCommonKLineData(stockCode, "day", days)
|
||||||
}
|
}
|
||||||
|
@ -1235,6 +1235,66 @@ func CheckBrowserOnWindows() (string, bool) {
|
|||||||
return path + "\\msedge.exe", true
|
return path + "\\msedge.exe", true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 分时数据
|
||||||
|
func (receiver StockDataApi) GetStockMinutePriceData(stockCode string) (*[]MinuteData, string) {
|
||||||
|
url := fmt.Sprintf("https://web.ifzq.gtimg.cn/appstock/app/minute/query?code=%s", stockCode)
|
||||||
|
if strutil.HasPrefixAny(stockCode, []string{"gb_", "GB_"}) {
|
||||||
|
stockCode = strings.Replace(strings.ToUpper(stockCode), "GB_", "us", 1) + ".OQ"
|
||||||
|
}
|
||||||
|
if strutil.HasPrefixAny(stockCode, []string{"us", "US"}) {
|
||||||
|
url = fmt.Sprintf("https://web.ifzq.gtimg.cn/appstock/app/UsMinute/query?code=%s", stockCode)
|
||||||
|
}
|
||||||
|
logger.SugaredLogger.Infof("GetStockMinutePriceData url:%s", url)
|
||||||
|
res := make(map[string]interface{})
|
||||||
|
resp, err := receiver.client.SetTimeout(time.Duration(receiver.config.CrawlTimeOut)*time.Second).R().
|
||||||
|
SetHeader("Host", "web.ifzq.gtimg.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(url)
|
||||||
|
|
||||||
|
date := ""
|
||||||
|
minuteDatas := &[]MinuteData{}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.SugaredLogger.Errorf("err:%s", err.Error())
|
||||||
|
return minuteDatas, date
|
||||||
|
}
|
||||||
|
//logger.SugaredLogger.Infof("resp:%s", resp.Body())
|
||||||
|
json.Unmarshal(resp.Body(), &res)
|
||||||
|
code, _ := convertor.ToInt(res["code"])
|
||||||
|
if res["data"] != nil && code == 0 {
|
||||||
|
data := res["data"].(map[string]interface{})
|
||||||
|
if stockData, ok := data[stockCode]; ok {
|
||||||
|
m := stockData.(map[string]interface{})
|
||||||
|
if d, ok := m["data"]; ok {
|
||||||
|
if m2, ok := d.(map[string]any); ok {
|
||||||
|
minutePriceData := m2["data"]
|
||||||
|
datas := minutePriceData.([]any)
|
||||||
|
for _, item := range datas {
|
||||||
|
minuteDataSplit := strutil.SplitEx(strutil.ReplaceWithMap(item.(string), map[string]string{
|
||||||
|
"\r\n": " ",
|
||||||
|
}), " ", true)
|
||||||
|
price, _ := convertor.ToFloat(minuteDataSplit[1])
|
||||||
|
volume, _ := convertor.ToFloat(minuteDataSplit[2])
|
||||||
|
amount := float64(0)
|
||||||
|
if len(minuteDataSplit) >= 4 {
|
||||||
|
amount, _ = convertor.ToFloat(minuteDataSplit[3])
|
||||||
|
}
|
||||||
|
minuteData := &MinuteData{
|
||||||
|
Time: minuteDataSplit[0][0:2] + ":" + minuteDataSplit[0][2:4],
|
||||||
|
Price: price,
|
||||||
|
Volume: volume,
|
||||||
|
Amount: amount,
|
||||||
|
}
|
||||||
|
*minuteDatas = append(*minuteDatas, *minuteData)
|
||||||
|
}
|
||||||
|
date = m2["date"].(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return minuteDatas, date
|
||||||
|
}
|
||||||
|
|
||||||
func (receiver StockDataApi) GetKLineData(stockCode string, kLineType string, days int64) *[]KLineData {
|
func (receiver StockDataApi) GetKLineData(stockCode string, kLineType string, days int64) *[]KLineData {
|
||||||
url := fmt.Sprintf("http://quotes.sina.cn/cn/api/json_v2.php/CN_MarketDataService.getKLineData?symbol=%s&scale=%s&ma=yes&datalen=%d", stockCode, kLineType, days)
|
url := fmt.Sprintf("http://quotes.sina.cn/cn/api/json_v2.php/CN_MarketDataService.getKLineData?symbol=%s&scale=%s&ma=yes&datalen=%d", stockCode, kLineType, days)
|
||||||
K := &[]KLineData{}
|
K := &[]KLineData{}
|
||||||
@ -1592,3 +1652,10 @@ type KLineData struct {
|
|||||||
Close string `json:"close"`
|
Close string `json:"close"`
|
||||||
Volume string `json:"volume"`
|
Volume string `json:"volume"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MinuteData struct {
|
||||||
|
Time string `json:"time"`
|
||||||
|
Price float64 `json:"price"`
|
||||||
|
Volume float64 `json:"volume"`
|
||||||
|
Amount float64 `json:"amount"`
|
||||||
|
}
|
||||||
|
@ -70,7 +70,12 @@ func TestSearchStockPriceInfo(t *testing.T) {
|
|||||||
//getZSInfo("沪深300指数", "sh000300", 30)
|
//getZSInfo("沪深300指数", "sh000300", 30)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
func TestGetStockMinutePriceData(t *testing.T) {
|
||||||
|
db.Init("../../data/stock.db")
|
||||||
|
data, date := NewStockDataApi().GetStockMinutePriceData("usTSLA.OQ")
|
||||||
|
logger.SugaredLogger.Infof("date:%s", date)
|
||||||
|
logger.SugaredLogger.Infof("%+#v", *data)
|
||||||
|
}
|
||||||
func TestGetKLineData(t *testing.T) {
|
func TestGetKLineData(t *testing.T) {
|
||||||
db.Init("../../data/stock.db")
|
db.Init("../../data/stock.db")
|
||||||
k := NewStockDataApi().GetKLineData("sh600171", "240", 30)
|
k := NewStockDataApi().GetKLineData("sh600171", "240", 30)
|
||||||
|
@ -96,7 +96,7 @@ function handleKLine(code,name){
|
|||||||
color: darkTheme?'#ccc':'#456'
|
color: darkTheme?'#ccc':'#456'
|
||||||
},
|
},
|
||||||
formatter: function (params) {//修改鼠标划过显示为中文
|
formatter: function (params) {//修改鼠标划过显示为中文
|
||||||
console.log("params",params)
|
//console.log("params",params)
|
||||||
let currentItemData = _.filter(params, (param) => param.seriesIndex === 0)[0].data;
|
let currentItemData = _.filter(params, (param) => param.seriesIndex === 0)[0].data;
|
||||||
let ma5=_.filter(params, (param) => param.seriesIndex === 1)[0].data;//ma5的值
|
let ma5=_.filter(params, (param) => param.seriesIndex === 1)[0].data;//ma5的值
|
||||||
let ma10=_.filter(params, (param) => param.seriesIndex === 2)[0].data;//ma10的值
|
let ma10=_.filter(params, (param) => param.seriesIndex === 2)[0].data;//ma10的值
|
||||||
@ -354,6 +354,10 @@ function handleKLine(code,name){
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
chart.setOption(option);
|
chart.setOption(option);
|
||||||
|
|
||||||
|
chart.on('click',{seriesName:'日K'}, function(params) {
|
||||||
|
console.log("click:",params);
|
||||||
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function calculateMA(dayCount,values) {
|
function calculateMA(dayCount,values) {
|
||||||
|
@ -23,7 +23,7 @@ import {
|
|||||||
AddGroup,
|
AddGroup,
|
||||||
GetGroupList,
|
GetGroupList,
|
||||||
AddStockGroup,
|
AddStockGroup,
|
||||||
RemoveStockGroup, RemoveGroup,GetStockKLine
|
RemoveStockGroup, RemoveGroup, GetStockKLine, GetStockMinutePriceLineData
|
||||||
} from '../../wailsjs/go/main/App'
|
} from '../../wailsjs/go/main/App'
|
||||||
import {
|
import {
|
||||||
NAvatar,
|
NAvatar,
|
||||||
@ -66,6 +66,7 @@ const upBorderColor = '';
|
|||||||
const downColor = '#00da3c';
|
const downColor = '#00da3c';
|
||||||
const downBorderColor = '';
|
const downBorderColor = '';
|
||||||
const kLineChartRef = ref(null);
|
const kLineChartRef = ref(null);
|
||||||
|
const kLineChartRef2 = ref(null);
|
||||||
|
|
||||||
|
|
||||||
const handleProgress = (progress) => {
|
const handleProgress = (progress) => {
|
||||||
@ -600,6 +601,103 @@ function showFenshi(code,name){
|
|||||||
}
|
}
|
||||||
|
|
||||||
modalShow2.value=true
|
modalShow2.value=true
|
||||||
|
|
||||||
|
GetStockMinutePriceLineData(code,name).then(result => {
|
||||||
|
console.log("GetStockMinutePriceLineData",result)
|
||||||
|
const priceData=result.priceData
|
||||||
|
const chart = echarts.init(kLineChartRef2.value);
|
||||||
|
let category=[]
|
||||||
|
let price=[]
|
||||||
|
let volume=[]
|
||||||
|
let min=0
|
||||||
|
let max=0
|
||||||
|
for (let i = 0; i < priceData.length; i++) {
|
||||||
|
category.push(priceData[i].time)
|
||||||
|
price.push(priceData[i].price)
|
||||||
|
if(min===0||min>priceData[i].price){
|
||||||
|
min=priceData[i].price
|
||||||
|
}
|
||||||
|
if(max<priceData[i].price){
|
||||||
|
max=priceData[i].price
|
||||||
|
}
|
||||||
|
if(i>0){
|
||||||
|
volume.push(priceData[i].volume-priceData[i-1].volume)
|
||||||
|
}else{
|
||||||
|
volume.push(priceData[i].volume)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let option = {
|
||||||
|
title: {
|
||||||
|
text: result.date,
|
||||||
|
left: 'center',
|
||||||
|
textStyle: {
|
||||||
|
color: data.darkTheme?'#ccc':'#456'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['股价', '成交量'],
|
||||||
|
textStyle: {
|
||||||
|
color: data.darkTheme?'#ccc':'#456'
|
||||||
|
},
|
||||||
|
right: 20,
|
||||||
|
},
|
||||||
|
darkMode: data.darkTheme,
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'cross',
|
||||||
|
animation: false,
|
||||||
|
label: {
|
||||||
|
backgroundColor: '#505765'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: category
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
name:"股价",
|
||||||
|
min: min-1,
|
||||||
|
max: max+1,
|
||||||
|
minInterval:0.01,
|
||||||
|
type: 'value'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name:"成交量",
|
||||||
|
type: 'value',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name:"股价",
|
||||||
|
data: price,
|
||||||
|
type: 'line',
|
||||||
|
smooth: false,
|
||||||
|
showSymbol: false,
|
||||||
|
markPoint: {
|
||||||
|
data: [
|
||||||
|
{ type: 'max', name: 'Max' },
|
||||||
|
{ type: 'min', name: 'Min' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
markLine: {
|
||||||
|
data: [{ type: 'average', name: 'Avg' }]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
yAxisIndex: 1,
|
||||||
|
name:"成交量",
|
||||||
|
data: volume,
|
||||||
|
type: 'bar',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
chart.setOption(option);
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateMA(dayCount,values) {
|
function calculateMA(dayCount,values) {
|
||||||
@ -670,7 +768,7 @@ function handleKLine(){
|
|||||||
color: data.darkTheme?'#ccc':'#456'
|
color: data.darkTheme?'#ccc':'#456'
|
||||||
},
|
},
|
||||||
formatter: function (params) {//修改鼠标划过显示为中文
|
formatter: function (params) {//修改鼠标划过显示为中文
|
||||||
console.log("params",params)
|
//console.log("params",params)
|
||||||
let volum=params[5].data;//ma5的值
|
let volum=params[5].data;//ma5的值
|
||||||
let ma5=params[1].data;//ma5的值
|
let ma5=params[1].data;//ma5的值
|
||||||
let ma10=params[2].data;//ma10的值
|
let ma10=params[2].data;//ma10的值
|
||||||
@ -937,6 +1035,9 @@ function handleKLine(){
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
chart.setOption(option);
|
chart.setOption(option);
|
||||||
|
chart.on('click',{seriesName:'日K'}, function(params) {
|
||||||
|
console.log("click:",params);
|
||||||
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function showK(code,name){
|
function showK(code,name){
|
||||||
@ -1534,8 +1635,9 @@ function delStockGroup(code,name,groupId){
|
|||||||
</n-flex>
|
</n-flex>
|
||||||
</template>
|
</template>
|
||||||
</n-modal>
|
</n-modal>
|
||||||
<n-modal v-model:show="modalShow2" :title="data.name" style="width: 600px" :preset="'card'">
|
<n-modal v-model:show="modalShow2" :title="data.name" style="width: 900px" :preset="'card'">
|
||||||
<n-image :src="data.fenshiURL" />
|
<!-- <n-image :src="data.fenshiURL" />-->
|
||||||
|
<div ref="kLineChartRef2" style="width: 850px; height: 500px;"></div>
|
||||||
</n-modal>
|
</n-modal>
|
||||||
<n-modal v-model:show="modalShow3" :title="data.name" style="width: 900px" :preset="'card'" @after-enter="handleKLine">
|
<n-modal v-model:show="modalShow3" :title="data.name" style="width: 900px" :preset="'card'" @after-enter="handleKLine">
|
||||||
<!-- <n-image :src="data.kURL" />-->
|
<!-- <n-image :src="data.kURL" />-->
|
||||||
|
2
frontend/wailsjs/go/main/App.d.ts
vendored
2
frontend/wailsjs/go/main/App.d.ts
vendored
@ -41,6 +41,8 @@ export function GetStockKLine(arg1:string,arg2:string,arg3:number):Promise<any>;
|
|||||||
|
|
||||||
export function GetStockList(arg1:string):Promise<Array<data.StockBasic>>;
|
export function GetStockList(arg1:string):Promise<Array<data.StockBasic>>;
|
||||||
|
|
||||||
|
export function GetStockMinutePriceLineData(arg1:string,arg2:string):Promise<Record<string, any>>;
|
||||||
|
|
||||||
export function GetTelegraphList(arg1:string):Promise<any>;
|
export function GetTelegraphList(arg1:string):Promise<any>;
|
||||||
|
|
||||||
export function GetVersionInfo():Promise<models.VersionInfo>;
|
export function GetVersionInfo():Promise<models.VersionInfo>;
|
||||||
|
@ -78,6 +78,10 @@ export function GetStockList(arg1) {
|
|||||||
return window['go']['main']['App']['GetStockList'](arg1);
|
return window['go']['main']['App']['GetStockList'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function GetStockMinutePriceLineData(arg1, arg2) {
|
||||||
|
return window['go']['main']['App']['GetStockMinutePriceLineData'](arg1, arg2);
|
||||||
|
}
|
||||||
|
|
||||||
export function GetTelegraphList(arg1) {
|
export function GetTelegraphList(arg1) {
|
||||||
return window['go']['main']['App']['GetTelegraphList'](arg1);
|
return window['go']['main']['App']['GetTelegraphList'](arg1);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user