Compare commits
34 Commits
v2025.8.26
...
v2025.11.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
483ffa2244 | ||
|
|
63d278b9aa | ||
|
|
5621d40c71 | ||
|
|
26e9753b94 | ||
|
|
b7f6dbd2da | ||
|
|
18dd01b613 | ||
|
|
81bb33a135 | ||
|
|
9926b61fac | ||
|
|
5e975b060c | ||
|
|
e8f063fd9b | ||
|
|
8b0b53fae7 | ||
|
|
b29c380055 | ||
|
|
cf58a707c7 | ||
|
|
1ae1bb0116 | ||
|
|
d8971935ee | ||
|
|
9c68458b81 | ||
|
|
b367d1eb40 | ||
|
|
8fe79adbb1 | ||
|
|
1d81fdba87 | ||
|
|
6aca0e15cc | ||
|
|
173ce6f243 | ||
|
|
e7875e73d3 | ||
|
|
ca4727db80 | ||
|
|
84ffe7c5fd | ||
|
|
da02d1bd1c | ||
|
|
bae2bf9c5c | ||
|
|
6568b5949a | ||
|
|
c4287f9b78 | ||
|
|
87441d8923 | ||
|
|
ebd166e72b | ||
|
|
494a60debe | ||
|
|
b3e2565a02 | ||
|
|
c0a87d5d2e | ||
|
|
d74ad3c03d |
@@ -37,11 +37,9 @@
|
||||
| [LMStudio](https://lmstudio.ai/) | ✅ | 本地大模型运行平台 |
|
||||
| [AnythingLLM](https://anythingllm.com/) | ✅ | 本地知识库 |
|
||||
| [DeepSeek](https://www.deepseek.com/) | ✅ | deepseek-reasoner,deepseek-chat |
|
||||
| [大模型聚合平台](https://cloud.siliconflow.cn/i/foufCerk) | ✅ | 如:[302.AI](https://share.302.ai/1KUpfG),[硅基流动](https://cloud.siliconflow.cn/i/foufCerk),[火山方舟](https://www.volcengine.com/experience/ark?utm_term=202502dsinvite&ac=DSASUQY5&rc=IJSE43PZ) |
|
||||
| [大模型聚合平台](https://cloud.siliconflow.cn/i/foufCerk) | ✅ | 如:[硅基流动](https://cloud.siliconflow.cn/i/foufCerk),[火山方舟](https://www.volcengine.com/experience/ark?utm_term=202502dsinvite&ac=DSASUQY5&rc=IJSE43PZ) |
|
||||
|
||||
### <span style="color: #568DF4;">各位亲爱的朋友们,如果您对这个项目感兴趣,请先给我一个<i style="color: #EA2626;">star</i>吧,谢谢!</span>💕
|
||||
- 302.AI:新用户使用邀请码注册,即可领取 $1 测试额度
|
||||
|
||||
[//]: # (- 优云智算(by UCloud):万卡规模4090免费用10小时,新人注册另增50万tokens,海量热门源项目镜像一键部署,[注册链接](https://www.compshare.cn/image-community?ytag=GPU_YY-gh_gostock))
|
||||
- 火山方舟:新用户每个模型注册即送50万tokens,[注册链接](https://www.volcengine.com/experience/ark?utm_term=202502dsinvite&ac=DSASUQY5&rc=IJSE43PZ)
|
||||
- 硅基流动(siliconflow),注册即送2000万Tokens,[注册链接](https://cloud.siliconflow.cn/i/foufCerk)
|
||||
@@ -62,7 +60,7 @@
|
||||
| 功能说明 | 状态 | 备注 |
|
||||
|-----------------|----|----------------------------------------------------------------------------------------------------------|
|
||||
| 股票分析知识库 | 🚧 | 未来计划 |
|
||||
| Ai智能选股 | 🚧 | Ai智能选股功能开发中(下半年重点开发计划) |
|
||||
| Ai智能选股 | ✅ | Ai智能选股功能(市场行情-》AI总结/AI智能体功能) |
|
||||
| ETF支持 | 🚧 | ETF数据支持 (目前可以查看净值和估值) |
|
||||
| 美股支持 | ✅ | 美股数据支持 |
|
||||
| 港股支持 | ✅ | 港股数据支持 |
|
||||
|
||||
160
app.go
160
app.go
@@ -131,6 +131,50 @@ func AddTools(tools []data.Tool) []data.Tool {
|
||||
},
|
||||
})
|
||||
|
||||
//tools = append(tools, data.Tool{
|
||||
// Type: "function",
|
||||
// Function: data.ToolFunction{
|
||||
// Name: "QueryBKDictInfo",
|
||||
// Description: "获取所有板块/行业名称或者代码(bkCode,bkName)",
|
||||
// },
|
||||
//})
|
||||
|
||||
//tools = append(tools, data.Tool{
|
||||
// Type: "function",
|
||||
// Function: data.ToolFunction{
|
||||
// Name: "GetIndustryResearchReport",
|
||||
// Description: "获取行业/板块研究报告,请先使用QueryBKDictInfo工具获取行业代码,然后输入行业代码调用",
|
||||
// Parameters: data.FunctionParameters{
|
||||
// Type: "object",
|
||||
// Properties: map[string]any{
|
||||
// "bkCode": map[string]any{
|
||||
// "type": "string",
|
||||
// "description": "板块/行业代码",
|
||||
// },
|
||||
// },
|
||||
// Required: []string{"bkCode"},
|
||||
// },
|
||||
// },
|
||||
//})
|
||||
|
||||
tools = append(tools, data.Tool{
|
||||
Type: "function",
|
||||
Function: data.ToolFunction{
|
||||
Name: "GetStockResearchReport",
|
||||
Description: "获取股票的分析/研究报告",
|
||||
Parameters: data.FunctionParameters{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"stockCode": map[string]any{
|
||||
"type": "string",
|
||||
"description": "股票代码",
|
||||
},
|
||||
},
|
||||
Required: []string{"stockCode"},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return tools
|
||||
}
|
||||
|
||||
@@ -384,7 +428,8 @@ func (a *App) domReady(ctx context.Context) {
|
||||
a.cronEntrys["MonitorStockPrices"] = id
|
||||
}
|
||||
entryID, err := a.cron.AddFunc(fmt.Sprintf("@every %ds", interval+10), func() {
|
||||
news := data.NewMarketNewsApi().GetNewTelegraph(30)
|
||||
//news := data.NewMarketNewsApi().GetNewTelegraph(30)
|
||||
news := data.NewMarketNewsApi().TelegraphList(30)
|
||||
if config.EnablePushNews {
|
||||
go a.NewsPush(news)
|
||||
}
|
||||
@@ -465,11 +510,7 @@ func (a *App) domReady(ctx context.Context) {
|
||||
//检查新版本
|
||||
go func() {
|
||||
a.CheckUpdate(0)
|
||||
count := int64(0)
|
||||
db.Dao.Model(&data.StockBasic{}).Count(&count)
|
||||
if count <= 0 {
|
||||
go a.CheckStockBaseInfo(a.ctx)
|
||||
}
|
||||
go a.CheckStockBaseInfo(a.ctx)
|
||||
|
||||
a.cron.AddFunc("0 0 2 * * *", func() {
|
||||
logger.SugaredLogger.Errorf("Checking for updates...")
|
||||
@@ -524,60 +565,84 @@ func (a *App) CheckStockBaseInfo(ctx context.Context) {
|
||||
SetResult(stockBasics).
|
||||
Get("http://8.134.249.145:18080/go-stock/stock_basic.json")
|
||||
|
||||
for _, stock := range *stockBasics {
|
||||
stockInfo := &data.StockBasic{
|
||||
TsCode: stock.TsCode,
|
||||
Name: stock.Name,
|
||||
Symbol: stock.Symbol,
|
||||
BKCode: stock.BKCode,
|
||||
BKName: stock.BKName,
|
||||
}
|
||||
db.Dao.Model(&data.StockBasic{}).Where("ts_code = ?", stock.TsCode).First(stockInfo)
|
||||
if stockInfo.ID == 0 {
|
||||
db.Dao.Model(&data.StockBasic{}).Create(stockInfo)
|
||||
} else {
|
||||
db.Dao.Model(&data.StockBasic{}).Where("ts_code = ?", stock.TsCode).Updates(stockInfo)
|
||||
}
|
||||
db.Dao.Unscoped().Model(&data.StockBasic{}).Where("1=1").Delete(&data.StockBasic{})
|
||||
err := db.Dao.CreateInBatches(stockBasics, 400).Error
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("保存StockBasic股票基础信息失败:%s", err.Error())
|
||||
}
|
||||
|
||||
//count := int64(0)
|
||||
//db.Dao.Model(&data.StockBasic{}).Count(&count)
|
||||
//if count == int64(len(*stockBasics)) {
|
||||
// return
|
||||
//}
|
||||
//for _, stock := range *stockBasics {
|
||||
// stockInfo := &data.StockBasic{
|
||||
// TsCode: stock.TsCode,
|
||||
// Name: stock.Name,
|
||||
// Symbol: stock.Symbol,
|
||||
// BKCode: stock.BKCode,
|
||||
// BKName: stock.BKName,
|
||||
// }
|
||||
// db.Dao.Model(&data.StockBasic{}).Where("ts_code = ?", stock.TsCode).First(stockInfo)
|
||||
// if stockInfo.ID == 0 {
|
||||
// db.Dao.Model(&data.StockBasic{}).Create(stockInfo)
|
||||
// } else {
|
||||
// db.Dao.Model(&data.StockBasic{}).Where("ts_code = ?", stock.TsCode).Updates(stockInfo)
|
||||
// }
|
||||
//}
|
||||
|
||||
stockHKBasics := &[]models.StockInfoHK{}
|
||||
resty.New().R().
|
||||
SetHeader("user", "go-stock").
|
||||
SetResult(stockHKBasics).
|
||||
Get("http://8.134.249.145:18080/go-stock/stock_base_info_hk.json")
|
||||
for _, stock := range *stockHKBasics {
|
||||
stockInfo := &models.StockInfoHK{
|
||||
Code: stock.Code,
|
||||
Name: stock.Name,
|
||||
BKName: stock.BKName,
|
||||
BKCode: stock.BKCode,
|
||||
}
|
||||
db.Dao.Model(&models.StockInfoHK{}).Where("code = ?", stock.Code).First(stockInfo)
|
||||
if stockInfo.ID == 0 {
|
||||
db.Dao.Model(&models.StockInfoHK{}).Create(stockInfo)
|
||||
} else {
|
||||
db.Dao.Model(&models.StockInfoHK{}).Where("code = ?", stock.Code).Updates(stockInfo)
|
||||
}
|
||||
|
||||
db.Dao.Unscoped().Model(&models.StockInfoHK{}).Where("1=1").Delete(&models.StockInfoHK{})
|
||||
err = db.Dao.CreateInBatches(stockHKBasics, 400).Error
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("保存StockInfoHK股票基础信息失败:%s", err.Error())
|
||||
}
|
||||
|
||||
//for _, stock := range *stockHKBasics {
|
||||
// stockInfo := &models.StockInfoHK{
|
||||
// Code: stock.Code,
|
||||
// Name: stock.Name,
|
||||
// BKName: stock.BKName,
|
||||
// BKCode: stock.BKCode,
|
||||
// }
|
||||
// db.Dao.Model(&models.StockInfoHK{}).Where("code = ?", stock.Code).First(stockInfo)
|
||||
// if stockInfo.ID == 0 {
|
||||
// db.Dao.Model(&models.StockInfoHK{}).Create(stockInfo)
|
||||
// } else {
|
||||
// db.Dao.Model(&models.StockInfoHK{}).Where("code = ?", stock.Code).Updates(stockInfo)
|
||||
// }
|
||||
//}
|
||||
stockUSBasics := &[]models.StockInfoUS{}
|
||||
resty.New().R().
|
||||
SetHeader("user", "go-stock").
|
||||
SetResult(stockUSBasics).
|
||||
Get("http://8.134.249.145:18080/go-stock/stock_base_info_us.json")
|
||||
for _, stock := range *stockUSBasics {
|
||||
stockInfo := &models.StockInfoUS{
|
||||
Code: stock.Code,
|
||||
Name: stock.Name,
|
||||
BKName: stock.BKName,
|
||||
BKCode: stock.BKCode,
|
||||
}
|
||||
db.Dao.Model(&models.StockInfoUS{}).Where("code = ?", stock.Code).First(stockInfo)
|
||||
if stockInfo.ID == 0 {
|
||||
db.Dao.Model(&models.StockInfoUS{}).Create(stockInfo)
|
||||
} else {
|
||||
db.Dao.Model(&models.StockInfoUS{}).Where("code = ?", stock.Code).Updates(stockInfo)
|
||||
}
|
||||
|
||||
db.Dao.Unscoped().Model(&models.StockInfoUS{}).Where("1=1").Delete(&models.StockInfoUS{})
|
||||
err = db.Dao.CreateInBatches(stockUSBasics, 400).Error
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("保存StockInfoUS股票基础信息失败:%s", err.Error())
|
||||
}
|
||||
//for _, stock := range *stockUSBasics {
|
||||
// stockInfo := &models.StockInfoUS{
|
||||
// Code: stock.Code,
|
||||
// Name: stock.Name,
|
||||
// BKName: stock.BKName,
|
||||
// BKCode: stock.BKCode,
|
||||
// }
|
||||
// db.Dao.Model(&models.StockInfoUS{}).Where("code = ?", stock.Code).First(stockInfo)
|
||||
// if stockInfo.ID == 0 {
|
||||
// db.Dao.Model(&models.StockInfoUS{}).Create(stockInfo)
|
||||
// } else {
|
||||
// db.Dao.Model(&models.StockInfoUS{}).Where("code = ?", stock.Code).Updates(stockInfo)
|
||||
// }
|
||||
//}
|
||||
|
||||
}
|
||||
func (a *App) NewsPush(news *[]models.Telegraph) {
|
||||
@@ -1292,7 +1357,8 @@ func (a *App) GetTelegraphList(source string) *[]*models.Telegraph {
|
||||
}
|
||||
|
||||
func (a *App) ReFleshTelegraphList(source string) *[]*models.Telegraph {
|
||||
data.NewMarketNewsApi().GetNewTelegraph(30)
|
||||
//data.NewMarketNewsApi().GetNewTelegraph(30)
|
||||
data.NewMarketNewsApi().TelegraphList(30)
|
||||
data.NewMarketNewsApi().GetSinaNews(30)
|
||||
telegraphs := data.NewMarketNewsApi().GetTelegraphList(source)
|
||||
return telegraphs
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||
"go-stock/backend/agent"
|
||||
"go-stock/backend/data"
|
||||
"go-stock/backend/models"
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||
)
|
||||
|
||||
// @Author spark
|
||||
@@ -26,48 +28,66 @@ func (a *App) StockNotice(stockCode string) []any {
|
||||
func (a *App) IndustryResearchReport(industryCode string) []any {
|
||||
return data.NewMarketNewsApi().IndustryResearchReport(industryCode, 7)
|
||||
}
|
||||
func (a App) EMDictCode(code string) []any {
|
||||
func (a *App) EMDictCode(code string) []any {
|
||||
return data.NewMarketNewsApi().EMDictCode(code, a.cache)
|
||||
}
|
||||
|
||||
func (a App) AnalyzeSentiment(text string) data.SentimentResult {
|
||||
func (a *App) AnalyzeSentiment(text string) data.SentimentResult {
|
||||
return data.AnalyzeSentiment(text)
|
||||
}
|
||||
|
||||
func (a App) HotStock(marketType string) *[]models.HotItem {
|
||||
func (a *App) HotStock(marketType string) *[]models.HotItem {
|
||||
return data.NewMarketNewsApi().XUEQIUHotStock(100, marketType)
|
||||
}
|
||||
|
||||
func (a App) HotEvent(size int) *[]models.HotEvent {
|
||||
func (a *App) HotEvent(size int) *[]models.HotEvent {
|
||||
if size <= 0 {
|
||||
size = 10
|
||||
}
|
||||
return data.NewMarketNewsApi().HotEvent(size)
|
||||
}
|
||||
func (a App) HotTopic(size int) []any {
|
||||
func (a *App) HotTopic(size int) []any {
|
||||
if size <= 0 {
|
||||
size = 10
|
||||
}
|
||||
return data.NewMarketNewsApi().HotTopic(size)
|
||||
}
|
||||
|
||||
func (a App) InvestCalendarTimeLine(yearMonth string) []any {
|
||||
func (a *App) InvestCalendarTimeLine(yearMonth string) []any {
|
||||
return data.NewMarketNewsApi().InvestCalendar(yearMonth)
|
||||
}
|
||||
func (a App) ClsCalendar() []any {
|
||||
func (a *App) ClsCalendar() []any {
|
||||
return data.NewMarketNewsApi().ClsCalendar()
|
||||
}
|
||||
|
||||
func (a App) SearchStock(words string) map[string]any {
|
||||
func (a *App) SearchStock(words string) map[string]any {
|
||||
return data.NewSearchStockApi(words).SearchStock(5000)
|
||||
}
|
||||
func (a App) GetHotStrategy() map[string]any {
|
||||
func (a *App) GetHotStrategy() map[string]any {
|
||||
return data.NewSearchStockApi("").HotStrategy()
|
||||
}
|
||||
|
||||
func (a App) ChatWithAgent(question string, aiConfigId int, sysPromptId *int) {
|
||||
func (a *App) ChatWithAgent(question string, aiConfigId int, sysPromptId *int) {
|
||||
ch := agent.NewStockAiAgentApi().Chat(question, aiConfigId, sysPromptId)
|
||||
for msg := range ch {
|
||||
runtime.EventsEmit(a.ctx, "agent-message", msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) AnalyzeSentimentWithFreqWeight(text string) map[string]any {
|
||||
if text == "" {
|
||||
telegraphs := data.NewMarketNewsApi().GetNews24HoursList("财联社电报", 1000)
|
||||
messageText := strings.Builder{}
|
||||
for _, telegraph := range *telegraphs {
|
||||
messageText.WriteString(telegraph.Content + "\n")
|
||||
}
|
||||
text = messageText.String()
|
||||
}
|
||||
result, frequencies := data.AnalyzeSentimentWithFreqWeight(text)
|
||||
// 过滤标点符号和分隔符
|
||||
cleanFrequencies := data.FilterAndSortWords(frequencies)
|
||||
return map[string]any{
|
||||
"result": result,
|
||||
"frequencies": cleanFrequencies,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,13 +73,14 @@ func GetStockAiAgent(ctx *context.Context, aiConfig data.AIConfig) *react.Agent
|
||||
tools.GetFinancialReportTool(),
|
||||
tools.GetQueryStockNewsTool(),
|
||||
tools.GetIndustryResearchReportTool(),
|
||||
tools.GetQueryBKDictTool(),
|
||||
},
|
||||
}
|
||||
// 创建 agent
|
||||
agent, err := react.NewAgent(*ctx, &react.AgentConfig{
|
||||
ToolCallingModel: toolableChatModel,
|
||||
ToolsConfig: aiTools,
|
||||
MaxStep: len(aiTools.Tools)*3 + 2,
|
||||
MaxStep: len(aiTools.Tools)*1 + 3,
|
||||
MessageModifier: func(ctx context.Context, input []*schema.Message) []*schema.Message {
|
||||
return input
|
||||
},
|
||||
|
||||
34
backend/agent/tools/bk_dict_tool.go
Normal file
34
backend/agent/tools/bk_dict_tool.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"go-stock/backend/data"
|
||||
|
||||
"github.com/cloudwego/eino/components/tool"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/coocood/freecache"
|
||||
)
|
||||
|
||||
// @Author spark
|
||||
// @Date 2025/9/27 14:09
|
||||
// @Desc
|
||||
// -----------------------------------------------------------------------------------
|
||||
type ToolQueryBKDict struct{}
|
||||
|
||||
func (t ToolQueryBKDict) Info(ctx context.Context) (*schema.ToolInfo, error) {
|
||||
return &schema.ToolInfo{
|
||||
Name: "QueryBKDictInfo",
|
||||
Desc: "获取所有板块/行业名称或者代码(bkCode,bkName)",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t ToolQueryBKDict) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...tool.Option) (string, error) {
|
||||
resp := data.NewMarketNewsApi().EMDictCode("016", freecache.NewCache(100))
|
||||
bytes, err := json.Marshal(resp)
|
||||
return string(bytes), err
|
||||
}
|
||||
|
||||
func GetQueryBKDictTool() tool.InvokableTool {
|
||||
return &ToolQueryBKDict{}
|
||||
}
|
||||
@@ -4,11 +4,12 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go-stock/backend/data"
|
||||
|
||||
"github.com/cloudwego/eino/components/tool"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
"go-stock/backend/data"
|
||||
)
|
||||
|
||||
// @Author spark
|
||||
@@ -55,7 +56,7 @@ func (c ChoiceStockByIndicators) InvokableRun(ctx context.Context, argumentsInJS
|
||||
}
|
||||
content := "无符合条件的数据"
|
||||
words := parms["words"].(string)
|
||||
res := data.NewSearchStockApi(words).SearchStock(random.RandInt(5, 10))
|
||||
res := data.NewSearchStockApi(words).SearchStock(random.RandInt(5, 20))
|
||||
if convertor.ToString(res["code"]) == "100" {
|
||||
resData := res["data"].(map[string]any)
|
||||
result := resData["result"].(map[string]any)
|
||||
|
||||
1
backend/data/data/dict/README.md
Normal file
1
backend/data/data/dict/README.md
Normal file
@@ -0,0 +1 @@
|
||||
Some dict/zh data is from [github.com/fxsjy/jieba](https://github.com/fxsjy/jieba)
|
||||
982
backend/data/data/dict/base.txt
Normal file
982
backend/data/data/dict/base.txt
Normal file
@@ -0,0 +1,982 @@
|
||||
# 金融股票全场景分词字典(最终去重优化版)
|
||||
# 格式:单词 权重 词性 | 权重280-350分,核心术语优先匹配,无重复词汇
|
||||
# 覆盖:净买卖、股指、财务指标、交易操作、政策宏观、热点概念、机构媒体、美股中概股、十五五规划等全场景
|
||||
|
||||
# 一、净买卖与资金流向(核心交易表述)
|
||||
净卖出 340 v
|
||||
净买入 340 v
|
||||
净卖出额 330 n
|
||||
净买入额 330 n
|
||||
净卖出量 330 n
|
||||
净买入量 330 n
|
||||
资金净流出 340 n
|
||||
资金净流入 340 n
|
||||
净额 330 n
|
||||
买卖净额 330 n
|
||||
资金净额 330 n
|
||||
北向资金净买入 330 n
|
||||
北向资金净卖出 330 n
|
||||
南向资金净买入 320 n
|
||||
南向资金净卖出 320 n
|
||||
主力资金净买入 330 n
|
||||
主力资金净卖出 330 n
|
||||
散户资金净买入 320 n
|
||||
散户资金净卖出 320 n
|
||||
机构资金净买入 330 n
|
||||
机构资金净卖出 330 n
|
||||
游资净买入 320 n
|
||||
游资净卖出 320 n
|
||||
大单净买入 320 n
|
||||
大单净卖出 320 n
|
||||
中单净买入 320 n
|
||||
中单净卖出 320 n
|
||||
小单净买入 320 n
|
||||
小单净卖出 320 n
|
||||
净买入占比 320 n
|
||||
净卖出占比 320 n
|
||||
净买入率 320 n
|
||||
净卖出率 320 n
|
||||
连续净买入 320 v
|
||||
连续净卖出 320 v
|
||||
单日净买入 320 n
|
||||
单日净卖出 320 n
|
||||
累计净买入 320 n
|
||||
累计净卖出 320 n
|
||||
净买入创纪录 310 adj
|
||||
净卖出创纪录 310 adj
|
||||
净买入放量 310 v
|
||||
净卖出放量 310 v
|
||||
净买入缩量 310 v
|
||||
净卖出缩量 310 v
|
||||
净多 310 n
|
||||
净空 310 n
|
||||
净多头 310 n
|
||||
净空头 310 n
|
||||
净多头头寸 310 n
|
||||
净空头头寸 310 n
|
||||
跌超 310 n
|
||||
跌逾 310 n
|
||||
|
||||
# 二、金融资讯与市场分析
|
||||
金融资讯 350 n
|
||||
市场快讯 340 n
|
||||
财经新闻 340 n
|
||||
政策解读 330 n
|
||||
市场分析 330 n
|
||||
行业研报 320 n
|
||||
宏观经济 330 n
|
||||
微观层面 310 n
|
||||
基本面 320 n
|
||||
技术面 320 n
|
||||
资金面 320 n
|
||||
政策面 320 n
|
||||
市场情绪 320 n
|
||||
风险偏好 310 n
|
||||
流动性 320 n
|
||||
估值修复 310 n
|
||||
价值投资 310 n
|
||||
趋势投资 310 n
|
||||
波段操作 310 n
|
||||
左侧交易 290 n
|
||||
右侧交易 290 n
|
||||
止损止盈 300 n
|
||||
仓位管理 300 n
|
||||
资产配置 310 n
|
||||
分散投资 290 n
|
||||
集中投资 290 n
|
||||
风险控制 310 n
|
||||
系统性风险 300 n
|
||||
非系统性风险 290 n
|
||||
黑天鹅事件 310 n
|
||||
灰犀牛事件 300 n
|
||||
熔断机制 300 n
|
||||
市场监管 310 n
|
||||
信息披露 310 n
|
||||
内幕交易 300 n
|
||||
操纵市场 300 n
|
||||
|
||||
# 三、全球主要股指(含中英文缩写)
|
||||
# 中国市场
|
||||
A股 350 n
|
||||
港股 350 n
|
||||
上证指数 350 n
|
||||
深证成指 350 n
|
||||
创业板指 340 n
|
||||
科创板指 330 n
|
||||
北证50 330 n
|
||||
沪深300 350 n
|
||||
沪深300指数 350 n
|
||||
中证500 340 n
|
||||
中证500指数 340 n
|
||||
中证1000 330 n
|
||||
中证1000指数 330 n
|
||||
上证50 340 n
|
||||
上证50指数 340 n
|
||||
科创50 330 n
|
||||
科创50指数 330 n
|
||||
上证综指 350 n
|
||||
富时中国A50指数 340 n
|
||||
FTSE China A50 330 n
|
||||
恒生指数 340 n
|
||||
HSI 330 n
|
||||
恒生科技指数 340 n
|
||||
恒生国企指数 330 n
|
||||
H股指数 330 n
|
||||
# 美洲市场
|
||||
道琼斯工业平均指数 350 n
|
||||
DJIA 340 n
|
||||
标普500指数 350 n
|
||||
S&P 500 340 n
|
||||
纳斯达克综合指数 340 n
|
||||
纳斯达克100指数 340 n
|
||||
Nasdaq 100 330 n
|
||||
罗素2000指数 320 n
|
||||
Russell 2000 310 n
|
||||
标普400中型股指数 310 n
|
||||
标普600小型股指数 310 n
|
||||
纽约证交所综合指数 310 n
|
||||
NYSE Composite 300 n
|
||||
纳斯达克中国金龙指数 310 n
|
||||
# 欧洲市场
|
||||
德国DAX指数 330 n
|
||||
DAX 30 320 n
|
||||
法国CAC40指数 330 n
|
||||
CAC 40 320 n
|
||||
富时100指数 330 n
|
||||
FTSE 100 320 n
|
||||
欧元斯托克50指数 320 n
|
||||
Euro Stoxx 50 310 n
|
||||
英国富时250指数 310 n
|
||||
FTSE 250 300 n
|
||||
意大利富时MIB指数 310 n
|
||||
FTSE MIB 300 n
|
||||
西班牙IBEX 35指数 310 n
|
||||
IBEX 35 300 n
|
||||
# 亚太其他市场
|
||||
日经225指数 330 n
|
||||
Nikkei 225 320 n
|
||||
日经500指数 310 n
|
||||
韩国综合股价指数 320 n
|
||||
韩国kospi指数 320 n
|
||||
KOSPI 310 n
|
||||
澳洲标普200指数 310 n
|
||||
S&P/ASX 200 300 n
|
||||
印度孟买敏感指数 310 n
|
||||
Sensex 300 n
|
||||
印度Nifty 50指数 310 n
|
||||
Nifty 50 300 n
|
||||
# 全球综合指数
|
||||
MSCI指数 320 n
|
||||
MSCI全球指数 330 n
|
||||
MSCI World Index 320 n
|
||||
MSCI新兴市场指数 330 n
|
||||
MSCI Emerging Markets 320 n
|
||||
富时罗素全球指数 320 n
|
||||
FTSE Russell Global Index 310 n
|
||||
摩根大通全球债券指数 310 n
|
||||
全球股指 300 n
|
||||
发达市场指数 300 n
|
||||
新兴市场指数 300 n
|
||||
金砖国家指数 300 n
|
||||
G20国家指数 300 n
|
||||
# 股指衍生工具
|
||||
指数期货 320 n
|
||||
股指期货 320 n
|
||||
富时中国A50指数期货 320 n
|
||||
沪深300股指期货 320 n
|
||||
标普500股指期货 320 n
|
||||
纳斯达克100股指期货 310 n
|
||||
指数成分股 320 n
|
||||
指数权重股 320 n
|
||||
指数涨幅 320 n
|
||||
指数跌幅 320 n
|
||||
指数反弹 310 n
|
||||
指数回调 310 n
|
||||
指数创新高 310 v
|
||||
指数创新低 310 v
|
||||
指数估值 310 n
|
||||
指数市盈率 310 n
|
||||
|
||||
# 四、A股龙头公司(资讯高频)
|
||||
贵州茅台 310 n
|
||||
宁德时代 350 n
|
||||
比亚迪 340 n
|
||||
隆基绿能 300 n
|
||||
长江电力 290 n
|
||||
中国平安 300 n
|
||||
招商银行 300 n
|
||||
五粮液 290 n
|
||||
美的集团 290 n
|
||||
格力电器 290 n
|
||||
海康威视 290 n
|
||||
迈瑞医疗 290 n
|
||||
恒瑞医药 290 n
|
||||
中芯国际 300 n
|
||||
中兴通讯 290 n
|
||||
东方财富 290 n
|
||||
爱尔眼科 290 n
|
||||
通威股份 290 n
|
||||
药明康德 320 n
|
||||
阳光电源 290 n
|
||||
天齐锂业 290 n
|
||||
赣锋锂业 290 n
|
||||
中国中免 290 n
|
||||
海螺水泥 280 n
|
||||
万科A 280 n
|
||||
保利发展 280 n
|
||||
招商蛇口 280 n
|
||||
上汽集团 280 n
|
||||
宝钢股份 280 n
|
||||
|
||||
# 五、财务与估值核心指标
|
||||
市盈率 350 n
|
||||
PE 350 n
|
||||
动态市盈率 340 n
|
||||
静态市盈率 340 n
|
||||
滚动市盈率 340 n
|
||||
市净率 350 n
|
||||
PB 350 n
|
||||
市销率 330 n
|
||||
PS 330 n
|
||||
市现率 320 n
|
||||
PCF 320 n
|
||||
净资产收益率 350 n
|
||||
ROE 350 n
|
||||
总资产收益率 330 n
|
||||
ROA 330 n
|
||||
毛利率 340 n
|
||||
净利率 340 n
|
||||
销售净利率 330 n
|
||||
资产负债率 340 n
|
||||
营收 340 n
|
||||
营业收入 340 n
|
||||
净利润 350 n
|
||||
归母净利润 340 n
|
||||
扣非净利润 340 n
|
||||
EPS 330 n
|
||||
每股收益 330 n
|
||||
现金流 340 n
|
||||
经营活动现金流 330 n
|
||||
自由现金流 330 n
|
||||
营收增长率 330 n
|
||||
净利润增长率 330 n
|
||||
股息率 320 n
|
||||
分红率 320 n
|
||||
换手率 330 n
|
||||
成交量 340 n
|
||||
成交额 340 n
|
||||
量比 320 n
|
||||
振幅 320 n
|
||||
|
||||
# 六、政策与宏观经济
|
||||
货币政策 330 n
|
||||
财政政策 330 n
|
||||
稳健货币政策 320 n
|
||||
积极财政政策 320 n
|
||||
宽松政策 320 n
|
||||
紧缩政策 320 n
|
||||
利率 330 n
|
||||
基准利率 320 n
|
||||
LPR 330 n
|
||||
贷款市场报价利率 320 n
|
||||
存款准备金率 320 n
|
||||
MLF 320 n
|
||||
中期借贷便利 310 n
|
||||
逆回购 320 n
|
||||
正回购 310 n
|
||||
汇率 330 n
|
||||
人民币汇率 330 n
|
||||
美元汇率 320 n
|
||||
通胀 320 n
|
||||
CPI 330 n
|
||||
PPI 330 n
|
||||
GDP 330 n
|
||||
国内生产总值 320 n
|
||||
PMI 330 n
|
||||
采购经理人指数 320 n
|
||||
行业政策 320 n
|
||||
产业政策 320 n
|
||||
税收政策 310 n
|
||||
补贴政策 310 n
|
||||
关税 310 n
|
||||
贸易政策 310 n
|
||||
地缘政治 310 n
|
||||
大宗商品 320 n
|
||||
原油价格 310 n
|
||||
黄金价格 310 n
|
||||
有色金属价格 300 n
|
||||
|
||||
# 七、金融产品与机构
|
||||
股票 320 n
|
||||
基金 320 n
|
||||
公募基金 310 n
|
||||
私募基金 310 n
|
||||
ETF 320 n
|
||||
指数基金 310 n
|
||||
混合型基金 300 n
|
||||
股票型基金 310 n
|
||||
债券型基金 300 n
|
||||
货币基金 290 n
|
||||
REITs 310 n
|
||||
可转债 310 n
|
||||
可交换债 300 n
|
||||
期货 310 n
|
||||
股指期货 310 n
|
||||
国债期货 300 n
|
||||
商品期货 300 n
|
||||
期权 300 n
|
||||
融资融券 310 n
|
||||
两融余额 300 n
|
||||
北向资金 320 n
|
||||
南向资金 310 n
|
||||
沪股通 310 n
|
||||
深股通 310 n
|
||||
陆股通 310 n
|
||||
证券公司 310 n
|
||||
券商 320 n
|
||||
基金公司 300 n
|
||||
保险公司 300 n
|
||||
银行 310 n
|
||||
监管机构 310 n
|
||||
证监会 320 n
|
||||
交易所 320 n
|
||||
上交所 320 n
|
||||
深交所 320 n
|
||||
北交所 310 n
|
||||
港交所 310 n
|
||||
社保基金 310 n
|
||||
养老金 300 n
|
||||
QFII 300 n
|
||||
RQFII 290 n
|
||||
北向资金机构 300 n
|
||||
|
||||
# 八、热点概念与行业
|
||||
AI 330 n
|
||||
人工智能 350 n
|
||||
算力 330 n
|
||||
大数据 320 n
|
||||
云计算 320 n
|
||||
半导体 350 n
|
||||
芯片 350 n
|
||||
集成电路 340 n
|
||||
新能源 350 n
|
||||
光伏 340 n
|
||||
锂电 320 n
|
||||
储能 340 n
|
||||
充电桩 310 n
|
||||
新能源车 320 n
|
||||
智能汽车 310 n
|
||||
自动驾驶 330 n
|
||||
军工 310 n
|
||||
国防军工 300 n
|
||||
医药 310 n
|
||||
创新药 310 n
|
||||
医疗器械 300 n
|
||||
CXO 300 n
|
||||
白酒 310 n
|
||||
消费 320 n
|
||||
可选消费 300 n
|
||||
必选消费 300 n
|
||||
食品饮料 310 n
|
||||
家电 300 n
|
||||
地产 300 n
|
||||
房地产 300 n
|
||||
基建 300 n
|
||||
新基建 310 n
|
||||
数字经济 350 n
|
||||
数字货币 310 n
|
||||
区块链 300 n
|
||||
元宇宙 300 n
|
||||
低空经济 340 n
|
||||
人形机器人 330 n
|
||||
工业互联网 330 n
|
||||
物联网 300 n
|
||||
5G 300 n
|
||||
6G 340 n
|
||||
|
||||
# 九、交易操作与行情
|
||||
上涨 310 v
|
||||
下跌 310 v
|
||||
涨停 310 v
|
||||
跌停 310 v
|
||||
反弹 300 v
|
||||
反转 300 v
|
||||
回调 300 v
|
||||
横盘 290 v
|
||||
震荡 290 v
|
||||
跳水 300 v
|
||||
拉升 300 v
|
||||
砸盘 300 v
|
||||
护盘 290 v
|
||||
建仓 300 v
|
||||
加仓 300 v
|
||||
减仓 300 v
|
||||
清仓 300 v
|
||||
平仓 300 v
|
||||
抄底 300 v
|
||||
逃顶 300 v
|
||||
追涨 290 v
|
||||
杀跌 290 v
|
||||
套牢 280 v
|
||||
解套 280 v
|
||||
净流入 300 n
|
||||
净流出 300 n
|
||||
主力资金 300 n
|
||||
资金流入 290 v
|
||||
资金流出 290 v
|
||||
放量 290 v
|
||||
缩量 290 v
|
||||
高换手 290 n
|
||||
低换手 280 n
|
||||
高估值 290 n
|
||||
低估值 290 n
|
||||
超预期 300 v
|
||||
不及预期 300 v
|
||||
符合预期 290 v
|
||||
利好 310 n
|
||||
利空 310 n
|
||||
政策利好 310 n
|
||||
业绩利好 310 n
|
||||
风险警示 300 n
|
||||
涨停板 300 n
|
||||
跌停板 300 n
|
||||
一字涨停 290 n
|
||||
一字跌停 290 n
|
||||
打开涨停 320 v
|
||||
打开跌停 320 v
|
||||
集合竞价 290 n
|
||||
连续竞价 280 n
|
||||
开盘价 340 n
|
||||
收盘价 340 n
|
||||
最高价 330 n
|
||||
最低价 330 n
|
||||
均价 330 n
|
||||
昨日收盘价 320 n
|
||||
涨跌额 330 n
|
||||
涨跌幅 340 n
|
||||
涨幅 340 n
|
||||
跌幅 340 n
|
||||
涨停价 330 n
|
||||
跌停价 330 n
|
||||
熔断 330 n
|
||||
临时停牌 320 n
|
||||
复牌 320 v
|
||||
停牌 320 n
|
||||
量价齐升 320 n
|
||||
量价背离 320 n
|
||||
高开 320 n
|
||||
低开 320 n
|
||||
平开 320 n
|
||||
高走 320 v
|
||||
低走 320 v
|
||||
震荡上行 320 v
|
||||
震荡下行 320 v
|
||||
|
||||
# 十、委托交易与规则
|
||||
限价委托 340 n
|
||||
市价委托 340 n
|
||||
止损委托 330 n
|
||||
止盈委托 330 n
|
||||
预埋单 320 n
|
||||
条件单 330 n
|
||||
触发委托 320 n
|
||||
追涨委托 320 n
|
||||
抄底委托 320 n
|
||||
挂单 330 n
|
||||
撤单 330 v
|
||||
成交 340 v
|
||||
未成交 320 adj
|
||||
部分成交 320 adj
|
||||
委托价 320 n
|
||||
成交价 320 n
|
||||
委托量 320 n
|
||||
买单 330 n
|
||||
卖单 330 n
|
||||
买入 340 v
|
||||
卖出 340 v
|
||||
做多 330 v
|
||||
做空 330 v
|
||||
开仓 330 v
|
||||
满仓 330 v
|
||||
空仓 330 v
|
||||
半仓 320 v
|
||||
轻仓 320 v
|
||||
重仓 320 v
|
||||
底仓 320 n
|
||||
补仓 320 v
|
||||
T+1交易 330 n
|
||||
T+0交易 330 n
|
||||
日内交易 320 n
|
||||
短线交易 320 n
|
||||
中线交易 320 n
|
||||
长线交易 320 n
|
||||
集合竞价交易 320 n
|
||||
连续竞价交易 320 n
|
||||
保证金 320 n
|
||||
杠杆 320 n
|
||||
融资 320 n
|
||||
融券 320 n
|
||||
融资买入 320 v
|
||||
融券卖出 320 v
|
||||
融资余额 320 n
|
||||
融券余额 320 n
|
||||
两融业务 320 n
|
||||
信用账户 320 n
|
||||
普通账户 320 n
|
||||
资金账户 320 n
|
||||
证券账户 320 n
|
||||
持仓 330 n
|
||||
持仓股 320 n
|
||||
持仓数量 320 n
|
||||
可用资金 320 n
|
||||
可取资金 320 n
|
||||
冻结资金 320 n
|
||||
交易成本 320 n
|
||||
手续费 320 n
|
||||
佣金 320 n
|
||||
印花税 320 n
|
||||
过户费 320 n
|
||||
交易规费 320 n
|
||||
B股 310 n
|
||||
H股 310 n
|
||||
美股 310 n
|
||||
创业板 320 n
|
||||
科创板 320 n
|
||||
主板 320 n
|
||||
纳斯达克 350 n
|
||||
纽交所 310 n
|
||||
标普500 350 n
|
||||
道琼斯 310 n
|
||||
成分股 310 n
|
||||
权重股 310 n
|
||||
龙头股 310 n
|
||||
中小盘股 310 n
|
||||
大盘股 310 n
|
||||
小盘股 310 n
|
||||
ST股 320 n
|
||||
*ST股 320 n
|
||||
退市股 320 n
|
||||
次新股 320 n
|
||||
新股 320 n
|
||||
打新 320 v
|
||||
新股申购 320 n
|
||||
中签 320 v
|
||||
新股上市 320 n
|
||||
限售股 310 n
|
||||
解禁 310 v
|
||||
股权登记日 310 n
|
||||
除权除息日 310 n
|
||||
派息 310 n
|
||||
分红 310 n
|
||||
送股 310 n
|
||||
转增股 310 n
|
||||
配股 310 n
|
||||
除权 310 n
|
||||
除息 310 n
|
||||
填权 310 v
|
||||
贴权 310 v
|
||||
筹码分析 310 n
|
||||
盘口分析 310 n
|
||||
K线图 310 n
|
||||
均线 310 n
|
||||
日均线 310 n
|
||||
周均线 310 n
|
||||
月均线 310 n
|
||||
MACD 310 n
|
||||
KDJ 310 n
|
||||
RSI 310 n
|
||||
布林带 310 n
|
||||
成交量均线 310 n
|
||||
支撑位 310 n
|
||||
压力位 310 n
|
||||
阻力位 310 n
|
||||
突破 310 v
|
||||
跌破 310 v
|
||||
站稳 310 v
|
||||
回落 310 v
|
||||
冲高 310 v
|
||||
横盘整理 310 n
|
||||
震荡整理 310 n
|
||||
洗盘 310 n
|
||||
吸筹 310 n
|
||||
出货 310 n
|
||||
建仓成本 310 n
|
||||
持仓周期 310 n
|
||||
交易频率 310 n
|
||||
长线持有 310 v
|
||||
高抛低吸 310 v
|
||||
追涨杀跌 310 v
|
||||
低吸高抛 310 v
|
||||
顺势而为 310 n
|
||||
逆向投资 310 n
|
||||
交易软件 300 n
|
||||
行情软件 300 n
|
||||
交易终端 300 n
|
||||
手机炒股 300 n
|
||||
电脑炒股 300 n
|
||||
网上交易 300 n
|
||||
电话委托 290 n
|
||||
营业部交易 290 n
|
||||
交易系统 300 n
|
||||
行情系统 300 n
|
||||
Level-2行情 300 n
|
||||
实时行情 300 n
|
||||
延时行情 290 n
|
||||
交易接口 300 n
|
||||
量化交易 310 n
|
||||
算法交易 300 n
|
||||
程序化交易 300 n
|
||||
自动交易 300 n
|
||||
智能投顾 300 n
|
||||
券商APP 300 n
|
||||
交易佣金 300 n
|
||||
开户 300 v
|
||||
销户 290 v
|
||||
转户 290 v
|
||||
绑定银行卡 290 v
|
||||
银证转账 300 n
|
||||
银证通 290 n
|
||||
第三方存管 290 n
|
||||
赛道股 330 n
|
||||
抱团股 310 n
|
||||
妖股 310 n
|
||||
庄股 310 n
|
||||
|
||||
# 十一、主要财经网站与机构
|
||||
# 国内财经网站
|
||||
东方财富网 350 n
|
||||
同花顺财经 340 n
|
||||
财新网 340 n
|
||||
新浪财经 340 n
|
||||
第一财经 330 n
|
||||
金融界 330 n
|
||||
华尔街见闻 330 n
|
||||
每日经济新闻 330 n
|
||||
证券时报网 330 n
|
||||
财联社 330 n
|
||||
和讯网 320 n
|
||||
证券之星 320 n
|
||||
中国证券报 330 n
|
||||
上海证券报 330 n
|
||||
证券日报 320 n
|
||||
界面新闻 320 n
|
||||
澎湃新闻财经 320 n
|
||||
腾讯财经 320 n
|
||||
网易财经 320 n
|
||||
凤凰财经 320 n
|
||||
# 国际财经媒体
|
||||
彭博社 350 n
|
||||
路透社 350 n
|
||||
金融时报 340 n
|
||||
华尔街日报 340 n
|
||||
雅虎财经 320 n
|
||||
CNBC 320 n
|
||||
路透财经 330 n
|
||||
彭博财经 330 n
|
||||
英国金融时报 330 n
|
||||
美国消费者新闻与商业频道 320 n
|
||||
日经新闻 320 n
|
||||
韩国经济新闻 310 n
|
||||
# 国际金融机构
|
||||
高盛集团 350 n
|
||||
摩根士丹利 350 n
|
||||
摩根大通 350 n
|
||||
瑞银集团 340 n
|
||||
汇丰银行 340 n
|
||||
野村证券 330 n
|
||||
贝莱德 350 n
|
||||
桥水基金 340 n
|
||||
黑石集团 340 n
|
||||
橡树资本 330 n
|
||||
花旗集团 330 n
|
||||
美银美林 330 n
|
||||
德意志银行 320 n
|
||||
瑞士信贷 320 n
|
||||
法国巴黎银行 320 n
|
||||
三菱日联金融集团 310 n
|
||||
# 国内外金融监管与交易机构
|
||||
中国证监会 350 n
|
||||
美联储 350 n
|
||||
英国金融行为管理局 330 n
|
||||
香港证监会 330 n
|
||||
纽约证券交易所 350 n
|
||||
香港交易所 340 n
|
||||
伦敦证券交易所 340 n
|
||||
芝商所集团 330 n
|
||||
泛欧证券交易所 330 n
|
||||
上海证券交易所 340 n
|
||||
深圳证券交易所 340 n
|
||||
北京证券交易所 330 n
|
||||
中国人民银行 350 n
|
||||
银保监会 340 n
|
||||
国家金融监督管理总局 340 n
|
||||
财政部 340 n
|
||||
发改委 330 n
|
||||
石油输出国组织 340 n
|
||||
国际能源署 330 n
|
||||
美国能源信息署 320 n
|
||||
世界银行 330 n
|
||||
国际货币基金组织 330 n
|
||||
# 国内核心金融机构
|
||||
中国工商银行 340 n
|
||||
中国建设银行 340 n
|
||||
中国农业银行 340 n
|
||||
中国银行 340 n
|
||||
交通银行 330 n
|
||||
招商银行 330 n
|
||||
兴业银行 320 n
|
||||
浦发银行 320 n
|
||||
中信证券 340 n
|
||||
华泰证券 330 n
|
||||
中金公司 330 n
|
||||
中信建投 330 n
|
||||
国泰君安 330 n
|
||||
广发证券 320 n
|
||||
东方证券 320 n
|
||||
南方基金 330 n
|
||||
易方达基金 330 n
|
||||
华夏基金 330 n
|
||||
嘉实基金 320 n
|
||||
博时基金 320 n
|
||||
|
||||
# 十二、知名美股与中概股
|
||||
# 知名美股
|
||||
苹果 350 n
|
||||
Apple 340 n
|
||||
英伟达 350 n
|
||||
Nvidia 340 n
|
||||
特斯拉 350 n
|
||||
Tesla 340 n
|
||||
谷歌 340 n
|
||||
Alphabet 330 n
|
||||
亚马逊 340 n
|
||||
Amazon 330 n
|
||||
Meta Platforms 330 n
|
||||
Meta 330 n
|
||||
微软 350 n
|
||||
Microsoft 340 n
|
||||
甲骨文 320 n
|
||||
Oracle 310 n
|
||||
伯克希尔哈撒韦 320 n
|
||||
Berkshire Hathaway 310 n
|
||||
闪迪 300 n
|
||||
SanDisk 290 n
|
||||
高通 320 n
|
||||
Qualcomm 310 n
|
||||
英特尔 320 n
|
||||
Intel 310 n
|
||||
AMD 320 n
|
||||
超威半导体 310 n
|
||||
脸书 320 n
|
||||
Facebook 310 n
|
||||
推特 310 n
|
||||
Twitter 300 n
|
||||
Square 300 n
|
||||
Block 290 n
|
||||
PayPal 310 n
|
||||
贝宝 300 n
|
||||
星巴克 310 n
|
||||
Starbucks 300 n
|
||||
可口可乐 310 n
|
||||
Coca-Cola 300 n
|
||||
百事可乐 300 n
|
||||
PepsiCo 290 n
|
||||
沃尔玛 310 n
|
||||
Walmart 300 n
|
||||
家得宝 300 n
|
||||
Home Depot 290 n
|
||||
美国银行 310 n
|
||||
Bank of America 300 n
|
||||
# 知名中概股
|
||||
阿里巴巴 350 n
|
||||
Alibaba 340 n
|
||||
拼多多 340 n
|
||||
PDD 330 n
|
||||
蔚来汽车 330 n
|
||||
NIO 320 n
|
||||
理想汽车 330 n
|
||||
LI 320 n
|
||||
腾讯音乐 320 n
|
||||
TME 310 n
|
||||
唯品会 310 n
|
||||
VIPS 300 n
|
||||
富途控股 310 n
|
||||
FUTU 300 n
|
||||
老虎证券 310 n
|
||||
TIGR 300 n
|
||||
万物新生 300 n
|
||||
RERE 290 n
|
||||
涂鸦智能 300 n
|
||||
TUYA 290 n
|
||||
百济神州 320 n
|
||||
BeiGene 310 n
|
||||
百度集团 340 n
|
||||
Baidu 330 n
|
||||
文远知行 300 n
|
||||
WRD 290 n
|
||||
贝壳 310 n
|
||||
KE 300 n
|
||||
新氧 300 n
|
||||
SY 290 n
|
||||
京东 340 n
|
||||
JD.com 330 n
|
||||
京东物流 320 n
|
||||
JD Logistics 310 n
|
||||
腾讯控股 350 n
|
||||
Tencent Holdings 340 n
|
||||
美团 340 n
|
||||
Meituan 330 n
|
||||
小米集团 340 n
|
||||
Xiaomi Group 330 n
|
||||
快手 330 n
|
||||
Kuaishou 320 n
|
||||
字节跳动 340 n
|
||||
ByteDance 330 n
|
||||
滴滴 330 n
|
||||
DiDi 320 n
|
||||
携程 320 n
|
||||
Ctrip 310 n
|
||||
去哪儿 310 n
|
||||
Qunar 300 n
|
||||
同程旅行 300 n
|
||||
LY.com 290 n
|
||||
途牛 300 n
|
||||
Tuniu 290 n
|
||||
哔哩哔哩 320 n
|
||||
Bilibili 310 n
|
||||
爱奇艺 320 n
|
||||
iQiyi 310 n
|
||||
优酷 310 n
|
||||
Youku 300 n
|
||||
芒果超媒 310 n
|
||||
Mango TV 300 n
|
||||
网易 330 n
|
||||
NetEase 320 n
|
||||
新浪 320 n
|
||||
Sina 310 n
|
||||
微博 320 n
|
||||
Weibo 310 n
|
||||
知乎 310 n
|
||||
Zhihu 300 n
|
||||
小红书 310 n
|
||||
Xiaohongshu 300 n
|
||||
商汤科技 310 n
|
||||
SenseTime 300 n
|
||||
旷视科技 300 n
|
||||
Megvii 290 n
|
||||
云从科技 300 n
|
||||
Cloudwalk 290 n
|
||||
依图科技 300 n
|
||||
Yitu 290 n
|
||||
药明生物 320 n
|
||||
WuXi Biologics 310 n
|
||||
康希诺 310 n
|
||||
CanSino Biologics 300 n
|
||||
智飞生物 310 n
|
||||
Innovax 300 n
|
||||
CATL 340 n
|
||||
BYD 330 n
|
||||
小鹏汽车 330 n
|
||||
Xpeng 320 n
|
||||
哪吒汽车 310 n
|
||||
Nezha Auto 300 n
|
||||
零跑汽车 310 n
|
||||
Leapmotor 300 n
|
||||
极氪 310 n
|
||||
ZEEKR 300 n
|
||||
岚图汽车 300 n
|
||||
VOYAH 290 n
|
||||
华为 350 n
|
||||
Huawei 340 n
|
||||
荣耀 330 n
|
||||
Honor 320 n
|
||||
OPPO 330 n
|
||||
vivo 330 n
|
||||
一加 310 n
|
||||
OnePlus 300 n
|
||||
真我 310 n
|
||||
realme 300 n
|
||||
传音控股 310 n
|
||||
Transsion 300 n
|
||||
|
||||
# 十三、十五五规划重点领域
|
||||
# 核心战略方向
|
||||
新质生产力 350 n
|
||||
科技自立自强 350 n
|
||||
全要素生产率 340 n
|
||||
高质量发展 340 n
|
||||
中国式现代化 340 n
|
||||
共同富裕 330 n
|
||||
区域协调发展 330 n
|
||||
城乡融合发展 330 n
|
||||
国家安全体系 330 n
|
||||
双循环 330 n
|
||||
高水平对外开放 320 n
|
||||
# 科技创新与数字经济
|
||||
量子科技 340 n
|
||||
脑机接口 340 n
|
||||
具身智能 340 n
|
||||
第六代移动通信 340 n
|
||||
生成式AI 340 n
|
||||
通用人工智能 330 n
|
||||
工业母机 340 n
|
||||
集成电路 340 n
|
||||
高端算力 330 n
|
||||
数据要素 340 n
|
||||
数字基础设施 330 n
|
||||
智能制造 340 n
|
||||
服务型制造 320 n
|
||||
绿色制造 320 n
|
||||
# 能源与绿色转型
|
||||
新型能源体系 340 n
|
||||
氢能 340 n
|
||||
核聚变能 330 n
|
||||
可再生能源 330 n
|
||||
风电 330 n
|
||||
生物质能 320 n
|
||||
碳排放双控 340 n
|
||||
碳达峰 330 n
|
||||
碳中和 330 n
|
||||
绿色低碳 330 n
|
||||
循环经济 320 n
|
||||
节能环保 320 n
|
||||
碳交易 320 n
|
||||
# 高端制造与新兴产业
|
||||
航空航天 340 n
|
||||
新材料 340 n
|
||||
生物制造 330 n
|
||||
生物医药 330 n
|
||||
基因编辑 320 n
|
||||
合成生物学 320 n
|
||||
智能网联汽车 330 n
|
||||
机器人 330 n
|
||||
海洋工程 320 n
|
||||
核电 320 n
|
||||
高端装备 330 n
|
||||
# 乡村振兴与农业现代化
|
||||
乡村振兴 340 n
|
||||
农业机械化 330 n
|
||||
智慧农业 330 n
|
||||
现代农业 320 n
|
||||
粮食安全 330 n
|
||||
农产品深加工 320 n
|
||||
农村电商 320 n
|
||||
乡村旅游 310 n
|
||||
# 对外开放与贸易升级
|
||||
跨境电商 330 n
|
||||
自贸试验区 320 n
|
||||
海南自贸港 320 n
|
||||
一带一路 330 n
|
||||
服务贸易 320 n
|
||||
数字贸易 320 n
|
||||
跨境金融 320 n
|
||||
外资准入 310 n
|
||||
# 社会民生与公共服务
|
||||
教育强国 320 n
|
||||
健康中国 320 n
|
||||
养老服务 310 n
|
||||
医疗保障 310 n
|
||||
保障性住房 310 n
|
||||
公共卫生 320 n
|
||||
文化强国 320 n
|
||||
体育强国 310 n
|
||||
0
backend/data/data/dict/en/dict.txt
Normal file
0
backend/data/data/dict/en/dict.txt
Normal file
1
backend/data/data/dict/jp/README.md
Normal file
1
backend/data/data/dict/jp/README.md
Normal file
@@ -0,0 +1 @@
|
||||
dict.txt 通过内部工具生成, Copyright 2017 ego authors. 商用和拷贝请注明来源和版权
|
||||
885298
backend/data/data/dict/jp/dict.txt
Normal file
885298
backend/data/data/dict/jp/dict.txt
Normal file
File diff suppressed because it is too large
Load Diff
270132
backend/data/data/dict/zh/idf.txt
Normal file
270132
backend/data/data/dict/zh/idf.txt
Normal file
File diff suppressed because it is too large
Load Diff
352279
backend/data/data/dict/zh/s_1.txt
Normal file
352279
backend/data/data/dict/zh/s_1.txt
Normal file
File diff suppressed because it is too large
Load Diff
1161
backend/data/data/dict/zh/stop_tokens.txt
Normal file
1161
backend/data/data/dict/zh/stop_tokens.txt
Normal file
File diff suppressed because it is too large
Load Diff
88
backend/data/data/dict/zh/stop_word.txt
Normal file
88
backend/data/data/dict/zh/stop_word.txt
Normal file
@@ -0,0 +1,88 @@
|
||||
,
|
||||
.
|
||||
?
|
||||
!
|
||||
"
|
||||
@
|
||||
,
|
||||
。
|
||||
、
|
||||
?
|
||||
!
|
||||
:
|
||||
“
|
||||
”
|
||||
;
|
||||
|
||||
(
|
||||
)
|
||||
《
|
||||
》
|
||||
~
|
||||
*
|
||||
<
|
||||
>
|
||||
/
|
||||
\
|
||||
|
|
||||
-
|
||||
_
|
||||
+
|
||||
=
|
||||
&
|
||||
^
|
||||
%
|
||||
#
|
||||
`
|
||||
;
|
||||
$
|
||||
¥
|
||||
‘
|
||||
’
|
||||
〉
|
||||
〈
|
||||
…
|
||||
>
|
||||
<
|
||||
@
|
||||
#
|
||||
$
|
||||
%
|
||||
︿
|
||||
&
|
||||
*
|
||||
+
|
||||
~
|
||||
|
|
||||
[
|
||||
]
|
||||
{
|
||||
}
|
||||
啊
|
||||
阿
|
||||
哎
|
||||
哎呀
|
||||
哎哟
|
||||
唉
|
||||
俺
|
||||
俺们
|
||||
按
|
||||
按照
|
||||
吧
|
||||
吧哒
|
||||
把
|
||||
罢了
|
||||
被
|
||||
本
|
||||
本着
|
||||
比
|
||||
比方
|
||||
比如
|
||||
鄙人
|
||||
彼
|
||||
彼此
|
||||
边
|
||||
别
|
||||
别的
|
||||
别说
|
||||
并
|
||||
236754
backend/data/data/dict/zh/t_1.txt
Normal file
236754
backend/data/data/dict/zh/t_1.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,73 @@ func NewMarketNewsApi() *MarketNewsApi {
|
||||
return &MarketNewsApi{}
|
||||
}
|
||||
|
||||
func (m MarketNewsApi) TelegraphList(crawlTimeOut int64) *[]models.Telegraph {
|
||||
//https://www.cls.cn/nodeapi/telegraphList
|
||||
url := "https://www.cls.cn/nodeapi/telegraphList"
|
||||
res := map[string]any{}
|
||||
_, _ = resty.New().SetTimeout(time.Duration(crawlTimeOut)*time.Second).R().
|
||||
SetHeader("Referer", "https://www.cls.cn/").
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.60").
|
||||
SetResult(&res).
|
||||
Get(url)
|
||||
var telegraphs []models.Telegraph
|
||||
|
||||
if v, _ := convertor.ToInt(res["error"]); v == 0 {
|
||||
if res["data"] == nil {
|
||||
return m.GetNewTelegraph(30)
|
||||
}
|
||||
data := res["data"].(map[string]any)
|
||||
rollData := data["roll_data"].([]any)
|
||||
for _, v := range rollData {
|
||||
news := v.(map[string]any)
|
||||
ctime, _ := convertor.ToInt(news["ctime"])
|
||||
dataTime := time.Unix(ctime, 0)
|
||||
logger.SugaredLogger.Debugf("dataTime: %s", dataTime)
|
||||
telegraph := models.Telegraph{
|
||||
Content: news["content"].(string),
|
||||
Time: dataTime.Format("15:04:05"),
|
||||
DataTime: &dataTime,
|
||||
Url: news["shareurl"].(string),
|
||||
Source: "财联社电报",
|
||||
IsRed: GetLevel(news["level"].(string)),
|
||||
SentimentResult: AnalyzeSentiment(news["content"].(string)).Description,
|
||||
}
|
||||
cnt := int64(0)
|
||||
db.Dao.Model(telegraph).Where("time=? and content=?", telegraph.Time, telegraph.Content).Count(&cnt)
|
||||
if cnt > 0 {
|
||||
continue
|
||||
}
|
||||
telegraphs = append(telegraphs, telegraph)
|
||||
db.Dao.Model(&models.Telegraph{}).Create(&telegraph)
|
||||
logger.SugaredLogger.Debugf("telegraph: %+v", &telegraph)
|
||||
if news["subjects"] == nil {
|
||||
continue
|
||||
}
|
||||
subjects := news["subjects"].([]any)
|
||||
for _, subject := range subjects {
|
||||
name := subject.(map[string]any)["subject_name"].(string)
|
||||
tag := &models.Tags{
|
||||
Name: name,
|
||||
Type: "subject",
|
||||
}
|
||||
db.Dao.Model(tag).Where("name=? and type=?", name, "subject").FirstOrCreate(&tag)
|
||||
db.Dao.Model(models.TelegraphTags{}).Where("telegraph_id=? and tag_id=?", telegraph.ID, tag.ID).FirstOrCreate(&models.TelegraphTags{
|
||||
TelegraphId: telegraph.ID,
|
||||
TagId: tag.ID,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
//db.Dao.Model(&models.Telegraph{}).Create(&telegraphs)
|
||||
//logger.SugaredLogger.Debugf("telegraphs: %+v", &telegraphs)
|
||||
}
|
||||
|
||||
return &telegraphs
|
||||
}
|
||||
func GetLevel(s string) bool {
|
||||
return s > "C"
|
||||
}
|
||||
|
||||
func (m MarketNewsApi) GetNewTelegraph(crawlTimeOut int64) *[]models.Telegraph {
|
||||
url := "https://www.cls.cn/telegraph"
|
||||
response, _ := resty.New().SetTimeout(time.Duration(crawlTimeOut)*time.Second).R().
|
||||
@@ -77,7 +144,7 @@ func (m MarketNewsApi) GetNewTelegraph(crawlTimeOut int64) *[]models.Telegraph {
|
||||
if telegraph.Content != "" {
|
||||
telegraph.SentimentResult = AnalyzeSentiment(telegraph.Content).Description
|
||||
cnt := int64(0)
|
||||
db.Dao.Model(telegraph).Where("time=? and source=?", telegraph.Time, telegraph.Source).Count(&cnt)
|
||||
db.Dao.Model(telegraph).Where("time=? and content=?", telegraph.Time, telegraph.Content).Count(&cnt)
|
||||
if cnt == 0 {
|
||||
db.Dao.Create(&telegraph)
|
||||
telegraphs = append(telegraphs, telegraph)
|
||||
@@ -117,6 +184,28 @@ func (m MarketNewsApi) GetNewsList(source string, limit int) *[]*models.Telegrap
|
||||
}
|
||||
return news
|
||||
}
|
||||
func (m MarketNewsApi) GetNewsList2(source string, limit int) *[]*models.Telegraph {
|
||||
NewMarketNewsApi().TelegraphList(30)
|
||||
news := &[]*models.Telegraph{}
|
||||
if source != "" {
|
||||
db.Dao.Model(news).Preload("TelegraphTags").Where("source=?", source).Order("id desc,is_red desc").Limit(limit).Find(news)
|
||||
} else {
|
||||
db.Dao.Model(news).Preload("TelegraphTags").Order("id desc,is_red desc").Limit(limit).Find(news)
|
||||
}
|
||||
for _, item := range *news {
|
||||
tags := &[]models.Tags{}
|
||||
db.Dao.Model(&models.Tags{}).Where("id in ?", lo.Map(item.TelegraphTags, func(item models.TelegraphTags, index int) uint {
|
||||
return item.TagId
|
||||
})).Find(&tags)
|
||||
tagNames := lo.Map(*tags, func(item models.Tags, index int) string {
|
||||
return item.Name
|
||||
})
|
||||
item.SubjectTags = tagNames
|
||||
logger.SugaredLogger.Infof("tagNames %v ,SubjectTags:%s", tagNames, item.SubjectTags)
|
||||
}
|
||||
return news
|
||||
}
|
||||
|
||||
func (m MarketNewsApi) GetTelegraphList(source string) *[]*models.Telegraph {
|
||||
news := &[]*models.Telegraph{}
|
||||
if source != "" {
|
||||
@@ -938,3 +1027,33 @@ func (m MarketNewsApi) CailianpressWeb(searchWords string) *models.CailianpressW
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (m MarketNewsApi) GetNews24HoursList(source string, limit int) *[]*models.Telegraph {
|
||||
news := &[]*models.Telegraph{}
|
||||
if source != "" {
|
||||
db.Dao.Model(news).Preload("TelegraphTags").Where("source=? and created_at>?", source, time.Now().Add(-24*time.Hour)).Order("id desc,is_red desc").Limit(limit).Find(news)
|
||||
} else {
|
||||
db.Dao.Model(news).Preload("TelegraphTags").Where("created_at>?", time.Now().Add(-24*time.Hour)).Order("id desc,is_red desc").Limit(limit).Find(news)
|
||||
}
|
||||
// 内容去重
|
||||
uniqueNews := make([]*models.Telegraph, 0)
|
||||
seenContent := make(map[string]bool)
|
||||
for _, item := range *news {
|
||||
tags := &[]models.Tags{}
|
||||
db.Dao.Model(&models.Tags{}).Where("id in ?", lo.Map(item.TelegraphTags, func(item models.TelegraphTags, index int) uint {
|
||||
return item.TagId
|
||||
})).Find(&tags)
|
||||
tagNames := lo.Map(*tags, func(item models.Tags, index int) string {
|
||||
return item.Name
|
||||
})
|
||||
item.SubjectTags = tagNames
|
||||
//logger.SugaredLogger.Infof("tagNames %v ,SubjectTags:%s", tagNames, item.SubjectTags)
|
||||
// 使用内容作为去重键值,可以考虑只使用内容的前几个字符或哈希值
|
||||
contentKey := strings.TrimSpace(item.Content)
|
||||
if contentKey != "" && !seenContent[contentKey] {
|
||||
seenContent[contentKey] = true
|
||||
uniqueNews = append(uniqueNews, item)
|
||||
}
|
||||
}
|
||||
return &uniqueNews
|
||||
}
|
||||
|
||||
@@ -4,11 +4,13 @@ import (
|
||||
"encoding/json"
|
||||
"go-stock/backend/db"
|
||||
"go-stock/backend/logger"
|
||||
"go-stock/backend/models"
|
||||
"go-stock/backend/util"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/coocood/freecache"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
@@ -37,7 +39,6 @@ func TestGetIndustryRank(t *testing.T) {
|
||||
res := NewMarketNewsApi().GetIndustryRank("0", 10)
|
||||
for s, a := range res["data"].([]any) {
|
||||
logger.SugaredLogger.Debugf("key: %+v, value: %+v", s, a)
|
||||
|
||||
}
|
||||
}
|
||||
func TestGetIndustryMoneyRankSina(t *testing.T) {
|
||||
@@ -72,9 +73,12 @@ func TestLongTiger(t *testing.T) {
|
||||
|
||||
func TestStockResearchReport(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
resp := NewMarketNewsApi().StockResearchReport("600584.sh", 7)
|
||||
resp := NewMarketNewsApi().StockResearchReport("688082", 7)
|
||||
for _, a := range resp {
|
||||
logger.SugaredLogger.Debugf("value: %+v", a)
|
||||
data := a.(map[string]any)
|
||||
logger.SugaredLogger.Debugf("value: %s infoCode:%s", data["title"], data["infoCode"])
|
||||
NewMarketNewsApi().GetIndustryReportInfo(data["infoCode"].(string))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +112,11 @@ func TestEMDictCode(t *testing.T) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
dict := &[]models.BKDict{}
|
||||
json.Unmarshal(bytes, dict)
|
||||
logger.SugaredLogger.Debugf("value: %s", string(bytes))
|
||||
md := util.MarkdownTableWithTitle("行业/板块代码", dict)
|
||||
logger.SugaredLogger.Debugf(md)
|
||||
|
||||
}
|
||||
|
||||
@@ -226,3 +234,18 @@ func TestInteractiveAnswer(t *testing.T) {
|
||||
logger.SugaredLogger.Debugf(md)
|
||||
|
||||
}
|
||||
func TestGetNewsList2(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
news := NewMarketNewsApi().GetNewsList2("财联社电报", random.RandInt(100, 500))
|
||||
messageText := strings.Builder{}
|
||||
for _, telegraph := range *news {
|
||||
messageText.WriteString("## " + telegraph.Time + ":" + "\n")
|
||||
messageText.WriteString("### " + telegraph.Content + "\n")
|
||||
}
|
||||
logger.SugaredLogger.Debugf("value: %s", messageText.String())
|
||||
}
|
||||
|
||||
func TestTelegraphList(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
NewMarketNewsApi().TelegraphList(30)
|
||||
}
|
||||
|
||||
@@ -323,8 +323,7 @@ func (o *OpenAi) NewSummaryStockNewsStreamWithTools(userQuestion string, sysProm
|
||||
})
|
||||
}()
|
||||
wg.Wait()
|
||||
|
||||
news := NewMarketNewsApi().GetNewsList("财联社电报", random.RandInt(100, 500))
|
||||
news := NewMarketNewsApi().GetNewsList2("财联社电报", random.RandInt(100, 500))
|
||||
messageText := strings.Builder{}
|
||||
for _, telegraph := range *news {
|
||||
messageText.WriteString("## " + telegraph.Time + ":" + "\n")
|
||||
@@ -473,7 +472,7 @@ func (o *OpenAi) NewSummaryStockNewsStream(userQuestion string, sysPromptId *int
|
||||
|
||||
wg.Wait()
|
||||
|
||||
news := NewMarketNewsApi().GetNewsList("", 100)
|
||||
news := NewMarketNewsApi().GetNewsList2("财联社电报", random.RandInt(100, 500))
|
||||
messageText := strings.Builder{}
|
||||
for _, telegraph := range *news {
|
||||
messageText.WriteString("## " + telegraph.Time + ":" + "\n")
|
||||
@@ -808,25 +807,25 @@ func (o *OpenAi) NewChatStream(stock, stockCode, userQuestion string, sysPromptI
|
||||
return
|
||||
}
|
||||
|
||||
messages := SearchGuShiTongStockInfo(stockCode, o.CrawlTimeOut)
|
||||
if messages == nil || len(*messages) == 0 {
|
||||
logger.SugaredLogger.Error("获取股势通资讯失败")
|
||||
//ch <- "***❗获取股势通资讯失败,分析结果可能不准确***<hr>"
|
||||
//go runtime.EventsEmit(o.ctx, "warnMsg", "❗获取股势通资讯失败,分析结果可能不准确")
|
||||
return
|
||||
}
|
||||
var newsText strings.Builder
|
||||
for _, message := range *messages {
|
||||
newsText.WriteString(message + "\n")
|
||||
}
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "user",
|
||||
"content": stock + "相关新闻资讯",
|
||||
})
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "assistant",
|
||||
"content": newsText.String(),
|
||||
})
|
||||
//messages := SearchGuShiTongStockInfo(stockCode, o.CrawlTimeOut)
|
||||
//if messages == nil || len(*messages) == 0 {
|
||||
// logger.SugaredLogger.Error("获取股势通资讯失败")
|
||||
// //ch <- "***❗获取股势通资讯失败,分析结果可能不准确***<hr>"
|
||||
// //go runtime.EventsEmit(o.ctx, "warnMsg", "❗获取股势通资讯失败,分析结果可能不准确")
|
||||
// return
|
||||
//}
|
||||
//var newsText strings.Builder
|
||||
//for _, message := range *messages {
|
||||
// newsText.WriteString(message + "\n")
|
||||
//}
|
||||
//msg = append(msg, map[string]interface{}{
|
||||
// "role": "user",
|
||||
// "content": stock + "相关新闻资讯",
|
||||
//})
|
||||
//msg = append(msg, map[string]interface{}{
|
||||
// "role": "assistant",
|
||||
// "content": newsText.String(),
|
||||
//})
|
||||
}()
|
||||
|
||||
go func() {
|
||||
@@ -1155,7 +1154,7 @@ func AskAiWithTools(o *OpenAi, err error, messages []map[string]interface{}, ch
|
||||
}
|
||||
|
||||
content := "无符合条件的数据"
|
||||
res := NewSearchStockApi(words).SearchStock(random.RandInt(5, 10))
|
||||
res := NewSearchStockApi(words).SearchStock(random.RandInt(5, 20))
|
||||
if convertor.ToString(res["code"]) == "100" {
|
||||
resData := res["data"].(map[string]any)
|
||||
result := resData["result"].(map[string]any)
|
||||
@@ -1366,6 +1365,140 @@ func AskAiWithTools(o *OpenAi, err error, messages []map[string]interface{}, ch
|
||||
"tool_call_id": currentCallId,
|
||||
})
|
||||
}
|
||||
//
|
||||
//if funcName == "QueryBKDictInfo" {
|
||||
// ch <- map[string]any{
|
||||
// "code": 1,
|
||||
// "question": question,
|
||||
// "chatId": streamResponse.Id,
|
||||
// "model": streamResponse.Model,
|
||||
// "content": "\r\n```\r\n开始调用工具:QueryBKDictInfo,\n参数:" + funcArguments + "\r\n```\r\n",
|
||||
// "time": time.Now().Format(time.DateTime),
|
||||
// }
|
||||
// res := NewMarketNewsApi().EMDictCode("016", freecache.NewCache(100))
|
||||
// bytes, err := json.Marshal(res)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// dict := &[]models.BKDict{}
|
||||
// json.Unmarshal(bytes, dict)
|
||||
// md := util.MarkdownTableWithTitle("行业/板块代码", dict)
|
||||
// logger.SugaredLogger.Infof("行业/板块代码=\n%s", md)
|
||||
// messages = append(messages, map[string]interface{}{
|
||||
// "role": "assistant",
|
||||
// "content": currentAIContent.String(),
|
||||
// "tool_calls": []map[string]any{
|
||||
// {
|
||||
// "id": currentCallId,
|
||||
// "tool_call_id": currentCallId,
|
||||
// "type": "function",
|
||||
// "function": map[string]string{
|
||||
// "name": funcName,
|
||||
// "arguments": funcArguments,
|
||||
// "parameters": funcArguments,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
// messages = append(messages, map[string]interface{}{
|
||||
// "role": "tool",
|
||||
// "content": md,
|
||||
// "tool_call_id": currentCallId,
|
||||
// })
|
||||
//}
|
||||
|
||||
//if funcName == "GetIndustryResearchReport" {
|
||||
// bkCode := gjson.Get(funcArguments, "bkCode").String()
|
||||
// ch <- map[string]any{
|
||||
// "code": 1,
|
||||
// "question": question,
|
||||
// "chatId": streamResponse.Id,
|
||||
// "model": streamResponse.Model,
|
||||
// "content": "\r\n```\r\n开始调用工具:GetIndustryResearchReport,\n参数:" + bkCode + "\r\n```\r\n",
|
||||
// "time": time.Now().Format(time.DateTime),
|
||||
// }
|
||||
// bkCode = strutil.ReplaceWithMap(bkCode, map[string]string{
|
||||
// "-": "",
|
||||
// "_": "",
|
||||
// "bk": "",
|
||||
// "BK": "",
|
||||
// "bk0": "",
|
||||
// "BK0": "",
|
||||
// })
|
||||
//
|
||||
// logger.SugaredLogger.Debugf("code:%s", bkCode)
|
||||
// codeStr := convertor.ToString(bkCode)
|
||||
// res := NewMarketNewsApi().IndustryResearchReport(codeStr, 7)
|
||||
// md := strings.Builder{}
|
||||
// for _, a := range res {
|
||||
// d := a.(map[string]any)
|
||||
// md.WriteString(NewMarketNewsApi().GetIndustryReportInfo(d["infoCode"].(string)))
|
||||
// }
|
||||
// logger.SugaredLogger.Infof("bkCode:%s IndustryResearchReport:\n %s", bkCode, md.String())
|
||||
// messages = append(messages, map[string]interface{}{
|
||||
// "role": "assistant",
|
||||
// "content": currentAIContent.String(),
|
||||
// "tool_calls": []map[string]any{
|
||||
// {
|
||||
// "id": currentCallId,
|
||||
// "tool_call_id": currentCallId,
|
||||
// "type": "function",
|
||||
// "function": map[string]string{
|
||||
// "name": funcName,
|
||||
// "arguments": funcArguments,
|
||||
// "parameters": funcArguments,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
// messages = append(messages, map[string]interface{}{
|
||||
// "role": "tool",
|
||||
// "content": md.String(),
|
||||
// "tool_call_id": currentCallId,
|
||||
// })
|
||||
//}
|
||||
|
||||
if funcName == "GetStockResearchReport" {
|
||||
stockCode := gjson.Get(funcArguments, "stockCode").String()
|
||||
ch <- map[string]any{
|
||||
"code": 1,
|
||||
"question": question,
|
||||
"chatId": streamResponse.Id,
|
||||
"model": streamResponse.Model,
|
||||
"content": "\r\n```\r\n开始调用工具:GetStockResearchReport,\n参数:" + stockCode + "\r\n```\r\n",
|
||||
"time": time.Now().Format(time.DateTime),
|
||||
}
|
||||
res := NewMarketNewsApi().StockResearchReport(stockCode, 7)
|
||||
md := strings.Builder{}
|
||||
for _, a := range res {
|
||||
logger.SugaredLogger.Debugf("value: %+v", a)
|
||||
d := a.(map[string]any)
|
||||
logger.SugaredLogger.Debugf("value: %s infoCode:%s", d["title"], d["infoCode"])
|
||||
md.WriteString(NewMarketNewsApi().GetIndustryReportInfo(d["infoCode"].(string)))
|
||||
}
|
||||
logger.SugaredLogger.Infof("stockCode:%s StockResearchReport:\n %s", stockCode, md.String())
|
||||
messages = append(messages, map[string]interface{}{
|
||||
"role": "assistant",
|
||||
"content": currentAIContent.String(),
|
||||
"tool_calls": []map[string]any{
|
||||
{
|
||||
"id": currentCallId,
|
||||
"tool_call_id": currentCallId,
|
||||
"type": "function",
|
||||
"function": map[string]string{
|
||||
"name": funcName,
|
||||
"arguments": funcArguments,
|
||||
"parameters": funcArguments,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
messages = append(messages, map[string]interface{}{
|
||||
"role": "tool",
|
||||
"content": md.String(),
|
||||
"tool_call_id": currentCallId,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
AskAiWithTools(o, err, messages, ch, question, tools)
|
||||
|
||||
@@ -3,6 +3,7 @@ package data
|
||||
import (
|
||||
"context"
|
||||
"go-stock/backend/db"
|
||||
log "go-stock/backend/logger"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -52,9 +53,12 @@ func TestGetTopNewsList(t *testing.T) {
|
||||
|
||||
func TestSearchGuShiTongStockInfo(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
SearchGuShiTongStockInfo("hk01810", 60)
|
||||
SearchGuShiTongStockInfo("sh600745", 60)
|
||||
SearchGuShiTongStockInfo("gb_goog", 60)
|
||||
//SearchGuShiTongStockInfo("hk01810", 60)
|
||||
msgs := SearchGuShiTongStockInfo("sh600745", 60)
|
||||
for _, msg := range *msgs {
|
||||
log.SugaredLogger.Infof("%s", msg)
|
||||
}
|
||||
//SearchGuShiTongStockInfo("gb_goog", 60)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,10 @@ package data
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"go-stock/backend/logger"
|
||||
"time"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
)
|
||||
|
||||
// @Author spark
|
||||
@@ -25,25 +26,25 @@ func (s SearchStockApi) SearchStock(pageSize int) map[string]any {
|
||||
SetHeader("Host", "np-tjxg-g.eastmoney.com").
|
||||
SetHeader("Origin", "https://xuangu.eastmoney.com").
|
||||
SetHeader("Referer", "https://xuangu.eastmoney.com/").
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0").
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(fmt.Sprintf(`{
|
||||
"keyWord": "%s",
|
||||
"pageSize": %d,
|
||||
"pageNo": 1,
|
||||
"fingerprint": "e38b5faabf9378c8238e57219f0ebc9b",
|
||||
"fingerprint": "02efa8944b1f90fbfe050e1e695a480d",
|
||||
"gids": [],
|
||||
"matchWord": "",
|
||||
"timestamp": "1751113883290349",
|
||||
"timestamp": "%d",
|
||||
"shareToGuba": false,
|
||||
"requestId": "8xTWgCDAjvQ5lmvz5mDA3Ydk2AE4yoiJ1751113883290",
|
||||
"requestId": "RMd3Y76AJI98axPvdhdbKvbBDVwLlUK61761559950168",
|
||||
"needCorrect": true,
|
||||
"removedConditionIdList": [],
|
||||
"xcId": "xc0af28549ab330013ed",
|
||||
"xcId": "xc0d61279aad33008260",
|
||||
"ownSelectAll": false,
|
||||
"dxInfo": [],
|
||||
"extraCondition": ""
|
||||
}`, s.words, pageSize)).Post(url)
|
||||
}`, s.words, pageSize, time.Now().Unix())).Post(url)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("SearchStock-err:%+v", err)
|
||||
return map[string]any{}
|
||||
|
||||
@@ -2,16 +2,18 @@ package data
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
"go-stock/backend/db"
|
||||
"go-stock/backend/logger"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func TestSearchStock(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
|
||||
res := NewSearchStockApi("算力股;净利润连续3年增长").SearchStock(10)
|
||||
res := NewSearchStockApi("量比大于2,基本面优秀,2025年三季报已披露,主力连续3日净流入,非创业板非科创板非ST").SearchStock(20)
|
||||
logger.SugaredLogger.Infof("res:%+v", res)
|
||||
data := res["data"].(map[string]any)
|
||||
result := data["result"].(map[string]any)
|
||||
dataList := result["dataList"].([]any)
|
||||
|
||||
@@ -3,11 +3,12 @@ package data
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/samber/lo"
|
||||
"go-stock/backend/db"
|
||||
"go-stock/backend/logger"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Settings struct {
|
||||
@@ -35,6 +36,7 @@ type Settings struct {
|
||||
SponsorCode string `json:"sponsorCode"`
|
||||
HttpProxy string `json:"httpProxy"`
|
||||
HttpProxyEnabled bool `json:"httpProxyEnabled"`
|
||||
EnableAgent bool `json:"enableAgent"`
|
||||
}
|
||||
|
||||
func (receiver Settings) TableName() string {
|
||||
@@ -105,6 +107,7 @@ func UpdateConfig(s *SettingConfig) string {
|
||||
"sponsor_code": s.SponsorCode,
|
||||
"http_proxy": s.HttpProxy,
|
||||
"http_proxy_enabled": s.HttpProxyEnabled,
|
||||
"enable_agent": s.EnableAgent,
|
||||
})
|
||||
|
||||
//更新AiConfig
|
||||
|
||||
@@ -9,6 +9,14 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go-stock/backend/db"
|
||||
"go-stock/backend/logger"
|
||||
"go-stock/backend/models"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/chromedp/chromedp"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
@@ -17,17 +25,10 @@ import (
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/robertkrimen/otto"
|
||||
"github.com/samber/lo"
|
||||
"go-stock/backend/db"
|
||||
"go-stock/backend/logger"
|
||||
"go-stock/backend/models"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"golang.org/x/text/transform"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/plugin/soft_delete"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const sinaStockUrl = "http://hq.sinajs.cn/rn=%d&list=%s"
|
||||
@@ -1744,6 +1745,11 @@ func (receiver StockDataApi) GetCommonKLineData(stockCode string, kLineType stri
|
||||
return K
|
||||
}
|
||||
|
||||
// GetStockHistoryMoneyData 获取股票历史资金流向数据
|
||||
func (receiver StockDataApi) GetStockHistoryMoneyData() {
|
||||
|
||||
}
|
||||
|
||||
// JSONToMarkdownTable 将JSON数据转换为Markdown表格
|
||||
func JSONToMarkdownTable(jsonData []byte) (string, error) {
|
||||
var data []map[string]interface{}
|
||||
|
||||
@@ -265,3 +265,20 @@ func TestStockDataApi_GetIndexBasic(t *testing.T) {
|
||||
stockDataApi := NewStockDataApi()
|
||||
stockDataApi.GetIndexBasic()
|
||||
}
|
||||
|
||||
func TestName(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
|
||||
stockBasics := &[]StockBasic{}
|
||||
resty.New().R().
|
||||
SetHeader("user", "go-stock").
|
||||
SetResult(stockBasics).
|
||||
Get("http://8.134.249.145:18080/go-stock/stock_basic.json")
|
||||
|
||||
db.Dao.Unscoped().Model(&StockBasic{}).Where("1=1").Delete(&StockBasic{})
|
||||
err := db.Dao.CreateInBatches(stockBasics, 400).Error
|
||||
if err != nil {
|
||||
t.Log(err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,21 +2,32 @@ package data
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"go-stock/backend/db"
|
||||
"go-stock/backend/logger"
|
||||
"go-stock/backend/models"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
"github.com/go-ego/gse"
|
||||
)
|
||||
|
||||
const basefreq float64 = 100
|
||||
|
||||
// 金融情感词典,包含股票市场相关的专业词汇
|
||||
var (
|
||||
seg gse.Segmenter
|
||||
|
||||
// 正面金融词汇及其权重
|
||||
positiveFinanceWords = map[string]float64{
|
||||
"上涨": 2.0, "涨停": 3.0, "牛市": 3.0, "反弹": 2.0, "新高": 2.5,
|
||||
"涨": 1.0, "上涨": 2.0, "涨停": 3.0, "牛市": 3.0, "反弹": 2.0, "新高": 2.5,
|
||||
"利好": 2.5, "增持": 2.0, "买入": 2.0, "推荐": 1.5, "看多": 2.0,
|
||||
"盈利": 2.0, "增长": 2.0, "超预期": 2.5, "强劲": 1.5, "回升": 1.5,
|
||||
"复苏": 2.0, "突破": 2.0, "创新高": 3.0, "回暖": 1.5, "上扬": 1.5,
|
||||
@@ -27,13 +38,13 @@ var (
|
||||
|
||||
// 负面金融词汇及其权重
|
||||
negativeFinanceWords = map[string]float64{
|
||||
"下跌": 2.0, "跌停": 3.0, "熊市": 3.0, "回调": 1.5, "新低": 2.5,
|
||||
"跌": 1.0, "下跌": 2.0, "跌停": 3.0, "熊市": 3.0, "回调": 1.5, "新低": 2.5,
|
||||
"利空": 2.5, "减持": 2.0, "卖出": 2.0, "看空": 2.0, "亏损": 2.5,
|
||||
"下滑": 2.0, "萎缩": 2.0, "不及预期": 2.5, "疲软": 1.5, "恶化": 2.0,
|
||||
"衰退": 2.0, "跌破": 2.0, "创新低": 3.0, "走弱": 1.5, "下挫": 1.5,
|
||||
"利空消息": 3.0, "收益下降": 2.5, "利润下滑": 2.5, "业绩不佳": 2.5,
|
||||
"垃圾股": 2.0, "风险股": 2.0, "弱势": 1.5, "走低": 1.5, "缩量": 2.5,
|
||||
"大跌": 2.5, "暴跌": 3.0, "崩盘": 3.0, "跳水": 3.0, "重挫": 3.0,
|
||||
"大跌": 2.5, "暴跌": 3.0, "崩盘": 3.0, "跳水": 3.0, "重挫": 3.0, "跌超": 2.5, "跌逾": 2.5,
|
||||
}
|
||||
|
||||
// 否定词,用于反转情感极性
|
||||
@@ -45,7 +56,7 @@ var (
|
||||
degreeWords = map[string]float64{
|
||||
"非常": 1.8, "极其": 2.2, "太": 1.8, "很": 1.5,
|
||||
"比较": 0.8, "稍微": 0.6, "有点": 0.7, "显著": 1.5,
|
||||
"大幅": 1.8, "急剧": 2.0, "轻微": 0.6, "小幅": 0.7,
|
||||
"大幅": 1.8, "急剧": 2.0, "轻微": 0.6, "小幅": 0.7, "逾": 1.8,
|
||||
}
|
||||
|
||||
// 转折词,用于识别情感转折
|
||||
@@ -54,12 +65,222 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 加载默认词典
|
||||
err := seg.LoadDict()
|
||||
//go:embed data/dict/base.txt
|
||||
var baseDict string
|
||||
|
||||
//go:embed data/dict/zh/s_1.txt
|
||||
var zhDict string
|
||||
|
||||
func InitAnalyzeSentiment() {
|
||||
logger.SugaredLogger.Infof("初始化词典库路径:%s", fileutil.CurrentPath())
|
||||
err := seg.LoadDictEmbed(baseDict)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Error(err.Error())
|
||||
} else {
|
||||
logger.SugaredLogger.Info("加载默认词典成功")
|
||||
}
|
||||
stocks := &[]StockBasic{}
|
||||
db.Dao.Model(&StockBasic{}).Find(stocks)
|
||||
for _, stock := range *stocks {
|
||||
if strutil.Trim(stock.Name) == "" {
|
||||
continue
|
||||
}
|
||||
err := seg.AddToken(stock.Name, basefreq+500, "n")
|
||||
if strutil.Trim(stock.BKName) != "" {
|
||||
err = seg.AddToken(stock.BKName, basefreq+500, "n")
|
||||
}
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("添加%s失败:%s", stock.Name, err.Error())
|
||||
}
|
||||
}
|
||||
stockhks := &[]models.StockInfoHK{}
|
||||
db.Dao.Model(&models.StockInfoHK{}).Find(stockhks)
|
||||
for _, stock := range *stockhks {
|
||||
if strutil.Trim(stock.Name) == "" {
|
||||
continue
|
||||
}
|
||||
err := seg.AddToken(stock.Name, basefreq+500, "n")
|
||||
if strutil.Trim(stock.BKName) != "" {
|
||||
err = seg.AddToken(stock.BKName, basefreq+500, "n")
|
||||
}
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("添加%s失败:%s", stock.Name, err.Error())
|
||||
}
|
||||
}
|
||||
//stockus := &[]models.StockInfoUS{}
|
||||
//db.Dao.Model(&models.StockInfoUS{}).Where("trim(name) != ?", "").Find(stockus)
|
||||
//for _, stock := range *stockus {
|
||||
// err := seg.AddToken(stock.Name, 500)
|
||||
// if err != nil {
|
||||
// logger.SugaredLogger.Errorf("添加%s失败:%s", stock.Name, err.Error())
|
||||
// }
|
||||
//}
|
||||
tags := &[]models.Tags{}
|
||||
db.Dao.Model(&models.Tags{}).Find(tags)
|
||||
for _, tag := range *tags {
|
||||
err := seg.AddToken(tag.Name, basefreq, "n")
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("添加%s失败:%s", tag.Name, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
//加载用户自定义词典 先判断用户词典是否存在
|
||||
if fileutil.IsExist(fileutil.CurrentPath() + "/data/dict/user.txt") {
|
||||
lines, err := fileutil.ReadFileByLine(fileutil.CurrentPath() + "/data/dict/user.txt")
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
for _, line := range lines {
|
||||
k := strutil.SplitAndTrim(line, " ")
|
||||
switch len(k) {
|
||||
case 1:
|
||||
err = seg.AddToken(k[0], 100)
|
||||
case 2:
|
||||
freq, _ := convertor.ToFloat(k[1])
|
||||
err = seg.AddToken(k[0], freq)
|
||||
case 3:
|
||||
freq, _ := convertor.ToFloat(k[1])
|
||||
err = seg.AddToken(k[0], freq, k[2])
|
||||
default:
|
||||
logger.SugaredLogger.Errorf("用户词典格式错误:%s", line)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Error(err.Error())
|
||||
} else {
|
||||
logger.SugaredLogger.Error("加载用户词典成功")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WordFreqWithWeight 词频统计结果,包含权重信息
|
||||
type WordFreqWithWeight struct {
|
||||
Word string
|
||||
Frequency int
|
||||
Weight float64
|
||||
Score float64
|
||||
}
|
||||
|
||||
// getWordWeight 获取词汇权重
|
||||
func getWordWeight(word string) float64 {
|
||||
// 从分词器获取词汇权重
|
||||
|
||||
freq, pos, ok := seg.Dictionary().Find([]byte(word))
|
||||
if ok && pos == "n" {
|
||||
return basefreq + freq
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// SortByWeightAndFrequency 按权重和频次排序词频结果
|
||||
func SortByWeightAndFrequency(frequencies map[string]WordFreqWithWeight) []WordFreqWithWeight {
|
||||
// 将map转换为slice以便排序
|
||||
freqSlice := make([]WordFreqWithWeight, 0, len(frequencies))
|
||||
for _, freq := range frequencies {
|
||||
freqSlice = append(freqSlice, freq)
|
||||
}
|
||||
|
||||
// 按权重*频次降序排列
|
||||
sort.Slice(freqSlice, func(i, j int) bool {
|
||||
return freqSlice[i].Weight*float64(freqSlice[i].Frequency) > freqSlice[j].Weight*float64(freqSlice[j].Frequency)
|
||||
})
|
||||
logger.SugaredLogger.Infof("排序后的结果:%v", freqSlice)
|
||||
|
||||
return freqSlice
|
||||
}
|
||||
|
||||
// FilterAndSortWords 过滤标点符号并按权重频次排序
|
||||
func FilterAndSortWords(frequencies map[string]WordFreqWithWeight) []WordFreqWithWeight {
|
||||
// 先过滤标点符号和分隔符
|
||||
cleanFrequencies := FilterPunctuationAndSeparators(frequencies)
|
||||
|
||||
// 再按权重和频次排序
|
||||
sortedFrequencies := SortByWeightAndFrequency(cleanFrequencies)
|
||||
|
||||
return sortedFrequencies
|
||||
}
|
||||
func FilterPunctuationAndSeparators(frequencies map[string]WordFreqWithWeight) map[string]WordFreqWithWeight {
|
||||
filteredWords := make(map[string]WordFreqWithWeight)
|
||||
|
||||
for word, freqInfo := range frequencies {
|
||||
// 过滤纯标点符号和分隔符
|
||||
if !isPunctuationOrSeparator(word) {
|
||||
filteredWords[word] = freqInfo
|
||||
}
|
||||
}
|
||||
return filteredWords
|
||||
}
|
||||
|
||||
// isPunctuationOrSeparator 判断是否为标点符号或分隔符
|
||||
func isPunctuationOrSeparator(word string) bool {
|
||||
// 空字符串
|
||||
if strings.TrimSpace(word) == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
// 检查是否全部由标点符号组成
|
||||
for _, r := range word {
|
||||
if !unicode.IsPunct(r) && !unicode.IsSymbol(r) && !unicode.IsSpace(r) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// FilterWithRegex 使用正则表达式过滤标点和特殊字符
|
||||
func FilterWithRegex(frequencies map[string]WordFreqWithWeight) map[string]WordFreqWithWeight {
|
||||
filteredWords := make(map[string]WordFreqWithWeight)
|
||||
|
||||
// 匹配标点符号、特殊字符的正则表达式
|
||||
punctuationRegex := regexp.MustCompile(`^[[:punct:][:space:]]+$`)
|
||||
|
||||
for word, freqInfo := range frequencies {
|
||||
// 过滤纯标点符号
|
||||
if !punctuationRegex.MatchString(word) && strings.TrimSpace(word) != "" {
|
||||
filteredWords[word] = freqInfo
|
||||
}
|
||||
}
|
||||
return filteredWords
|
||||
}
|
||||
|
||||
// countWordFrequencyWithWeight 统计词频并包含权重信息
|
||||
func countWordFrequencyWithWeight(text string) map[string]WordFreqWithWeight {
|
||||
words := splitWords(text)
|
||||
freqMap := make(map[string]WordFreqWithWeight)
|
||||
|
||||
// 统计词频
|
||||
wordCount := make(map[string]int)
|
||||
for _, word := range words {
|
||||
wordCount[word]++
|
||||
}
|
||||
|
||||
// 构建包含权重的结果
|
||||
for word, frequency := range wordCount {
|
||||
weight := getWordWeight(word)
|
||||
if weight > 0 {
|
||||
freqMap[word] = WordFreqWithWeight{
|
||||
Word: word,
|
||||
Frequency: frequency,
|
||||
Weight: weight,
|
||||
Score: float64(frequency) * weight,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return freqMap
|
||||
}
|
||||
|
||||
// AnalyzeSentimentWithFreqWeight 带权重词频统计的情感分析
|
||||
func AnalyzeSentimentWithFreqWeight(text string) (SentimentResult, map[string]WordFreqWithWeight) {
|
||||
// 原有情感分析逻辑
|
||||
result := AnalyzeSentiment(text)
|
||||
|
||||
// 带权重的词频统计
|
||||
frequencies := countWordFrequencyWithWeight(text)
|
||||
|
||||
return result, frequencies
|
||||
}
|
||||
|
||||
// SentimentResult 情感分析结果类型
|
||||
|
||||
@@ -2,6 +2,8 @@ package data
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go-stock/backend/db"
|
||||
"go-stock/backend/logger"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -12,25 +14,32 @@ import (
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
func TestAnalyzeSentiment(t *testing.T) {
|
||||
// 分析情感
|
||||
text := " 【调查:韩国近两成中小学生过度使用智能手机或互联网】财联社6月19日电,韩国女性家族部18日公布的一项年度调查结果显示,接受调查的韩国中小学生中,共计约17.3%、即超过21万人使用智能手机或互联网的程度达到了“危险水平”,这意味着他们因过度依赖智能手机或互联网而需要关注或干预,这一比例引人担忧。 (新华社)\n"
|
||||
text = "消息人士称,联合利华(Unilever)正在为Graze零食品牌寻找买家。\n"
|
||||
text = "【韩国未来5年将投入51万亿韩元发展文化产业】 据韩联社,韩国文化体育观光部(文体部)今后5年将投入51万亿韩元(约合人民币2667亿元)预算,落实总统李在明在竞选时期提出的“将韩国打造成全球五大文化强国之一”的承诺。\n"
|
||||
//text = "【油气股持续拉升 国际实业午后涨停】财联社6月19日电,油气股午后持续拉升,国际实业、宝莫股份午后涨停,准油股份、山东墨龙。茂化实华此前涨停,通源石油、海默科技、贝肯能源、中曼石油、科力股份等多股涨超5%。\n"
|
||||
//text = " 【三大指数均跌逾1% 下跌个股近4800只】财联社6月19日电,指数持续走弱,沪指下挫跌逾1.00%,深成指跌1.25%,创业板指跌1.39%。核聚变、风电、军工、食品消费等板块指数跌幅居前,沪深京三市下跌个股近4800只。\n"
|
||||
text = "【银行理财首单网下打新落地】财联社6月20日电,记者从多渠道获悉,光大理财以申报价格17元参与信通电子网下打新,并成功入围有效报价,成为行业内首家参与网下打新的银行理财公司。光大理财工作人员向证券时报记者表示,本次光大理财是以其管理的混合类产品“阳光橙增盈绝对收益策略”参与了此次网下打新,该产品为光大理财“固收+”银行理财产品。资料显示,信通电子成立于1996年,核心产品包括输电线路智能巡检系统、变电站智能辅控系统、移动智能终端及其他产品。根据其招股说明书,信通电子2023、2024年营业收入分别较上年增长19.08%和7.97%,净利润分别较上年增长5.6%和15.11%。 (证券时报)"
|
||||
text = " 【以军称拦截数枚伊朗导弹】财联社6月20日电,据央视新闻报道,以军在贝尔谢巴及周边区域拦截了数枚伊朗导弹,但仍有导弹或拦截残骸落地。以色列国防军发文表示,搜救队伍正在一处“空中物体落地”的所在区域开展工作,公众目前可以离开避难场所。伊朗方面对上述说法暂无回应。"
|
||||
|
||||
db.Init("../../data/stock.db")
|
||||
InitAnalyzeSentiment()
|
||||
|
||||
messageText := strings.Builder{}
|
||||
//news := NewMarketNewsApi().GetNewsList2("", random.RandInt(500, 1000))
|
||||
//for _, telegraph := range *news {
|
||||
// messageText.WriteString(telegraph.Content + "\n")
|
||||
//}
|
||||
|
||||
text := messageText.String()
|
||||
text = " 【周六你需要知道的隔夜全球要闻:美联储鸽声重振 美股走势回稳】 1、纽约联储行长威廉姆斯表示,随着劳动力市场走软,美联储近期内仍有再次降息的空间。 2、美联储理事斯蒂芬·米兰表示,自上次联邦公开市场委员会(FOMC)会议以来的经济数据应“促使人们偏向鸽派立场”。 3、波士顿联邦储备银行行长柯林斯表示,由于通胀可能在一段时间内保持高位,维持利率不变“目前合适”。 4、据CME“美联储观察”,截至北京时间11月22日6时30分,美联储12月降息25个基点的概率为69.4%,维持利率不变的概率为30.6%。 5、美国劳工统计局表示,11月CPI报告将于12月18日发布,同时取消了10月CPI报告发布,表示无法追溯采集政府停摆期间未能收集的部分数据。 6、俄罗斯总统普京表示,已收到美提出解决俄乌冲突的计划,俄罗斯愿意进行和平谈判。美国总统特朗普表示,他认为27日是乌克兰接受美国支持的和平计划的最后期限。 7、美联储高官鸽派言论提振市场情绪,美股三大指数收盘集体上涨,道琼斯指数涨1.08%,标普500指数涨0.98%,纳斯达克综合指数涨0.88%。甲骨文跌超5%,英伟达跌超1%。纳指本周累计跌2.74%,标普500指数累跌1.95%,道指累跌1.91%。英伟达本周累跌5.9%。 8、热门中概股多数上涨,纳斯达克中国金龙指数收涨1.23%。蔚来涨超3%,哔哩哔哩、理想汽车涨超2%,京东、小鹏汽车涨超1%。 9、国际油价下跌,交易员评估乌克兰与俄罗斯可能达成和平协议的前景。WTI 1月期货下跌1.6%,结算价报每桶58.06美元,为过去五个交易日中第四次下跌。布伦特1月期货下跌1.3%,结算价报每桶62.56美元。 10、美联储延长压力测试改进方案征询期,为银行反馈提供更多时间。 11、由于美国人对个人财务状况的看法恶化,美国消费者信心在11月跌至接近纪录最低水平;密歇根大学数据显示,11月消费者信心指数降至51,10月为53.6。 12、日本央行政策委员会委员Kazuyuki Masu表示,日本央行接近作出加息决定。 13、穆迪将意大利信用评级从BAA3上调至BAA2,展望稳定。\n"
|
||||
text = "财联社电:英伟达周五冲高回落,股价涨幅收于1%,市场普遍认为其走势疲软"
|
||||
// 分析情感
|
||||
words := splitWords(text)
|
||||
fmt.Println(strings.Join(words, " "))
|
||||
|
||||
result := AnalyzeSentiment(text)
|
||||
|
||||
result, frequencies := AnalyzeSentimentWithFreqWeight(text)
|
||||
// 过滤标点符号和分隔符
|
||||
cleanFrequencies := FilterPunctuationAndSeparators(frequencies)
|
||||
// 输出结果
|
||||
fmt.Printf("情感分析结果: %s (得分: %.2f, 正面词:%d, 负面词:%d)\n",
|
||||
logger.SugaredLogger.Infof("情感分析结果: %s (得分: %.2f, 正面词:%d, 负面词:%d)\n 词频统计结果: %v",
|
||||
result.Description,
|
||||
result.Score,
|
||||
result.PositiveCount,
|
||||
result.NegativeCount)
|
||||
result.NegativeCount,
|
||||
cleanFrequencies,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/plugin/soft_delete"
|
||||
"time"
|
||||
)
|
||||
|
||||
// @Author spark
|
||||
@@ -231,6 +232,7 @@ type Prompt struct {
|
||||
type Telegraph struct {
|
||||
gorm.Model
|
||||
Time string `json:"time"`
|
||||
DataTime *time.Time `json:"dataTime"`
|
||||
Content string `json:"content"`
|
||||
SubjectTags []string `json:"subjects" gorm:"-:all"`
|
||||
StocksTags []string `json:"stocks" gorm:"-:all"`
|
||||
@@ -238,7 +240,7 @@ type Telegraph struct {
|
||||
Url string `json:"url"`
|
||||
Source string `json:"source"`
|
||||
TelegraphTags []TelegraphTags `json:"tags" gorm:"-:migration;foreignKey:TelegraphId"`
|
||||
SentimentResult string `json:"sentimentResult" gorm:"-:all"`
|
||||
SentimentResult string `json:"sentimentResult"`
|
||||
}
|
||||
type TelegraphTags struct {
|
||||
gorm.Model
|
||||
@@ -687,3 +689,16 @@ type CailianpressWeb struct {
|
||||
Author string `json:"author" md:"资讯发布者"`
|
||||
} `json:"list"`
|
||||
}
|
||||
|
||||
type BKDict struct {
|
||||
gorm.Model `md:"-"`
|
||||
BkCode string `json:"bkCode" md:"行业/板块代码"`
|
||||
BkName string `json:"bkName" md:"行业/板块名称"`
|
||||
FirstLetter string `json:"firstLetter" md:"first_letter"`
|
||||
FubkCode string `json:"fubkCode" md:"fubk_code"`
|
||||
PublishCode string `json:"publishCode" md:"publish_code"`
|
||||
}
|
||||
|
||||
func (b BKDict) TableName() string {
|
||||
return "bk_dict"
|
||||
}
|
||||
|
||||
1
frontend/components.d.ts
vendored
1
frontend/components.d.ts
vendored
@@ -11,6 +11,7 @@ declare module 'vue' {
|
||||
About: typeof import('./src/components/about.vue')['default']
|
||||
AgentChat: typeof import('./src/components/agent-chat.vue')['default']
|
||||
AgentChat_bk: typeof import('./src/components/agent-chat_bk.vue')['default']
|
||||
AnalyzeMartket: typeof import('./src/components/AnalyzeMartket.vue')['default']
|
||||
ClsCalendarTimeLine: typeof import('./src/components/ClsCalendarTimeLine.vue')['default']
|
||||
EmbeddedUrl: typeof import('./src/components/EmbeddedUrl.vue')['default']
|
||||
Fund: typeof import('./src/components/fund.vue')['default']
|
||||
|
||||
@@ -6,7 +6,8 @@ import {
|
||||
Quit,
|
||||
WindowFullscreen,
|
||||
WindowHide,
|
||||
WindowUnfullscreen
|
||||
WindowUnfullscreen,
|
||||
WindowSetTitle
|
||||
} from '../wailsjs/runtime'
|
||||
import {h, onBeforeMount, onBeforeUnmount, onMounted, ref} from "vue";
|
||||
import {RouterLink, useRouter} from 'vue-router'
|
||||
@@ -43,6 +44,7 @@ const loadingMsg = ref("加载数据中...")
|
||||
const enableNews = ref(false)
|
||||
const contentStyle = ref("")
|
||||
const enableFund = ref(false)
|
||||
const enableAgent = ref(false)
|
||||
const enableDarkTheme = ref(null)
|
||||
const content = ref('未经授权,禁止商业目的!\n\n数据来源于网络,仅供参考;投资有风险,入市需谨慎')
|
||||
const isFullscreen = ref(false)
|
||||
@@ -440,6 +442,7 @@ const menuOptions = ref([
|
||||
{default: () => 'Ai智能体'}
|
||||
),
|
||||
key: 'agent',
|
||||
show:enableAgent.value,
|
||||
icon: renderIcon(Robot),
|
||||
},
|
||||
{
|
||||
@@ -646,11 +649,15 @@ onBeforeMount(() => {
|
||||
GetConfig().then((res) => {
|
||||
//console.log(res)
|
||||
enableFund.value = res.enableFund
|
||||
enableAgent.value = res.enableAgent
|
||||
|
||||
menuOptions.value.filter((item) => {
|
||||
if (item.key === 'fund') {
|
||||
item.show = res.enableFund
|
||||
}
|
||||
if (item.key === 'agent') {
|
||||
item.show = res.enableAgent
|
||||
}
|
||||
})
|
||||
|
||||
if (res.darkTheme) {
|
||||
@@ -662,12 +669,14 @@ onBeforeMount(() => {
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
WindowSetTitle("go-stock:AI赋能股票分析✨ 未经授权,禁止商业目的! [数据来源于网络,仅供参考;投资有风险,入市需谨慎]")
|
||||
contentStyle.value = "max-height: calc(92vh);overflow: hidden"
|
||||
GetConfig().then((res) => {
|
||||
if (res.enableNews) {
|
||||
enableNews.value = true
|
||||
}
|
||||
enableFund.value = res.enableFund
|
||||
enableAgent.value = res.enableAgent
|
||||
const {notification } =createDiscreteApi(["notification"], {
|
||||
configProviderProps: {
|
||||
theme: enableDarkTheme.value ? darkTheme : lightTheme ,
|
||||
@@ -714,7 +723,7 @@ onMounted(() => {
|
||||
<n-modal-provider>
|
||||
<n-dialog-provider>
|
||||
<n-watermark
|
||||
:content="content"
|
||||
:content="''"
|
||||
cross
|
||||
selectable
|
||||
:font-size="16"
|
||||
|
||||
11
frontend/src/components/AnalyzeMartket.vue
Normal file
11
frontend/src/components/AnalyzeMartket.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<script setup>
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -5,7 +5,9 @@ import 'md-editor-v3/lib/preview.css';
|
||||
import {h, onBeforeUnmount, onMounted, ref} from 'vue';
|
||||
import {CheckUpdate, GetVersionInfo,GetSponsorInfo,OpenURL} from "../../wailsjs/go/main/App";
|
||||
import {EventsOff, EventsOn,Environment} from "../../wailsjs/runtime";
|
||||
import {NAvatar, NButton, useNotification} from "naive-ui";
|
||||
import {NAvatar, NButton, useNotification,NText} from "naive-ui";
|
||||
import { addMonths, format ,parse} from 'date-fns';
|
||||
import { zhCN } from 'date-fns/locale';
|
||||
const updateLog = ref('');
|
||||
const versionInfo = ref('');
|
||||
const icon = ref('https://raw.githubusercontent.com/ArvinLovegood/go-stock/master/build/appicon.png');
|
||||
@@ -16,6 +18,7 @@ const notify = useNotification()
|
||||
const vipLevel=ref("");
|
||||
const vipStartTime=ref("");
|
||||
const vipEndTime=ref("");
|
||||
const expired=ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
document.title = '关于软件';
|
||||
@@ -31,6 +34,13 @@ onMounted(() => {
|
||||
vipLevel.value = res.vipLevel;
|
||||
vipStartTime.value = res.vipStartTime;
|
||||
vipEndTime.value = res.vipEndTime;
|
||||
//判断时间是否到期
|
||||
if (res.vipLevel) {
|
||||
if (res.vipEndTime < format(new Date(), 'yyyy-MM-dd HH:mm:ss')) {
|
||||
notify.warning({content: 'VIP已到期'})
|
||||
expired.value = true;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
});
|
||||
@@ -115,10 +125,10 @@ EventsOn("updateVersion",async (msg) => {
|
||||
<n-gradient-text type="info" :size="50" >go-stock</n-gradient-text>
|
||||
</n-badge>
|
||||
<n-badge v-if="vipLevel" :value="versionInfo" :offset="[50,10]" type="success">
|
||||
<n-gradient-text type="warning" :size="50" >go-stock</n-gradient-text><n-tag :bordered="false" size="small" type="warning">VIP{{vipLevel}}</n-tag>
|
||||
<n-gradient-text :type="expired?'error':'warning'" :size="50" >go-stock</n-gradient-text><n-tag :bordered="false" size="small" type="warning">VIP{{vipLevel}}</n-tag>
|
||||
</n-badge>
|
||||
</h1>
|
||||
<n-gradient-text type="warning" v-if="vipLevel" >vip到期时间:{{vipEndTime}}</n-gradient-text>
|
||||
<n-gradient-text :type="expired?'error':'warning'" v-if="vipLevel" >vip到期时间:{{vipEndTime}}</n-gradient-text>
|
||||
<n-button size="tiny" @click="CheckUpdate(1)" type="info" tertiary >检查更新</n-button>
|
||||
<div style="justify-self: center;text-align: left" >
|
||||
<p>自选股行情实时监控,基于Wails和NaiveUI构建的AI赋能股票分析工具</p>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<template #content="{ item, index }">
|
||||
<t-chat-reasoning v-if="item.role === 'assistant'" expand-icon-placement="right">
|
||||
<t-chat-loading v-if="isStreamLoad" text="思考中..." />
|
||||
<!-- <t-chat-content v-if="item.reasoning.length > 0" :content="item.reasoning" />-->
|
||||
<t-chat-content v-if="item.reasoning.length > 0" :content="item.reasoning" />
|
||||
</t-chat-reasoning>
|
||||
<t-chat-content v-if="item.content.length > 0" :content="item.content" />
|
||||
</template>
|
||||
@@ -97,9 +97,9 @@ EventsOn("agent-message", (data) => {
|
||||
if(data['role']==="assistant"){
|
||||
loading.value = false;
|
||||
const lastItem = chatList.value[0];
|
||||
// if (data['reasoning_content']){
|
||||
// lastItem.reasoning = data['reasoning_content'];
|
||||
// }
|
||||
if (data['reasoning_content']){
|
||||
lastItem.reasoning += data['reasoning_content'];
|
||||
}
|
||||
if (data['content']){
|
||||
lastItem.content +=data['content'];
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup>
|
||||
import {computed, h, onBeforeMount, onBeforeUnmount, onMounted, ref} from 'vue'
|
||||
import * as echarts from "echarts";
|
||||
import {computed, h, onBeforeMount, onBeforeUnmount, onMounted,onUnmounted, ref} from 'vue'
|
||||
import {
|
||||
GetAIResponseResult,
|
||||
GetConfig,
|
||||
@@ -12,7 +13,7 @@ import {
|
||||
SaveAsMarkdown,
|
||||
ShareAnalysis,
|
||||
SummaryStockNews,
|
||||
GetAiConfigs
|
||||
GetAiConfigs, AnalyzeSentimentWithFreqWeight
|
||||
} from "../../wailsjs/go/main/App";
|
||||
import {EventsOff, EventsOn} from "../../wailsjs/runtime";
|
||||
import NewsList from "./newsList.vue";
|
||||
@@ -75,6 +76,8 @@ const indexInterval = ref(null)
|
||||
const indexIndustryRank = ref(null)
|
||||
const stockCode= ref('')
|
||||
const enableTools= ref(true)
|
||||
const treemapRef = ref(null);
|
||||
let treemapchart =null;
|
||||
|
||||
function getIndex() {
|
||||
GlobalStockIndexes().then((res) => {
|
||||
@@ -120,7 +123,13 @@ onBeforeMount(() => {
|
||||
indexIndustryRank.value = setInterval(() => {
|
||||
industryRank()
|
||||
}, 1000 * 10)
|
||||
|
||||
|
||||
})
|
||||
onMounted(() => {
|
||||
Analyze() // 页面显示
|
||||
})
|
||||
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
EventsOff("changeMarketTab")
|
||||
@@ -131,8 +140,12 @@ onBeforeUnmount(() => {
|
||||
clearInterval(indexIndustryRank.value)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
|
||||
});
|
||||
EventsOn("changeMarketTab", async (msg) => {
|
||||
//message.info(msg.name)
|
||||
console.log(msg.name)
|
||||
updateTab(msg.name)
|
||||
})
|
||||
|
||||
@@ -142,6 +155,7 @@ EventsOn("newTelegraph", (data) => {
|
||||
telegraphList.value.pop()
|
||||
}
|
||||
telegraphList.value.unshift(...data)
|
||||
Analyze() // 页面显示
|
||||
}
|
||||
})
|
||||
EventsOn("newSinaNews", (data) => {
|
||||
@@ -150,6 +164,7 @@ EventsOn("newSinaNews", (data) => {
|
||||
sinaNewsList.value.pop()
|
||||
}
|
||||
sinaNewsList.value.unshift(...data)
|
||||
Analyze() // 页面显示
|
||||
}
|
||||
})
|
||||
|
||||
@@ -158,6 +173,32 @@ window.onresize = () => {
|
||||
panelHeight.value = window.innerHeight - 240
|
||||
}
|
||||
|
||||
function Analyze(){
|
||||
console.log("treemapchart:",treemapchart)
|
||||
console.log("treemapRef:",treemapRef.value)
|
||||
treemapchart = echarts.init(treemapRef.value);
|
||||
treemapchart.showLoading()
|
||||
AnalyzeSentimentWithFreqWeight("").then((res) => {
|
||||
console.log(res)
|
||||
let option = {
|
||||
legend: {
|
||||
show: false
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'treemap',
|
||||
data: res['frequencies'].map(item => ({
|
||||
name: item.Word,
|
||||
value: item.Score,
|
||||
}))
|
||||
}
|
||||
]
|
||||
};
|
||||
treemapchart.setOption(option);
|
||||
treemapchart.hideLoading()
|
||||
})
|
||||
}
|
||||
|
||||
function getAreaName(code) {
|
||||
switch (code) {
|
||||
case "america":
|
||||
@@ -232,6 +273,9 @@ function getAiSummary() {
|
||||
function updateTab(name) {
|
||||
summaryBTN.value = (name === "市场快讯");
|
||||
nowTab.value = name
|
||||
if (name === "市场快讯") {
|
||||
Analyze()
|
||||
}
|
||||
}
|
||||
|
||||
EventsOn("summaryStockNews", async (msg) => {
|
||||
@@ -320,14 +364,22 @@ function ReFlesh(source) {
|
||||
<n-card>
|
||||
<n-tabs type="line" animated @update-value="updateTab" :value="nowTab" style="--wails-draggable:no-drag">
|
||||
<n-tab-pane name="市场快讯" tab="市场快讯">
|
||||
<n-grid :cols="2" :y-gap="0">
|
||||
<n-grid :cols="1" :y-gap="0">
|
||||
<n-gi>
|
||||
<news-list :newsList="telegraphList" :header-title="'财联社电报'" @update:message="ReFlesh"></news-list>
|
||||
<div ref="treemapRef" style="width: 100%;height: 300px;" ></div>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<news-list :newsList="sinaNewsList" :header-title="'新浪财经'" @update:message="ReFlesh"></news-list>
|
||||
<n-grid :cols="2" :y-gap="0">
|
||||
<n-gi>
|
||||
<news-list :newsList="telegraphList" :header-title="'财联社电报'" @update:message="ReFlesh"></news-list>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<news-list :newsList="sinaNewsList" :header-title="'新浪财经'" @update:message="ReFlesh"></news-list>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="全球股指" tab="全球股指">
|
||||
<n-tabs type="segment" animated>
|
||||
|
||||
@@ -49,6 +49,9 @@ const updateMessage = () => {
|
||||
<n-text type="warning">查看原文</n-text>
|
||||
</a>
|
||||
</n-tag>
|
||||
<n-tag v-if="item.sentimentResult" :bordered="false" :type="item.sentimentResult==='看涨'?'error':item.sentimentResult==='看跌'?'success':'info'" size="small">
|
||||
{{ item.sentimentResult }}
|
||||
</n-tag>
|
||||
</n-space>
|
||||
</n-list-item>
|
||||
</n-list>
|
||||
|
||||
@@ -45,6 +45,7 @@ const formValue = ref({
|
||||
sponsorCode: "",
|
||||
httpProxy:"",
|
||||
httpProxyEnabled:false,
|
||||
enableAgent: false,
|
||||
})
|
||||
|
||||
// 添加一个新的AI配置到列表
|
||||
@@ -103,6 +104,7 @@ onMounted(() => {
|
||||
formValue.value.sponsorCode = res.sponsorCode
|
||||
formValue.value.httpProxy=res.httpProxy;
|
||||
formValue.value.httpProxyEnabled=res.httpProxyEnabled;
|
||||
formValue.value.enableAgent = res.enableAgent;
|
||||
|
||||
})
|
||||
|
||||
@@ -142,6 +144,7 @@ function saveConfig() {
|
||||
sponsorCode: formValue.value.sponsorCode,
|
||||
httpProxy:formValue.value.httpProxy,
|
||||
httpProxyEnabled:formValue.value.httpProxyEnabled,
|
||||
enableAgent: formValue.value.enableAgent,
|
||||
})
|
||||
|
||||
if (config.sponsorCode) {
|
||||
@@ -231,6 +234,7 @@ function importConfig() {
|
||||
formValue.value.sponsorCode = config.sponsorCode
|
||||
formValue.value.httpProxy=config.httpProxy
|
||||
formValue.value.httpProxyEnabled=config.httpProxyEnabled
|
||||
formValue.value.enableAgent = config.enableAgent
|
||||
};
|
||||
reader.readAsText(file);
|
||||
};
|
||||
@@ -321,6 +325,10 @@ function deletePrompt(ID) {
|
||||
<n-form-item-gi :span="3" label="指数基金:" path="enableFund">
|
||||
<n-switch v-model:value="formValue.enableFund"/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="3" label="AI智能体:" path="enableAgent">
|
||||
<n-switch v-model:value="formValue.enableAgent"/>
|
||||
</n-form-item-gi>
|
||||
|
||||
<n-form-item-gi :span="11" label="赞助码:" path="sponsorCode">
|
||||
<n-input-group>
|
||||
<n-input :show-count="true" placeholder="赞助码" v-model:value="formValue.sponsorCode"/>
|
||||
|
||||
@@ -1853,8 +1853,8 @@ function updateTab(name) {
|
||||
})
|
||||
}
|
||||
|
||||
function delTab(name) {
|
||||
let infos = groupList.value = groupList.value.filter(item => item.ID === Number(name))
|
||||
function delTab(groupId) {
|
||||
let infos = groupList.value = groupList.value.filter(item => item.ID === Number(groupId))
|
||||
dialog.create({
|
||||
title: '删除分组',
|
||||
type: 'warning',
|
||||
@@ -1862,7 +1862,7 @@ function delTab(name) {
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
RemoveGroup(name).then(result => {
|
||||
RemoveGroup(Number(groupId)).then(result => {
|
||||
message.info(result)
|
||||
GetGroupList().then(result => {
|
||||
groupList.value = result
|
||||
|
||||
@@ -9,18 +9,21 @@ import EmbeddedUrl from "./EmbeddedUrl.vue";
|
||||
<n-tab-pane name="选股通" tab="选股通">
|
||||
<embedded-url url="https://xuangutong.com.cn" :height="'calc(100vh - 252px)'"/>
|
||||
</n-tab-pane>
|
||||
<!-- <n-tab-pane name="百度股市通" tab="百度股市通">-->
|
||||
<!-- <embedded-url url="https://gushitong.baidu.com" :height="'calc(100vh - 252px)'"/>-->
|
||||
<!-- </n-tab-pane>-->
|
||||
<n-tab-pane name="百度股市通" tab="百度股市通">
|
||||
<embedded-url url="https://gushitong.baidu.com" :height="'calc(100vh - 252px)'"/>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="东财大盘星图" tab="东财大盘星图">
|
||||
<embedded-url url="https://quote.eastmoney.com/stockhotmap/" :height="'calc(100vh - 252px)'"/>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="TopHub" tab="TopHub(今日热榜)">
|
||||
<embedded-url url="https://tophub.today/c/finance" :height="'calc(100vh - 252px)'"/>
|
||||
</n-tab-pane>
|
||||
<!-- <n-tab-pane name="摸鱼" tab="摸鱼">-->
|
||||
<!-- <embedded-url url="https://996.ninja/" :height="'calc(100vh - 252px)'"/>-->
|
||||
<!-- </n-tab-pane>-->
|
||||
<n-tab-pane name="摸鱼" tab="摸鱼">
|
||||
<embedded-url url="https://996.ninja/" :height="'calc(100vh - 252px)'"/>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="财联社-行情数据" tab="财联社-行情数据">
|
||||
<embedded-url url="https://www.cls.cn/quotation" :height="'calc(100vh - 252px)'"/>
|
||||
</n-tab-pane>
|
||||
|
||||
|
||||
<n-tab-pane name="欢迎推荐更多有趣的财经网页" tab="欢迎推荐更多有趣的财经网页">
|
||||
|
||||
2
frontend/wailsjs/go/main/App.d.ts
vendored
2
frontend/wailsjs/go/main/App.d.ts
vendored
@@ -14,6 +14,8 @@ export function AddStockGroup(arg1:number,arg2:string):Promise<string>;
|
||||
|
||||
export function AnalyzeSentiment(arg1:string):Promise<data.SentimentResult>;
|
||||
|
||||
export function AnalyzeSentimentWithFreqWeight(arg1:string):Promise<Record<string, any>>;
|
||||
|
||||
export function ChatWithAgent(arg1:string,arg2:number,arg3:any):Promise<void>;
|
||||
|
||||
export function CheckSponsorCode(arg1:string):Promise<Record<string, any>>;
|
||||
|
||||
@@ -22,6 +22,10 @@ export function AnalyzeSentiment(arg1) {
|
||||
return window['go']['main']['App']['AnalyzeSentiment'](arg1);
|
||||
}
|
||||
|
||||
export function AnalyzeSentimentWithFreqWeight(arg1) {
|
||||
return window['go']['main']['App']['AnalyzeSentimentWithFreqWeight'](arg1);
|
||||
}
|
||||
|
||||
export function ChatWithAgent(arg1, arg2, arg3) {
|
||||
return window['go']['main']['App']['ChatWithAgent'](arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
@@ -393,6 +393,7 @@ export namespace data {
|
||||
sponsorCode: string;
|
||||
httpProxy: string;
|
||||
httpProxyEnabled: boolean;
|
||||
enableAgent: boolean;
|
||||
aiConfigs: AIConfig[];
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
@@ -428,6 +429,7 @@ export namespace data {
|
||||
this.sponsorCode = source["sponsorCode"];
|
||||
this.httpProxy = source["httpProxy"];
|
||||
this.httpProxyEnabled = source["httpProxyEnabled"];
|
||||
this.enableAgent = source["enableAgent"];
|
||||
this.aiConfigs = this.convertValues(source["aiConfigs"], AIConfig);
|
||||
}
|
||||
|
||||
|
||||
11
go.mod
11
go.mod
@@ -1,12 +1,10 @@
|
||||
module go-stock
|
||||
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.24.5
|
||||
go 1.25.0
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/goquery v1.10.1
|
||||
github.com/chromedp/chromedp v0.11.2
|
||||
github.com/chromedp/chromedp v0.14.1
|
||||
github.com/cloudwego/eino v0.4.1
|
||||
github.com/cloudwego/eino-ext/components/model/ark v0.1.19
|
||||
github.com/cloudwego/eino-ext/components/model/deepseek v0.0.0-20250804092122-8845979a2228
|
||||
@@ -28,7 +26,7 @@ require (
|
||||
github.com/wailsapp/wails/v2 v2.10.1
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/net v0.38.0
|
||||
golang.org/x/sys v0.35.0
|
||||
golang.org/x/sys v0.36.0
|
||||
golang.org/x/text v0.26.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gorm.io/gorm v1.25.12
|
||||
@@ -43,7 +41,7 @@ require (
|
||||
github.com/bytedance/sonic v1.14.0 // indirect
|
||||
github.com/bytedance/sonic/loader v0.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/chromedp/cdproto v0.0.0-20241022234722-4d5d5faf59fb // indirect
|
||||
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d // indirect
|
||||
github.com/chromedp/sysutil v1.1.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||
github.com/cloudwego/eino-ext/libs/acl/openai v0.0.0-20250804062529-6e67726a4b3f // indirect
|
||||
@@ -54,6 +52,7 @@ require (
|
||||
github.com/evanphx/json-patch v0.5.2 // indirect
|
||||
github.com/getkin/kin-openapi v0.118.0 // indirect
|
||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||
github.com/go-json-experiment/json v0.0.0-20250910080747-cc2cfa0554c3 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
|
||||
14
go.sum
14
go.sum
@@ -24,10 +24,10 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
|
||||
github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chromedp/cdproto v0.0.0-20241022234722-4d5d5faf59fb h1:noKVm2SsG4v0Yd0lHNtFYc9EUxIVvrr4kJ6hM8wvIYU=
|
||||
github.com/chromedp/cdproto v0.0.0-20241022234722-4d5d5faf59fb/go.mod h1:4XqMl3iIW08jtieURWL6Tt5924w21pxirC6th662XUM=
|
||||
github.com/chromedp/chromedp v0.11.2 h1:ZRHTh7DjbNTlfIv3NFTbB7eVeu5XCNkgrpcGSpn2oX0=
|
||||
github.com/chromedp/chromedp v0.11.2/go.mod h1:lr8dFRLKsdTTWb75C/Ttol2vnBKOSnt0BW8R9Xaupi8=
|
||||
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d h1:ZtA1sedVbEW7EW80Iz2GR3Ye6PwbJAJXjv7D74xG6HU=
|
||||
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=
|
||||
github.com/chromedp/chromedp v0.14.1 h1:0uAbnxewy/Q+Bg7oafVePE/6EXEho9hnaC38f+TTENg=
|
||||
github.com/chromedp/chromedp v0.14.1/go.mod h1:rHzAv60xDE7VNy/MYtTUrYreSc0ujt2O1/C3bzctYBo=
|
||||
github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=
|
||||
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
@@ -76,6 +76,8 @@ github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJY
|
||||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
|
||||
github.com/go-ego/gse v0.80.3 h1:YNFkjMhlhQnUeuoFcUEd1ivh6SOB764rT8GDsEbDiEg=
|
||||
github.com/go-ego/gse v0.80.3/go.mod h1:Gt3A9Ry1Eso2Kza4MRaiZ7f2DTAvActmETY46Lxg0gU=
|
||||
github.com/go-json-experiment/json v0.0.0-20250910080747-cc2cfa0554c3 h1:02WINGfSX5w0Mn+F28UyRoSt9uvMhKguwWMlOAh6U/0=
|
||||
github.com/go-json-experiment/json v0.0.0-20250910080747-cc2cfa0554c3/go.mod h1:uNVvRXArCGbZ508SxYYTC5v1JWoz2voff5pm25jU1Ok=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
@@ -409,8 +411,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
||||
2
main.go
2
main.go
@@ -60,6 +60,7 @@ var BuildKey string
|
||||
func main() {
|
||||
checkDir("data")
|
||||
db.Init("")
|
||||
data.InitAnalyzeSentiment()
|
||||
go AutoMigrate()
|
||||
|
||||
//db.Dao.Model(&data.Group{}).Where("id = ?", 0).FirstOrCreate(&data.Group{
|
||||
@@ -228,6 +229,7 @@ func AutoMigrate() {
|
||||
db.Dao.AutoMigrate(&models.TelegraphTags{})
|
||||
db.Dao.AutoMigrate(&models.LongTigerRankData{})
|
||||
db.Dao.AutoMigrate(&data.AIConfig{})
|
||||
db.Dao.AutoMigrate(&models.BKDict{})
|
||||
|
||||
updateMultipleModel()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user