AI驱动的本地化股票分析系统:go-stock技术架构全解析
引言:解决量化投资的三大痛点
在当今数据爆炸的时代,股票投资者面临着三重困境:商业软件的高昂订阅费用形成资金门槛,云端分析平台的数据隐私泄露风险,以及普通散户难以企及的专业量化模型能力。go-stock项目应运而生,以**"本地数据主权+AI赋能分析"**为核心理念,构建了一套完整的股票分析解决方案。
本文将深入剖析go-stock的技术架构,展示如何通过Go语言生态实现从数据采集、本地存储、AI分析到可视化展示的全链路能力。我们将逐一拆解其跨平台桌面应用框架、实时数据处理引擎、多模型AI集成方案和低延迟告警系统,为开发者提供可复用的技术实现参考。
系统架构总览:Go生态的全栈整合
go-stock采用现代化的分层架构设计,基于Go语言构建后端服务,通过Wails框架融合Vue前端,形成高性能的桌面应用。系统整体架构如图所示:
核心技术栈选型:
- 桌面框架:Wails v2 (Go + WebView2)
- 后端:Go 1.22+,Goroutine并发模型
- 数据库:SQLite 3 + GORM ORM
- 前端:Vue 3 + Vite + Naive UI
- AI集成:Eino框架 + 多模型适配器
- 数据处理:GoQuery爬虫 + 正则解析
- 任务调度:Cron表达式定时任务
这种架构设计实现了几个关键优势:
- 跨平台一致性:一套代码运行在Windows、macOS和Linux
- 前后端无缝通信:通过Wails实现高效的Go<->JS交互
- 本地数据安全:所有敏感数据存储在用户设备上
- 低资源占用:Go语言编译为原生二进制,内存占用<50MB
- 可扩展架构:模块化设计便于功能扩展和第三方集成
工程结构解析:领域驱动的代码组织
项目采用领域驱动的目录结构,将业务逻辑按功能模块划分:
go-stock/
├── backend/ # 后端服务代码
│ ├── agent/ # AI智能体模块
│ │ ├── tools/ # 工具函数集合
│ │ ├── agent.go # 智能体核心逻辑
│ │ └── agent_api.go # 对外API接口
│ ├── data/ # 数据处理模块
│ │ ├── stock_data_api.go # 股票数据API
│ │ ├── market_news_api.go # 新闻数据API
│ │ └── tushare_data_api.go # 第三方数据集成
│ ├── db/ # 数据库模块
│ │ └── db.go # 数据库连接管理
│ ├── models/ # 数据模型定义
│ └── util/ # 通用工具函数
├── frontend/ # 前端界面代码
│ ├── src/components/ # Vue组件
│ ├── src/router/ # 路由配置
│ └── src/style.css # 样式定义
├── main.go # 应用入口点
├── app.go # 应用核心逻辑
└── wails.json # Wails配置文件
这种结构将业务逻辑与技术实现分离,每个模块专注于单一职责,提高了代码的可维护性和可测试性。
本地数据存储方案:SQLite + GORM的高效实践
go-stock采用SQLite作为主要数据存储引擎,结合GORM进行ORM操作,实现高效的数据管理。数据库初始化代码位于backend/db/db.go:
func Init(sqlitePath string) {
dbLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{
SlowThreshold: time.Second * 3,
Colorful: false,
IgnoreRecordNotFoundError: true,
LogLevel: logger.Info,
},
)
if sqlitePath == "" {
sqlitePath = "data/stock.db?cache=shared&mode=rwc&_journal_mode=WAL"
}
openDb, err := gorm.Open(sqlite.Open(sqlitePath), &gorm.Config{
Logger: dbLogger,
DisableForeignKeyConstraintWhenMigrating: true,
SkipDefaultTransaction: true,
PrepareStmt: true,
})
// 启用读写分离以提高性能
openDb.Use(dbresolver.Register(
dbresolver.Config{
Replicas: []gorm.Dialector{sqlite.Open(sqlitePath)}},
))
dbCon, err := openDb.DB()
dbCon.SetMaxIdleConns(10)
dbCon.SetMaxOpenConns(100)
dbCon.SetConnMaxLifetime(time.Hour)
Dao = openDb
}
关键优化点包括:
- 启用WAL(Write-Ahead Logging)模式提升并发写入性能
- 配置连接池参数避免频繁连接开销
- 使用读写分离插件提高查询吞吐量
- 禁用默认事务以减少不必要的锁竞争
数据模型设计遵循第三范式,主要实体包括:
StockBasic:股票基本信息StockInfo:实时行情数据FollowedStock:用户自选股AIResponseResult:AI分析结果Settings:应用配置项
以股票基本信息表为例,其定义如下:
type StockBasic struct {
gorm.Model
TsCode string `json:"ts_code" gorm:"index"` // 股票代码
Symbol string `json:"symbol" gorm:"index"` // 交易代码
Name string `json:"name" gorm:"index"` // 股票名称
Area string `json:"area"` // 地域
Industry string `json:"industry" gorm:"index"`// 所属行业
Fullname string `json:"fullname"` // 全称
Market string `json:"market"` // 市场类型
ListDate string `json:"list_date"` // 上市日期
IsHs string `json:"is_hs"` // 是否沪深港通标的
}
通过合理设计索引和关联关系,系统能够高效支持复杂查询和数据分析需求。
实时行情数据采集:多源整合与增量更新
股票数据采集是系统的核心功能之一,StockDataApi结构体(位于backend/data/stock_data_api.go)封装了完整的数据源访问逻辑。系统支持多渠道数据获取:
func (receiver StockDataApi) GetStockCodeRealTimeData(stockCodes ...string) (*[]StockInfo, error) {
stockInfos := make([]StockInfo, 0)
// 处理A股和港股数据
hkcodes := slice.Filter(stockCodes, func(i int, s string) bool {
return strutil.HasPrefixAny(s, []string{"hk", "HK", "sh", "sz"})
})
if hkcodes != nil && len(hkcodes) > 0 {
// 从腾讯财经API获取数据
hkcodesStr := slice.JoinFunc(hkcodes, ",", func(s string) string {
if strutil.HasPrefixAny(s, []string{"hk", "HK"}) {
return "r_" + strings.ToLower(s)
} else {
return strings.ToLower(s)
}
})
url := fmt.Sprintf(txStockUrl, time.Now().Unix(), hkcodesStr)
resp, err := receiver.client.R().Get(url)
// 数据解析和处理...
}
// 处理美股数据
szzusCodes := slice.Filter(stockCodes, func(i int, s string) bool {
return !strutil.HasPrefixAny(s, []string{"hk", "HK", "sh", "sz"})
})
// 从新浪财经API获取数据
codes := slice.JoinFunc(szzusCodes, ",", func(s string) {
// 代码转换逻辑...
})
url := fmt.Sprintf(sinaStockUrl, time.Now().Unix(), codes)
resp, err := receiver.client.R().Get(url)
// 数据解析和处理...
return &stockInfos, err
}
数据采集策略特点:
- 多源备份:同时对接腾讯财经和新浪财经API,确保数据可靠性
- 增量更新:仅更新变化的数据,减少网络传输和存储开销
- 错误重试:实现指数退避重试机制处理临时网络故障
- 本地缓存:使用freecache缓存频繁访问的数据,减少API调用
数据解析采用自定义的状态机解析器,能够高效处理非标准格式的行情数据:
func ParseTxHKStockData(datas []string) (map[string]string, error) {
stockCode := strutil.ReplaceWithMap(datas[0], map[string]string{
"v_r_": "",
"v_": "",
})
result := make(map[string]string)
result["股票代码"] = stockCode
parts := strutil.SplitAndTrim(datas[1], "~")
if len(parts) < 35 {
return nil, fmt.Errorf("invalid data format")
}
result["股票名称"] = parts[1]
result["当前价格"] = parts[3]
result["昨日收盘价"] = parts[4]
result["今日开盘价"] = parts[5]
result["今日最高价"] = parts[33]
result["今日最低价"] = parts[34]
// 处理时间格式
timestr := strutil.ReplaceWithMap(parts[30], map[string]string{
"/": "-",
"\n": " ",
})
result["日期"] = strutil.SplitAndTrim(timestr, " ", "")[0]
result["时间"] = strutil.SplitAndTrim(timestr, " ", "")[1]
return result, nil
}
AI分析引擎:多模型支持的智能决策系统
go-stock的AI分析引擎基于Eino框架构建,支持多种LLM模型的集成,包括DeepSeek、OpenAI、Ollama等。核心实现位于backend/agent/agent.go:
func GetStockAiAgent(ctx *context.Context, aiConfig data.AIConfig) *react.Agent {
temperature := float32(aiConfig.Temperature)
var toolableChatModel model.ToolCallingChatModel
var err error
// 根据配置选择不同的LLM提供商
if aiConfig.BaseUrl == "https://ark.cn-beijing.volces.com/api/v3" {
toolableChatModel, err = ark.NewChatModel(context.Background(), &ark.ChatModelConfig{
BaseURL: aiConfig.BaseUrl,
Model: aiConfig.ModelName,
APIKey: aiConfig.ApiKey,
MaxTokens: &aiConfig.MaxTokens,
Temperature: &temperature,
})
} else if aiConfig.BaseUrl == "https://api.deepseek.com" {
toolableChatModel, err = deepseek.NewChatModel(*ctx, &deepseek.ChatModelConfig{
BaseURL: aiConfig.BaseUrl,
Model: aiConfig.ModelName,
APIKey: aiConfig.ApiKey,
Timeout: time.Duration(aiConfig.TimeOut) * time.Second,
MaxTokens: aiConfig.MaxTokens,
Temperature: temperature,
})
} else {
toolableChatModel, err = openai.NewChatModel(*ctx, &openai.ChatModelConfig{
BaseURL: aiConfig.BaseUrl,
Model: aiConfig.ModelName,
APIKey: aiConfig.ApiKey,
Timeout: time.Duration(aiConfig.TimeOut) * time.Second,
MaxTokens: &aiConfig.MaxTokens,
Temperature: &temperature,
})
}
// 初始化分析工具集
aiTools := compose.ToolsNodeConfig{
Tools: []tool.BaseTool{
tools.GetQueryEconomicDataTool(),
tools.GetQueryStockPriceInfoTool(),
tools.GetQueryStockCodeInfoTool(),
tools.GetQueryMarketNewsTool(),
tools.GetChoiceStockByIndicatorsTool(),
tools.GetStockKLineTool(),
// 其他分析工具...
},
}
// 创建智能体
agent, err := react.NewAgent(*ctx, &react.AgentConfig{
ToolCallingModel: toolableChatModel,
ToolsConfig: aiTools,
MaxStep: len(aiTools.Tools)*3 + 2,
})
return agent
}
AI分析引擎特点:
- 多模型适配:统一接口封装不同LLM提供商的API差异
- 工具调用能力:使AI能够调用外部工具获取实时数据
- 思维链推理:通过React模式实现复杂问题的分步解决
- 上下文管理:智能维护对话状态,支持多轮分析
技术指标分析工具示例(KDJ指标计算):
func calculateKDJ(prices []float64, periods int) (k, d, j []float64) {
// 计算RSV值
rsv := make([]float64, len(prices))
for i := range prices {
if i < periods-1 {
rsv[i] = 0
continue
}
// 找到periods周期内的最低价和最高价
start := i - periods + 1
minPrice := prices[start]
maxPrice := prices[start]
for _, p := range prices[start:i+1] {
if p < minPrice {
minPrice = p
}
if p > maxPrice {
maxPrice = p
}
}
// 计算RSV
if maxPrice == minPrice {
rsv[i] = 0
} else {
rsv[i] = (prices[i] - minPrice) / (maxPrice - minPrice) * 100
}
}
// 计算K、D、J值
k = make([]float64, len(prices))
d = make([]float64, len(prices))
j = make([]float64, len(prices))
for i := range rsv {
if i < periods-1 {
k[i] = 50
d[i] = 50
j[i] = 50
continue
}
if i == periods-1 {
k[i] = rsv[i]
d[i] = k[i]
} else {
k[i] = k[i-1]*2/3 + rsv[i]/3
d[i] = d[i-1]*2/3 + k[i]/3
}
j[i] = 3*k[i] - 2*d[i]
}
return k, d, j
}
前端交互实现:Wails框架的跨语言通信
go-stock使用Wails框架实现前后端通信,将Go后端的功能无缝暴露给Vue前端。应用初始化流程位于main.go:
func main() {
// 初始化数据库
checkDir("data")
db.Init("")
go AutoMigrate()
// 创建应用实例
app := NewApp()
// 配置应用窗口
width, _, minWidth, minHeight, err := getScreenResolution()
if err != nil {
width = 1456
}
// 运行Wails应用
err = wails.Run(&options.App{
Title: "go-stock:AI赋能股票分析✨",
Width: width * 4 / 5,
Height: 920,
MinWidth: minWidth,
MinHeight: minHeight,
Assets: assets,
Menu: AppMenu,
OnStartup: app.startup,
OnDomReady: app.domReady,
OnShutdown: app.shutdown,
Bind: []interface{}{
app,
},
// 平台特定配置...
})
}
前后端通信通过Wails的绑定机制实现,Go方法通过Bind配置暴露给前端:
// 在App结构体中定义可绑定的方法
type App struct {
ctx context.Context
cache *freecache.Cache
cron *cron.Cron
cronEntrys map[string]cron.EntryID
AiTools []data.Tool
}
// Greet方法可被前端调用
func (a *App) Greet(stockCode string) *data.StockInfo {
follow := &data.FollowedStock{
StockCode: stockCode,
}
db.Dao.Model(follow).Where("stock_code = ?", stockCode).Preload("Groups").First(follow)
stockInfo := getStockInfo(*follow)
return stockInfo
}
前端通过wailsjs包调用Go方法:
// 前端调用示例
import
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



