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"
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/chromedp/chromedp"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"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 := ""
|
||||
if userQuestion == "" {
|
||||
replaceTemplates := map[string]string{
|
||||
@ -180,21 +190,49 @@ func (o OpenAi) NewChatStream(stock, stockCode, userQuestion string, sysPromptId
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
endDate := time.Now().Format("20060102")
|
||||
startDate := time.Now().Add(-time.Hour * time.Duration(24*o.KDays)).Format("20060102")
|
||||
code := stockCode
|
||||
if strutil.HasPrefixAny(stockCode, []string{"hk", "sz", "sh"}) {
|
||||
code = ConvertStockCodeToTushareCode(stockCode)
|
||||
//endDate := time.Now().Format("20060102")
|
||||
//startDate := time.Now().Add(-time.Hour * time.Duration(24*o.KDays)).Format("20060102")
|
||||
//code := stockCode
|
||||
//if strutil.HasPrefixAny(stockCode, []string{"hk"}) {
|
||||
// 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() {
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
func TestNewDeepSeekOpenAiConfig(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
ai := NewDeepSeekOpenAi(context.TODO())
|
||||
res := ai.NewChatStream("中信证券", "hk06030", "中信证券分析和总结", nil)
|
||||
res := ai.NewChatStream("长电科技", "sh600584", "长电科技分析和总结", nil)
|
||||
for {
|
||||
select {
|
||||
case msg := <-res:
|
||||
|
@ -1075,3 +1075,73 @@ func CheckBrowserOnWindows() (string, bool) {
|
||||
}
|
||||
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) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
Loading…
x
Reference in New Issue
Block a user