diff --git a/app.go b/app.go index 9e43b4e..13e3a59 100644 --- a/app.go +++ b/app.go @@ -1065,6 +1065,17 @@ func (a *App) RemoveGroup(groupId int) string { func (a *App) GetStockKLine(stockCode, stockName string, days int64) *[]data.KLineData { 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 { return data.NewStockDataApi().GetCommonKLineData(stockCode, "day", days) } diff --git a/backend/data/stock_data_api.go b/backend/data/stock_data_api.go index 8a91497..d4a134a 100644 --- a/backend/data/stock_data_api.go +++ b/backend/data/stock_data_api.go @@ -1235,6 +1235,66 @@ func CheckBrowserOnWindows() (string, bool) { 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 { 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{} @@ -1592,3 +1652,10 @@ type KLineData struct { Close string `json:"close"` Volume string `json:"volume"` } + +type MinuteData struct { + Time string `json:"time"` + Price float64 `json:"price"` + Volume float64 `json:"volume"` + Amount float64 `json:"amount"` +} diff --git a/backend/data/stock_data_api_test.go b/backend/data/stock_data_api_test.go index 806c853..45c0303 100644 --- a/backend/data/stock_data_api_test.go +++ b/backend/data/stock_data_api_test.go @@ -70,7 +70,12 @@ func TestSearchStockPriceInfo(t *testing.T) { //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) { db.Init("../../data/stock.db") k := NewStockDataApi().GetKLineData("sh600171", "240", 30) diff --git a/frontend/src/components/KLineChart.vue b/frontend/src/components/KLineChart.vue index 105eeea..ae2ab30 100644 --- a/frontend/src/components/KLineChart.vue +++ b/frontend/src/components/KLineChart.vue @@ -96,7 +96,7 @@ function handleKLine(code,name){ color: darkTheme?'#ccc':'#456' }, formatter: function (params) {//修改鼠标划过显示为中文 - console.log("params",params) + //console.log("params",params) let currentItemData = _.filter(params, (param) => param.seriesIndex === 0)[0].data; let ma5=_.filter(params, (param) => param.seriesIndex === 1)[0].data;//ma5的值 let ma10=_.filter(params, (param) => param.seriesIndex === 2)[0].data;//ma10的值 @@ -354,6 +354,10 @@ function handleKLine(code,name){ ] }; chart.setOption(option); + + chart.on('click',{seriesName:'日K'}, function(params) { + console.log("click:",params); + }); }) } function calculateMA(dayCount,values) { diff --git a/frontend/src/components/stock.vue b/frontend/src/components/stock.vue index 44d5a9a..174a35a 100644 --- a/frontend/src/components/stock.vue +++ b/frontend/src/components/stock.vue @@ -23,7 +23,7 @@ import { AddGroup, GetGroupList, AddStockGroup, - RemoveStockGroup, RemoveGroup,GetStockKLine + RemoveStockGroup, RemoveGroup, GetStockKLine, GetStockMinutePriceLineData } from '../../wailsjs/go/main/App' import { NAvatar, @@ -66,6 +66,7 @@ const upBorderColor = ''; const downColor = '#00da3c'; const downBorderColor = ''; const kLineChartRef = ref(null); +const kLineChartRef2 = ref(null); const handleProgress = (progress) => { @@ -600,6 +601,103 @@ function showFenshi(code,name){ } 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(max0){ + 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) { @@ -670,7 +768,7 @@ function handleKLine(){ color: data.darkTheme?'#ccc':'#456' }, formatter: function (params) {//修改鼠标划过显示为中文 - console.log("params",params) + //console.log("params",params) let volum=params[5].data;//ma5的值 let ma5=params[1].data;//ma5的值 let ma10=params[2].data;//ma10的值 @@ -937,6 +1035,9 @@ function handleKLine(){ ] }; chart.setOption(option); + chart.on('click',{seriesName:'日K'}, function(params) { + console.log("click:",params); + }); }) } function showK(code,name){ @@ -1534,8 +1635,9 @@ function delStockGroup(code,name,groupId){ - - + + +
diff --git a/frontend/wailsjs/go/main/App.d.ts b/frontend/wailsjs/go/main/App.d.ts index 8e944ad..a93ba02 100644 --- a/frontend/wailsjs/go/main/App.d.ts +++ b/frontend/wailsjs/go/main/App.d.ts @@ -41,6 +41,8 @@ export function GetStockKLine(arg1:string,arg2:string,arg3:number):Promise; export function GetStockList(arg1:string):Promise>; +export function GetStockMinutePriceLineData(arg1:string,arg2:string):Promise>; + export function GetTelegraphList(arg1:string):Promise; export function GetVersionInfo():Promise; diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js index 1a528e5..53258cc 100644 --- a/frontend/wailsjs/go/main/App.js +++ b/frontend/wailsjs/go/main/App.js @@ -78,6 +78,10 @@ export function 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) { return window['go']['main']['App']['GetTelegraphList'](arg1); }