From b2b0300aa1c38edd56c8ecfe6e6168178da9d0c7 Mon Sep 17 00:00:00 2001 From: ArvinLovegood Date: Fri, 28 Feb 2025 17:38:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(data):=E5=A2=9E=E5=8A=A0=E5=AF=B9=E7=BE=8E?= =?UTF-8?q?=E8=82=A1=E6=95=B0=E6=8D=AE=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 getUSStockPriceInfo 函数用于获取美股实时行情信息 - 修改 SearchStockPriceInfo 函数,支持美股代码查询 - 更新 Tushare 数据接口,增加对美股每日数据的支持 - 优化股票代码处理逻辑,兼容不同市场代码格式 --- backend/data/openai_api.go | 6 ++- backend/data/stock_data_api.go | 65 ++++++++++++++++++++++++--- backend/data/stock_data_api_test.go | 4 +- backend/data/tushare_data_api.go | 18 +++++++- backend/data/tushare_data_api_test.go | 11 +++++ 5 files changed, 95 insertions(+), 9 deletions(-) diff --git a/backend/data/openai_api.go b/backend/data/openai_api.go index c92cae0..96e0151 100644 --- a/backend/data/openai_api.go +++ b/backend/data/openai_api.go @@ -152,7 +152,11 @@ func (o OpenAi) NewChatStream(stock, stockCode, userQuestion string) <-chan map[ defer wg.Done() endDate := time.Now().Format("20060102") startDate := time.Now().Add(-time.Hour * time.Duration(24*o.KDays)).Format("20060102") - K := NewTushareApi(getConfig()).GetDaily(ConvertStockCodeToTushareCode(stockCode), startDate, endDate, o.CrawlTimeOut) + code := stockCode + if strutil.HasPrefixAny(stockCode, []string{"hk", "sz", "sh"}) { + code = ConvertStockCodeToTushareCode(stockCode) + } + K := NewTushareApi(getConfig()).GetDaily(code, startDate, endDate, o.CrawlTimeOut) msg = append(msg, map[string]interface{}{ "role": "assistant", "content": stock + "日K数据如下:\n" + K, diff --git a/backend/data/stock_data_api.go b/backend/data/stock_data_api.go index 89c6329..3845758 100644 --- a/backend/data/stock_data_api.go +++ b/backend/data/stock_data_api.go @@ -534,7 +534,7 @@ func ParseUSStockData(datas []string) (map[string]string, error) { result["当前价格"] = parts[1] result["日期"] = strutil.SplitAndTrim(parts[3], " ", "")[0] result["时间"] = strutil.SplitAndTrim(parts[3], " ", "")[1] - logger.SugaredLogger.Infof("美股股票数据解析完成: %v", result) + //logger.SugaredLogger.Infof("美股股票数据解析完成: %v", result) return result, nil } @@ -576,7 +576,7 @@ func ParseHKStockData(datas []string) (map[string]string, error) { result["当前价格"] = parts[6] result["日期"] = strings.ReplaceAll(parts[17], "/", "-") result["时间"] = strings.ReplaceAll(parts[18], "\";", ":00") - logger.SugaredLogger.Infof("股票数据解析完成: %v", result) + //logger.SugaredLogger.Infof("股票数据解析完成: %v", result) return result, nil } @@ -712,15 +712,70 @@ func GetRealTimeStockPriceInfo(ctx context.Context, stockCode string) (price, pr func SearchStockPriceInfo(stockCode string, crawlTimeOut int64) *[]string { - if strutil.HasPrefixAny(stockCode, []string{"HK", "hk"}) { - return getHKStockPriceInfo(stockCode, crawlTimeOut) - } if strutil.HasPrefixAny(stockCode, []string{"SZ", "SH", "sh", "sz"}) { return getSHSZStockPriceInfo(stockCode, crawlTimeOut) } + if strutil.HasPrefixAny(stockCode, []string{"HK", "hk"}) { + return getHKStockPriceInfo(stockCode, crawlTimeOut) + } + if strutil.HasPrefixAny(stockCode, []string{"US", "us", "gb_"}) { + return getUSStockPriceInfo(stockCode, crawlTimeOut) + } return &[]string{} } +func getUSStockPriceInfo(stockCode string, crawlTimeOut int64) *[]string { + var messages []string + crawlerAPI := CrawlerApi{} + crawlerBaseInfo := CrawlerBaseInfo{ + Name: "SinaCrawler", + Description: "SinaCrawler Crawler Description", + BaseUrl: "https://stock.finance.sina.com.cn", + Headers: map[string]string{"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0"}, + } + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(crawlTimeOut)*time.Second) + defer cancel() + crawlerAPI = crawlerAPI.NewCrawler(ctx, crawlerBaseInfo) + + url := fmt.Sprintf("https://stock.finance.sina.com.cn/usstock/quotes/%s.html", strings.ReplaceAll(stockCode, "gb_", "")) + htmlContent, ok := crawlerAPI.GetHtml(url, "div#hqPrice", true) + if !ok { + return &[]string{} + } + document, err := goquery.NewDocumentFromReader(strings.NewReader(htmlContent)) + if err != nil { + logger.SugaredLogger.Error(err.Error()) + } + stockName := "" + stockPrice := "" + stockPriceTime := "" + document.Find("div.hq_title >h1").Each(func(i int, selection *goquery.Selection) { + stockName = strutil.RemoveNonPrintable(selection.Text()) + logger.SugaredLogger.Infof("股票名称-:%s", stockName) + }) + + document.Find("#hqPrice").Each(func(i int, selection *goquery.Selection) { + stockPrice = strutil.RemoveNonPrintable(selection.Text()) + logger.SugaredLogger.Infof("现价: %s", stockPrice) + }) + + document.Find("div.hq_time").Each(func(i int, selection *goquery.Selection) { + stockPriceTime = strutil.RemoveNonPrintable(selection.Text()) + logger.SugaredLogger.Infof("时间: %s", stockPriceTime) + }) + + messages = append(messages, fmt.Sprintf("%s:%s现价%s", stockPriceTime, stockName, stockPrice)) + logger.SugaredLogger.Infof("股票: %s", messages) + + document.Find("div#hqDetails >table tbody tr").Each(func(i int, selection *goquery.Selection) { + text := strutil.RemoveNonPrintable(selection.Text()) + logger.SugaredLogger.Infof("股票名称-%s: %s", stockName, text) + messages = append(messages, text) + }) + + return &messages +} + func getHKStockPriceInfo(stockCode string, crawlTimeOut int64) *[]string { var messages []string crawlerAPI := CrawlerApi{} diff --git a/backend/data/stock_data_api_test.go b/backend/data/stock_data_api_test.go index c191b44..e3ce168 100644 --- a/backend/data/stock_data_api_test.go +++ b/backend/data/stock_data_api_test.go @@ -47,7 +47,9 @@ func TestSearchStockInfoByCode(t *testing.T) { func TestSearchStockPriceInfo(t *testing.T) { //SearchStockPriceInfo("hk06030", 30) - SearchStockPriceInfo("sh600171", 30) + //SearchStockPriceInfo("sh600171", 30) + SearchStockPriceInfo("gb_aapl", 30) + } func TestGetRealTimeStockPriceInfo(t *testing.T) { diff --git a/backend/data/tushare_data_api.go b/backend/data/tushare_data_api.go index 88ab158..a959897 100644 --- a/backend/data/tushare_data_api.go +++ b/backend/data/tushare_data_api.go @@ -6,6 +6,7 @@ import ( "github.com/duke-git/lancet/v2/strutil" "github.com/go-resty/resty/v2" "go-stock/backend/logger" + "strings" "time" ) @@ -32,14 +33,15 @@ func (receiver TushareApi) GetDaily(tsCode, startDate, endDate string, crawlTime fields := "ts_code,trade_date,open,high,low,close,pre_close,change,pct_chg,vol,amount" resp := &TushareStockBasicResponse{} stockType := getStockType(tsCode) - logger.SugaredLogger.Debugf("tushare daily request: %s", stockType) + tsCodeNEW := getTsCode(tsCode) + logger.SugaredLogger.Debugf("tushare daily request: %s,tsCode:%s,tsCodeNEW:%s", stockType, tsCode, tsCodeNEW) _, err := receiver.client.SetTimeout(time.Duration(crawlTimeOut)*time.Second).R(). SetHeader("content-type", "application/json"). SetBody(&TushareRequest{ ApiName: stockType, Token: receiver.config.TushareToken, Params: map[string]any{ - "ts_code": tsCode, + "ts_code": tsCodeNEW, "start_date": startDate, "end_date": endDate, }, @@ -68,6 +70,15 @@ func (receiver TushareApi) GetDaily(tsCode, startDate, endDate string, crawlTime return res } +func getTsCode(code string) any { + if strutil.HasPrefixAny(code, []string{"US", "us", "gb_"}) { + code = strings.Replace(code, "gb_", "", 1) + code = strings.Replace(code, "us", "", 1) + return code + } + return code +} + func getStockType(code string) string { if strutil.HasSuffixAny(code, []string{"SZ", "SH", "sh", "sz"}) { return "daily" @@ -75,5 +86,8 @@ func getStockType(code string) string { if strutil.HasSuffixAny(code, []string{"HK", "hk"}) { return "hk_daily" } + if strutil.HasPrefixAny(code, []string{"US", "us", "gb_"}) { + return "us_daily" + } return "" } diff --git a/backend/data/tushare_data_api_test.go b/backend/data/tushare_data_api_test.go index 97c2aba..627e1bf 100644 --- a/backend/data/tushare_data_api_test.go +++ b/backend/data/tushare_data_api_test.go @@ -16,3 +16,14 @@ func TestGetDaily(t *testing.T) { t.Log(res) } + +func TestGetUSDaily(t *testing.T) { + db.Init("../../data/stock.db") + tushareApi := NewTushareApi(getConfig()) + + res := tushareApi.GetDaily("gb_AAPL", "20250101", "20250217", 30) + t.Log(res) + + // + +}