Compare commits

...

17 Commits

Author SHA1 Message Date
ArvinLovegood
7bbc6831f4 feat(frontend):实现词云图按权重和频次切换显示
- 添加工具箱按钮用于切换数据展示方式
- 支持按权重、频次和分数三种方式展示词云图
- 优化图表标题和坐标轴标签颜色适配暗色主题
- 调整树图布局顶部间距以避免遮挡标题
- 隐藏树图面包屑导航提升界面简洁性
2025-11-23 11:20:32 +08:00
ArvinLovegood
ab0ccc4fe0 feat(frontend):调整市场情绪仪表盘配置与数据映射逻辑
- 为仪表盘启用暗色主题支持
- 修改仪表盘数值范围从[0,1]到[-100,100]
- 更新颜色分段以匹配新的评分区间
- 调整轴标签位置并重新定义文案映射规则
- 修正数据传入方式,将原始分数转换为适配图表的比例值
- 优化后端接口调用参数,移除固定来源限制以获取更全面的新闻数据
2025-11-23 08:13:35 +08:00
ArvinLovegood
fa658357c9 feat(sentiment):新增市场情绪分析功能
- 添加 AnalyzeMartket 组件用于展示情绪热力图和仪表盘
- 引入 ECharts 实现数据可视化
- 配置定时任务定期更新图表数据
- 在 backend 中扩展情感词典,新增关键词如“被抓”、“超”等
- 优化 sentiment 分析逻辑,提升准确性
- 移除旧版 treemap 图表实现,统一使用新组件渲染
- 调整 single instance ID 为 go-stock
- 更新 base.txt 词库,增加“亏损”、“加工”等词汇
2025-11-22 23:35:02 +08:00
ArvinLovegood
746589a972 feat(backend):优化词典加载与情感分析逻辑
- 重构词典初始化流程,提升加载效率
- 新增CalcToken调用以确保词典更新生效
- 改进用户词典读取路径并增强格式校验
- 忽略空行及注释行,防止无效词条干扰分析
- 使用ReAddToken方法替换原有AddToken实现热更新
- 调整词频权重过滤阈值,提高情感识别准确度
- 引入Score字段用于treemap可视化展示
- 更新基础词典和用户词典内容,强化专业术语覆盖
- 注释冗余测试文本,避免影响正式环境运行
- 增加日志记录以便追踪词典加载与匹配过程
2025-11-22 20:16:14 +08:00
ArvinLovegood
401dd17fa8 feat(stock):加载用户自定义词典进行情感分析(用户可以自己定义词典调整热词权重)
- 在默认词典加载成功后,增加加载用户自定义词典逻辑
- 判断用户词典文件是否存在,避免加载空文件
- 记录用户词典加载成功或失败的日志信息
- 保持原有默认词典加载流程不变
- 确保词典加载错误不会中断程序运行
- 统一词典加载后的日志输出格式
2025-11-22 17:28:40 +08:00
ArvinLovegood
c365bd9534 feat(frontend): 添加官方声明显示功能
- 在 App.vue 中新增 officialStatement 响应式变量
- 从版本信息接口获取官方声明内容并存储
- 将官方声明动态插入到窗口标题中
- 调整窗口标题显示逻辑以包含官方声明
2025-11-22 17:26:31 +08:00
ArvinLovegood
104ee51e13 feat(frontend): 添加官方声明显示功能
- 在 App.vue 中新增 officialStatement 响应式变量
- 从版本信息接口获取官方声明内容并存储
- 将官方声明动态插入到窗口标题中
- 调整窗口标题显示逻辑以包含官方声明
2025-11-22 17:26:12 +08:00
ArvinLovegood
00f3e5f0e0 feat(data): 添加用户词典文件
- 新增包含13个常用词汇的用户词典
- 词汇涵盖公司、国家、市场等业务相关术语
- 为自然语言处理模块提供基础词汇支持
2025-11-22 17:18:35 +08:00
ArvinLovegood
483ffa2244 feat(data): 优化金融分词词典与情感分析逻辑
- 更新基础词典文件,完善覆盖场景并调整部分词条权重
- 移除重复或冗余的美股及中概股名称条目
- 提升多个关键金融术语如“人工智能”、“半导体”等权重至350
- 新增“冲高”、“打开涨停”等交易行为相关词汇并设定合理权重
- 完善“十五五规划”相关内容条目,并分类整理结构
- 在情感分析模块引入basefreq常量替代硬编码数值
- 调整股票名称和板块名称添加逻辑中的频率值计算方式
- 重构用户自定义词典加载流程,增强兼容性和健壮性
- 支持更灵活的用户词典格式(支持词、频、词性三元素)
- 修改词频结果结构体,新增Score字段用于综合评分
- 优化排序规则,依据频率与权重乘积进行降序排列
- 增加调试日志输出,便于追踪分析过程与结果
- 前端Treemap图表展示逻辑同步更新以适配新的评分标准
2025-11-22 17:17:55 +08:00
ArvinLovegood
63d278b9aa feat(stock):加载用户自定义词典进行情感分析(用户可以自己定义词典调整热词权重)
- 在默认词典加载成功后,增加加载用户自定义词典逻辑
- 判断用户词典文件是否存在,避免加载空文件
- 记录用户词典加载成功或失败的日志信息
- 保持原有默认词典加载流程不变
- 确保词典加载错误不会中断程序运行
- 统一词典加载后的日志输出格式
2025-11-22 13:02:33 +08:00
ArvinLovegood
5621d40c71 feat(market):调整词频树图数据计算方式
- 将词频树图中的值计算方式从 Frequency 改为 Frequency * Weight
- 更新 treemap 数据映射逻辑以反映新的权重计算
- 确保前端展示的数据更加准确地反映词汇的重要性
2025-11-22 12:58:41 +08:00
ArvinLovegood
26e9753b94 feat(data):添加十五五规划重点领域关键词到基础词典
- 新增涵盖七个大类的政策关键词汇
- 设置词汇权重范围为310-350,适配政策资讯分词场景
- 包含核心战略方向、科技创新与数字经济等领域术语
- 添加能源与绿色转型相关高频词汇
- 补充高端制造与新兴产业的专业表达
- 增加乡村振兴与农业现代化关键词
- 纳入对外开放与贸易升级术语
- 更新社会民生与公共服务领域用词
2025-11-22 12:55:11 +08:00
ArvinLovegood
b7f6dbd2da feat(data):更新股票情感分析词典并优化测试代码
- 在 base.txt 中新增多个知名美股和中概股词汇,提升分词准确性
- 调整测试代码逻辑,移除随机新闻获取,使用固定文本进行情感分析验证
- 初始化数据库连接和情感分析模块,确保测试环境正常运行
- 添加详细的市场新闻示例文本,增强测试覆盖度和结果可靠性
2025-11-22 08:03:44 +08:00
ArvinLovegood
18dd01b613 feat(data):热词算法优化(最近24小时资讯+去重)
- 新增 GetNews24HoursList 方法,用于获取最近24小时内的新闻数据
- 支持按来源筛选新闻,如“财联社电报”
- 添加内容去重逻辑,避免重复新闻条目
- 自动加载新闻关联的标签信息,并构建主题标签字段
- 优化查询逻辑,提升数据获取效率与准确性
2025-11-22 07:48:00 +08:00
ArvinLovegood
81bb33a135 feat(sentiment):新增带频率权重的情感分析功能
- 新增 AnalyzeSentimentWithFreqWeight 方法,支持词频统计与权重分析
- 扩展前端组件 market.vue,集成词频热力图展示功能
- 更新后端词典库,新增 base.txt 金融专业词汇字典
- 引入 ECharts 实现词频 TreeMap 可视化展示
- 优化情感分析算法,增加对股票名称及行业标签的识别支持
- 完善词频过滤逻辑,去除标点符号与无效字符干扰
- 增加词典初始化方法 InitAnalyzeSentiment,提升分析准确性
2025-11-21 20:17:57 +08:00
ArvinLovegood
9926b61fac fix(data): 调整新闻等级判断逻辑
- 修改 GetLevel 函数中的比较操作符,确保更准确的等级判定
- 将大于等于 "C" 的条件改为严格大于 "C",以符合新的业务需求
2025-11-21 13:35:28 +08:00
ArvinLovegood
5e975b060c fix(backend):偶尔修复闪退BUG
- 添加空数据检查避免nil指针异常
2025-11-21 09:12:54 +08:00
22 changed files with 1746846 additions and 41 deletions

