mirror of
https://github.com/ArvinLovegood/go-stock.git
synced 2025-07-19 00:00:09 +08:00
feat(data):替换A股K线数据源(不再强制依赖Tushare)
- 新增 GetKLineData 方法,用于获取指定股票的 K线数据 - 实现了将 JSON 数据转换为 Markdown 表格的函数 JSONToMarkdownTable- 在 NewChatStream 中添加了对 A 股 K线数据的获取和展示逻辑- 增加了相关测试用例
This commit is contained in:
parent
fdaa80777d
commit
2ae3893325
@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
"github.com/chromedp/chromedp"
|
"github.com/chromedp/chromedp"
|
||||||
|
"github.com/duke-git/lancet/v2/convertor"
|
||||||
"github.com/duke-git/lancet/v2/strutil"
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||||
@ -133,6 +134,15 @@ func (o OpenAi) NewChatStream(stock, stockCode, userQuestion string, sysPromptId
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msg = append(msg, map[string]interface{}{
|
||||||
|
"role": "user",
|
||||||
|
"content": "当前时间",
|
||||||
|
})
|
||||||
|
msg = append(msg, map[string]interface{}{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "当前本地时间是:" + time.Now().Format("2006-01-02 15:04:05"),
|
||||||
|
})
|
||||||
|
|
||||||
question := ""
|
question := ""
|
||||||
if userQuestion == "" {
|
if userQuestion == "" {
|
||||||
replaceTemplates := map[string]string{
|
replaceTemplates := map[string]string{
|
||||||
@ -180,21 +190,49 @@ func (o OpenAi) NewChatStream(stock, stockCode, userQuestion string, sysPromptId
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
endDate := time.Now().Format("20060102")
|
//endDate := time.Now().Format("20060102")
|
||||||
startDate := time.Now().Add(-time.Hour * time.Duration(24*o.KDays)).Format("20060102")
|
//startDate := time.Now().Add(-time.Hour * time.Duration(24*o.KDays)).Format("20060102")
|
||||||
code := stockCode
|
//code := stockCode
|
||||||
if strutil.HasPrefixAny(stockCode, []string{"hk", "sz", "sh"}) {
|
//if strutil.HasPrefixAny(stockCode, []string{"hk"}) {
|
||||||
code = ConvertStockCodeToTushareCode(stockCode)
|
// code = ConvertStockCodeToTushareCode(stockCode)
|
||||||
|
// K := NewTushareApi(GetConfig()).GetDaily(code, startDate, endDate, o.CrawlTimeOut)
|
||||||
|
// msg = append(msg, map[string]interface{}{
|
||||||
|
// "role": "user",
|
||||||
|
// "content": stock + "日K数据",
|
||||||
|
// })
|
||||||
|
// msg = append(msg, map[string]interface{}{
|
||||||
|
// "role": "assistant",
|
||||||
|
// "content": stock + "日K数据如下:\n" + K,
|
||||||
|
// })
|
||||||
|
//}
|
||||||
|
|
||||||
|
if strutil.HasPrefixAny(stockCode, []string{"sz", "sh"}) {
|
||||||
|
K := NewStockDataApi().GetKLineData(stockCode, "240", o.KDays)
|
||||||
|
Kmap := &[]map[string]any{}
|
||||||
|
for _, kline := range *K {
|
||||||
|
mapk := make(map[string]any, 6)
|
||||||
|
mapk["日期"] = kline.Day
|
||||||
|
mapk["开盘价"] = kline.Open
|
||||||
|
mapk["最高价"] = kline.High
|
||||||
|
mapk["最低价"] = kline.Low
|
||||||
|
mapk["收盘价"] = kline.Close
|
||||||
|
Volume, _ := convertor.ToFloat(kline.Volume)
|
||||||
|
mapk["成交量(万手)"] = Volume / 10000.00 / 100.00
|
||||||
|
*Kmap = append(*Kmap, mapk)
|
||||||
|
}
|
||||||
|
jsonData, _ := json.Marshal(Kmap)
|
||||||
|
markdownTable, _ := JSONToMarkdownTable(jsonData)
|
||||||
|
msg = append(msg, map[string]interface{}{
|
||||||
|
"role": "user",
|
||||||
|
"content": stock + "日K数据",
|
||||||
|
})
|
||||||
|
msg = append(msg, map[string]interface{}{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "## " + stock + "日K数据如下:\n" + markdownTable,
|
||||||
|
})
|
||||||
|
logger.SugaredLogger.Infof("getKLineData=\n%s", markdownTable)
|
||||||
}
|
}
|
||||||
K := NewTushareApi(GetConfig()).GetDaily(code, startDate, endDate, o.CrawlTimeOut)
|
|
||||||
msg = append(msg, map[string]interface{}{
|
|
||||||
"role": "user",
|
|
||||||
"content": stock + "日K数据",
|
|
||||||
})
|
|
||||||
msg = append(msg, map[string]interface{}{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": stock + "日K数据如下:\n" + K,
|
|
||||||
})
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
func TestNewDeepSeekOpenAiConfig(t *testing.T) {
|
func TestNewDeepSeekOpenAiConfig(t *testing.T) {
|
||||||
db.Init("../../data/stock.db")
|
db.Init("../../data/stock.db")
|
||||||
ai := NewDeepSeekOpenAi(context.TODO())
|
ai := NewDeepSeekOpenAi(context.TODO())
|
||||||
res := ai.NewChatStream("中信证券", "hk06030", "中信证券分析和总结", nil)
|
res := ai.NewChatStream("长电科技", "sh600584", "长电科技分析和总结", nil)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case msg := <-res:
|
case msg := <-res:
|
||||||
|
@ -1075,3 +1075,73 @@ func CheckBrowserOnWindows() (string, bool) {
|
|||||||
}
|
}
|
||||||
return path + "\\msedge.exe", true
|
return path + "\\msedge.exe", true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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&days=%d", stockCode, kLineType, days)
|
||||||
|
K := &[]KLineData{}
|
||||||
|
_, err := receiver.client.SetTimeout(time.Duration(receiver.config.CrawlTimeOut)*time.Second).R().
|
||||||
|
SetHeader("Host", "quotes.sina.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").
|
||||||
|
SetResult(K).
|
||||||
|
Get(url)
|
||||||
|
if err != nil {
|
||||||
|
logger.SugaredLogger.Errorf("err:%s", err.Error())
|
||||||
|
return K
|
||||||
|
}
|
||||||
|
return K
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONToMarkdownTable 将JSON数据转换为Markdown表格
|
||||||
|
func JSONToMarkdownTable(jsonData []byte) (string, error) {
|
||||||
|
var data []map[string]interface{}
|
||||||
|
err := json.Unmarshal(jsonData, &data)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data) == 0 {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取表头
|
||||||
|
headers := []string{}
|
||||||
|
for key := range data[0] {
|
||||||
|
headers = append(headers, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建表头行
|
||||||
|
headerRow := "|"
|
||||||
|
for _, header := range headers {
|
||||||
|
headerRow += fmt.Sprintf(" %s |", header)
|
||||||
|
}
|
||||||
|
headerRow += "\n"
|
||||||
|
|
||||||
|
// 构建分隔行
|
||||||
|
separatorRow := "|"
|
||||||
|
for range headers {
|
||||||
|
separatorRow += " --- |"
|
||||||
|
}
|
||||||
|
separatorRow += "\n"
|
||||||
|
|
||||||
|
// 构建数据行
|
||||||
|
bodyRows := ""
|
||||||
|
for _, rowData := range data {
|
||||||
|
bodyRow := "|"
|
||||||
|
for _, header := range headers {
|
||||||
|
value := rowData[header]
|
||||||
|
bodyRow += fmt.Sprintf(" %v |", value)
|
||||||
|
}
|
||||||
|
bodyRows += bodyRow + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
return headerRow + separatorRow + bodyRows, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type KLineData struct {
|
||||||
|
Day string `json:"day"`
|
||||||
|
Open string `json:"open"`
|
||||||
|
High string `json:"high"`
|
||||||
|
Low string `json:"low"`
|
||||||
|
Close string `json:"close"`
|
||||||
|
Volume string `json:"volume"`
|
||||||
|
}
|
||||||
|
@ -57,6 +57,21 @@ func TestSearchStockPriceInfo(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetKLineData(t *testing.T) {
|
||||||
|
db.Init("../../data/stock.db")
|
||||||
|
k := NewStockDataApi().GetKLineData("sh600171", "240", 30)
|
||||||
|
//for _, kline := range *k {
|
||||||
|
// logger.SugaredLogger.Infof("%+#v", kline)
|
||||||
|
//}
|
||||||
|
jsonData, _ := json.Marshal(*k)
|
||||||
|
markdownTable, err := JSONToMarkdownTable(jsonData)
|
||||||
|
if err != nil {
|
||||||
|
logger.SugaredLogger.Errorf("json.Marshal error:%s", err.Error())
|
||||||
|
}
|
||||||
|
logger.SugaredLogger.Infof("markdownTable:\n%s", markdownTable)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetRealTimeStockPriceInfo(t *testing.T) {
|
func TestGetRealTimeStockPriceInfo(t *testing.T) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user