View File

@@ -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,
}
}

View File

@@ -0,0 +1 @@
Some dict/zh data is from [github.com/fxsjy/jieba](https://github.com/fxsjy/jieba)

View File

@@ -0,0 +1,479 @@
# 金融股票全场景分词字典(最终去重优化版)
# 格式:单词 权重 词性 | 权重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
亏损 100 n
加工 100 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

View File

View File

@@ -0,0 +1 @@
dict.txt 通过内部工具生成, Copyright 2017 ego authors. 商用和拷贝请注明来源和版权

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
公司 0.1 n
国家 0.1 n
国际 0.1 n
会议 0.1 n
市场 0.1 n
经济 0.1 n
技术 0.1 n
记者 0.1 n
时间 0.1 n
项目 0.1 n
问题 0.1 n
企业 0.1 n
财联社 0.1 n
上涨 0.1 v
下跌 0.1 v
期货 0.1 n
跌幅 0.1 n
跌超 0.1 adj
股票 0.1 n
冰雪旅游 500 n
特高压 500 n
跨境电商 500 n
俄乌冲突 400 n
新能源汽车 500 n
机器人 500 n
具身智能 500 n

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,88 @@
,
.
?
!
"
@
 
~
*
<
>
/
\
|
-
_
+
=
&
^
%
#
`
;
$
︿
哎呀
哎哟
俺们
按照
吧哒
罢了
本着
比方
比如
鄙人
彼此
别的
别说

File diff suppressed because it is too large Load Diff

View File

@@ -45,6 +45,9 @@ func (m MarketNewsApi) TelegraphList(crawlTimeOut int64) *[]models.Telegraph {
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 {
@@ -94,7 +97,7 @@ func (m MarketNewsApi) TelegraphList(crawlTimeOut int64) *[]models.Telegraph {
return &telegraphs
}
func GetLevel(s string) bool {
return s >= "C"
return s > "C"
}
func (m MarketNewsApi) GetNewTelegraph(crawlTimeOut int64) *[]models.Telegraph {
@@ -1024,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
}

View File

@@ -2,38 +2,50 @@ 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,
"利好消息": 3.0, "收益增长": 2.5, "利润增长": 2.5, "业绩优异": 2.5,
"潜力股": 2.0, "绩优股": 2.0, "强势": 1.5, "走高": 1.5, "攀升": 1.5,
"大涨": 2.5, "飙升": 3.0, "井喷": 3.0, "爆发": 2.5, "暴涨": 3.0,
"大涨": 2.5, "飙升": 3.0, "井喷": 3.0, "暴涨": 3.0,
}
// 负面金融词汇及其权重
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,
"被抓": 3.0, "被抓捕": 3.0,
}
// 否定词,用于反转情感极性
@@ -45,7 +57,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, "超": 1.8,
}
// 转折词,用于识别情感转折
@@ -54,12 +66,230 @@ 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() {
//err := seg.LoadDictEmbed()
err := seg.LoadDictEmbed(baseDict)
if err != nil {
logger.SugaredLogger.Error(err.Error())
} else {
logger.SugaredLogger.Info("加载默认词典成功")
}
seg.CalcToken()
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())
}
}
seg.CalcToken()
//加载用户自定义词典 先判断用户词典是否存在
if fileutil.IsExist("data/dict/user.txt") {
lines, err := fileutil.ReadFileByLine("data/dict/user.txt")
if err != nil {
logger.SugaredLogger.Error(err.Error())
return
}
for _, line := range lines {
if len(line) == 0 || line[0] == '#' {
continue
}
k := strutil.SplitAndTrim(line, " ")
switch len(k) {
case 1:
err = seg.ReAddToken(k[0], 100)
case 2:
freq, _ := convertor.ToFloat(k[1])
err = seg.ReAddToken(k[0], freq)
case 3:
freq, _ := convertor.ToFloat(k[1])
err = seg.ReAddToken(k[0], freq, k[2])
default:
logger.SugaredLogger.Errorf("用户词典格式错误:%s", line)
}
logger.SugaredLogger.Infof("添加用户词典[%s]成功", line)
}
if err != nil {
logger.SugaredLogger.Error(err.Error())
} else {
logger.SugaredLogger.Infof("加载用户词典成功")
}
}
seg.CalcToken()
}
// 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 {
logger.SugaredLogger.Infof("获取%s的权重:%f,pos:%s,ok:%v", word, freq, pos, ok)
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 > 200 {
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 情感分析结果类型

View File

@@ -2,6 +2,8 @@ package data
import (
"fmt"
"go-stock/backend/db"
"go-stock/backend/logger"
"strings"
"testing"
)
@@ -12,25 +14,34 @@ 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月消费者信心指数降至5110月为53.6。 12、日本央行政策委员会委员Kazuyuki Masu表示日本央行接近作出加息决定。 13、穆迪将意大利信用评级从BAA3上调至BAA2展望稳定。\n"
text = "财联社电英伟达周五冲高回落股价涨幅收于1%,市场普遍认为其走势疲软"
text = "【本轮巴以冲突已致加沙地带69733人死亡】财联社11月22日电当地时间22日下午以军对加沙城西部一辆汽车发动空袭已造成5人死亡多人受伤。自2023年10月7日巴以新一轮大规模冲突爆发以来以色列对加沙地带的袭击已造成69733人死亡、170863人受伤。"
//text = "【牛肉加工亏损 美国泰森公司关停缩减相关业务】财联社11月22日电受牛肉加工业务亏损影响当地时间21日美国泰森食品公司发布公告称将关闭位于内布拉斯加州的一家大型牛肉加工厂还计划缩小得克萨斯州一家牛肉加工厂的生产规模。根据泰森食品公司的公告被关闭的这家工厂位于内布拉斯加州列克星敦日均可宰杀并处理大约5000头牛约占全美日均牛肉屠宰数量的4.8%。与此同时公司还计划缩小得克萨斯州一家牛肉加工厂的生产规模这家工厂每天大约可屠宰6000头牛。据悉泰森此次业务调整影响两个工厂大约5000个工作岗位。《华尔街日报》报道称泰森是美国四大肉类加工公司中首家关闭主要牛肉加工厂的公司其最新财报显示2025财年牛肉加工是唯一亏损的业务部门调整后的营业亏损为4.26亿美元。"
// 分析情感
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,
)
}

View File

@@ -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']

View File

@@ -53,6 +53,7 @@ const containerRef = ref({})
const realtimeProfit = ref(0)
const telegraph = ref([])
const groupList = ref([])
const officialStatement= ref("")
const menuOptions = ref([
{
label: () =>
@@ -599,6 +600,7 @@ onBeforeMount(() => {
GetVersionInfo().then(result => {
if(result.officialStatement){
content.value = result.officialStatement+"\n\n"+content.value
officialStatement.value = result.officialStatement
}
})
@@ -669,7 +671,7 @@ onBeforeMount(() => {
})
onMounted(() => {
WindowSetTitle("go-stockAI赋能股票分析✨ 未经授权,禁止商业目的! [数据来源于网络,仅供参考;投资有风险,入市需谨慎]")
WindowSetTitle("go-stockAI赋能股票分析✨ "+officialStatement.value+" 未经授权,禁止商业目的! [数据来源于网络,仅供参考;投资有风险,入市需谨慎]")
contentStyle.value = "max-height: calc(92vh);overflow: hidden"
GetConfig().then((res) => {
if (res.enableNews) {

View File

@@ -0,0 +1,262 @@
<script setup>
import {AnalyzeSentimentWithFreqWeight} from "../../wailsjs/go/main/App";
import * as echarts from "echarts";
import {onMounted,onUnmounted, ref} from "vue";
import _ from "lodash";
const { name,darkTheme,kDays ,chartHeight} = defineProps({
name: {
type: String,
default: ''
},
kDays: {
type: Number,
default: 14
},
chartHeight: {
type: Number,
default: 500
},
darkTheme: {
type: Boolean,
default: false
}
})
const chartRef = ref(null);
const gaugeChartRef = ref(null);
let handleChartInterval=null
onMounted(() => {
handleChart()
handleChartInterval=setInterval(function () {
handleChart()
}, 1000 * 60)
})
onUnmounted(()=>{
clearInterval(handleChartInterval)
})
function handleChart(){
const formatUtil = echarts.format;
AnalyzeSentimentWithFreqWeight("").then((res) => {
console.log(res)
const treemapchart = echarts.init(chartRef.value);
const gaugeChart=echarts.init(gaugeChartRef.value);
let data = res['frequencies'].map(item => ({
name: item.Word,
// value: item.Frequency,
// value: item.Weight,
frequency: item.Frequency,
weight: item.Weight,
value: item.Score,
}));
let data2 = res['frequencies'].map(item => ({
name: item.Word,
value: item.Frequency,
// value: item.Weight,
frequency: item.Frequency,
weight: item.Weight,
//value: item.Score,
}));
let data3 = res['frequencies'].map(item => ({
name: item.Word,
//value: item.Frequency,
value: item.Weight,
frequency: item.Frequency,
weight: item.Weight,
//value: item.Score,
}));
let option = {
darkMode: darkTheme,
title: {
text:name,
left: 'center',
textStyle: {
color: darkTheme?'#ccc':'#456'
}
},
legend: {
show: false
},
toolbox: {
left: '20px',
tooltip:{
textStyle: {
color: darkTheme?'#ccc':'#456'
}
},
feature: {
saveAsImage: {title: '保存图片'},
restore: {
title: '默认',
},
myTool2: {
show: true,
title: '按权重',
icon:"path://M393.8816 148.1216a29.3376 29.3376 0 0 1-15.2576 38.0928c-43.776 17.152-81.92 43.8272-114.2784 76.2368A345.7536 345.7536 0 0 0 159.5392 512 352.8704 352.8704 0 0 0 512 864.4608a351.744 351.744 0 0 0 249.5488-102.912 353.536 353.536 0 0 0 76.2368-114.2784c5.6832-15.2576 22.8352-20.992 38.0928-15.2576 15.2576 5.7344 20.992 22.8864 15.2576 38.0928a421.2224 421.2224 0 0 1-89.6 133.376A412.6208 412.6208 0 0 1 512 921.6c-226.7136 0-409.6-182.8864-409.6-409.6 0-108.544 41.9328-211.456 120.0128-289.5872A421.2224 421.2224 0 0 1 355.84 132.864a29.3376 29.3376 0 0 1 38.0928 15.2576zM512 102.4c226.7136 0 409.6 182.8864 409.6 409.6 0 15.2576-13.312 28.5696-28.5696 28.5696H512A29.2864 29.2864 0 0 1 483.4304 512V130.9696c0-15.2576 13.312-28.5696 28.5696-28.5696z m28.5696 59.0336v321.9968h321.9968a350.976 350.976 0 0 0-321.9968-321.9968z",
onclick: function (){
treemapchart.setOption( {series:{
data: data3
}})
}
},
myTool1: {
show: true,
title: '按频次',
icon:"path://M895.466667 476.8l-87.424-87.424v-123.626667a49.770667 49.770667 0 0 0-49.770667-49.770666h-123.626667L547.2 128.533333a49.792 49.792 0 0 0-70.4 0l-87.424 87.424h-123.626667a49.770667 49.770667 0 0 0-49.770666 49.770667v123.626667L128.533333 476.8a49.792 49.792 0 0 0 0 70.4l87.424 87.424v123.626667a49.770667 49.770667 0 0 0 49.770667 49.770666h123.626667l87.424 87.424a49.792 49.792 0 0 0 70.4 0l87.424-87.424h123.626666a49.770667 49.770667 0 0 0 49.770667-49.770666v-123.626667l87.424-87.424a49.749333 49.749333 0 0 0 0.042667-70.4z m-137.216 137.194667v144.256h-144.256L512 860.266667l-101.994667-101.994667h-144.256v-144.256L163.733333 512l101.994667-101.994667v-144.256h144.256L512 163.733333l101.994667 101.994667h144.256v144.256L860.266667 512l-102.016 101.994667z M414.378667 514.730667l28.672 10.922666c-18.090667 47.445333-38.229333 92.16-60.757334 133.802667l-30.037333-13.653333a1042.133333 1042.133333 0 0 0 62.122667-131.072zM381.952 367.616L355.669333 384c25.258667 26.282667 45.056 50.176 60.074667 72.021333l25.6-17.749333c-13.994667-20.48-33.792-44.032-59.392-70.656zM537.258667 455.338667c-0.682667 43.690667-6.144 79.189333-16.725334 106.837333-14.336 32.768-44.373333 60.416-89.429333 82.944l21.162667 25.941333c52.224-26.624 85.333333-60.074667 99.328-100.693333 1.706667-5.12 3.413333-10.24 4.778666-15.36 21.504 45.738667 52.906667 83.968 93.866667 115.370667l21.504-24.917334c-51.2-34.474667-86.357333-81.237333-105.813333-140.288 1.706667-15.701333 2.730667-32.085333 2.730666-49.834666h-31.402666z M508.586667 434.858667h115.712c-6.826667 25.258667-15.018667 47.786667-24.917334 66.901333l31.744 8.874667a627.008 627.008 0 0 0 27.989334-85.674667v-21.162667H517.12c3.413333-14.336 6.144-29.354667 8.874667-45.738666l-32.426667-5.12c-7.850667 59.392-25.6 105.813333-52.906667 139.264l26.965334 19.114666c16.725333-19.114667 30.378667-44.373333 40.96-76.458666z",
onclick: function (){
treemapchart.setOption( {series:{
data: data2
}})
}
}
}
},
tooltip: {
formatter: function (info) {
var value = info.value;
var frequency = info.data.frequency;
var weight = info.data.weight;
return [
'<div class="tooltip-title">' + info.name+ '</div>',
'热度: ' + formatUtil.addCommas(value) + '',
'<div class="tooltip-title">频次: ' + formatUtil.addCommas(frequency)+ '</div>',
'<div class="tooltip-title">权重: ' + formatUtil.addCommas(weight)+ '</div>',
].join('');
}
},
series: [
{
type: 'treemap',
breadcrumb:{show: false},
left: '0',
top: '40',
right: '0',
bottom: '0',
tooltip: {
show: true
},
data: data
}
]
};
treemapchart.setOption(option);
let option2 = {
darkMode: darkTheme,
series: [
{
type: 'gauge',
startAngle: 180,
endAngle: 0,
center: ['50%', '75%'],
radius: '90%',
min: -100,
max: 100,
splitNumber: 8,
axisLine: {
lineStyle: {
width: 6,
color: [
// [0.25, '#FF6E76'],
// [0.5, '#FDDD60'],
// [0.75, '#58D9F9'],
// [1, '#7CFFB2'],
[0.25, '#03fb6a'],
[0.5, '#58e1f9'],
[0.75, '#ef5922'],
[1, '#f11d29'],
]
}
},
pointer: {
icon: 'path://M12.8,0.7l12,40.1H0.7L12.8,0.7z',
length: '12%',
width: 20,
offsetCenter: [0, '-60%'],
itemStyle: {
color: 'auto'
}
},
axisTick: {
length: 12,
lineStyle: {
color: 'auto',
width: 2
}
},
splitLine: {
length: 20,
lineStyle: {
color: 'auto',
width: 5
}
},
axisLabel: {
color: darkTheme?'#ccc':'#456',
fontSize: 20,
distance: -45,
rotate: 'tangential',
formatter: function (value) {
if (value ===100) {
return '极热';
} else if (value === 50) {
return '乐观';
} else if (value === 0) {
return '中性';
}else if (value === -50) {
return '谨慎';
} else if (value === -100) {
return '冰点';
}
return '';
}
},
title: {
offsetCenter: [0, '-10%'],
fontSize: 20
},
detail: {
fontSize: 30,
offsetCenter: [0, '-35%'],
valueAnimation: true,
formatter: function (value) {
return value.toFixed(2) + '';
},
color: 'inherit'
},
data: [
{
value: res.result.Score*0.2,
name: '市场情绪'
}
]
}
]
};
gaugeChart.setOption(option2);
})
}
</script>
<template>
<n-grid :cols="24" :y-gap="0">
<n-gi span="6">
<div ref="gaugeChartRef" style="width: 100%;height: auto;--wails-draggable:no-drag" :style="{height:chartHeight+'px'}" ></div>
</n-gi>
<n-gi span="18">
<div ref="chartRef" style="width: 100%;height: auto;--wails-draggable:no-drag" :style="{height:chartHeight+'px'}" ></div>
</n-gi>
</n-grid>
</template>
<style scoped>
</style>

View File

@@ -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,
} 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,12 @@ onBeforeMount(() => {
indexIndustryRank.value = setInterval(() => {
industryRank()
}, 1000 * 10)
})
onMounted(() => {
})
onBeforeUnmount(() => {
EventsOff("changeMarketTab")
@@ -131,8 +139,12 @@ onBeforeUnmount(() => {
clearInterval(indexIndustryRank.value)
})
onUnmounted(() => {
});
EventsOn("changeMarketTab", async (msg) => {
//message.info(msg.name)
console.log(msg.name)
updateTab(msg.name)
})
@@ -320,14 +332,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>
<AnalyzeMartket :dark-theme="darkTheme" :chart-height="300" :kDays="1" :name="'最近24小时热词'" />
</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>

View File

@@ -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>>;

View File

@@ -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);
}

View File

@@ -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{
@@ -124,7 +125,7 @@ func main() {
// Create application with options
err = wails.Run(&options.App{
Title: "go-stockAI赋能股票分析✨",
Title: "go-stockAI赋能股票分析✨ " + OFFICIAL_STATEMENT,
Width: width * 4 / 5,
Height: 920,
MinWidth: minWidth,
@@ -149,7 +150,7 @@ func main() {
OnShutdown: app.shutdown,
WindowStartState: options.Normal,
SingleInstanceLock: &options.SingleInstanceLock{
UniqueId: "go-stock-dev",
UniqueId: "go-stock",
OnSecondInstanceLaunch: OnSecondInstanceLaunch,
},
Bind: []interface{}{