跳转到内容
VibeQuant Blog
返回

ashare-quant Web 应用设计方案(v4 · 双进程 + 桌面控制台 + 市场注册表)

更新于:

ashare-quant Web 应用设计方案(v4 · 双进程 + 桌面控制台 + 市场注册表)

本文档描述当前已实现的系统全貌。v4 最大的变化是从”单进程 Web 服务”升级为 双进程架构:一个轻量 tkinter 桌面控制台(GUI) + 一个独立后台服务进程**。 Web 应用(Flask 3.1.1 + Jinja2 + Bootstrap5 + ECharts,端口 5188)由后台服务进程承载, 由 GUI 按需启停、改端口、看全局日志、管理数据。

变更记录:v1 三页草案 → v2 五页 + 自定义因子 + LLM → v3 反映全部实现 → v4 双进程 + GUI 单入口 + 日志中控 + 市场注册表(配置驱动,TDX 优先)。


1. 总体架构(v4:双进程)

┌──────────────────────────────────────────────────────────────────┐
│  GUI 进程  gui.py  (tkinter,仅标准库,瞬启)                       │
│  ┌────────────┬─────────────┬──────────────┬─────────────┐       │
│  │ 控制台      │ 服务         │ 数据/市场     │ 任务         │       │
│  │ (全局日志)  │ (Web 启停)   │ (注册表/导入)  │ (Job 状态)   │       │
│  └────────────┴─────────────┴──────────────┴─────────────┘       │
│   · 启动后台服务进程(自动拉起)                                   │
│   · 增量拉取日志 /ctrl/logs?after=   · 启停 Web /ctrl/flask/*      │
│   · 看市场 /ctrl/markets              · 提交任务 /ctrl/jobs/submit │
└───────────────────────────────┬──────────────────────────────────┘
                                │ 控制通道 HTTP 127.0.0.1:5190(stdlib)
┌───────────────────────────────▼──────────────────────────────────┐
│  服务进程  core/service.py  (双进程之"服务")                       │
│  core/                                                           │
│  ├─ loghub.py        LogHub 全局日志中控(独立线程+环形缓冲+Tee) │
│  ├─ apppool.py       AppPool 统一线程池 + Flask 服务线程启停       │
│  ├─ control.py       ControlServer 控制通道路由                    │
│  └─ service.py       ServiceFacade 装配 + 市场概览按需刷新          │
│  webapp/  Flask 3 (JobManager 注入 AppPool.executor 统一线程池)    │
│  data/    fetchers · store(daily 带 market 列 + symbols 主表)      │
│           markets.py(注册表) · pipeline · calendar                 │
│  factors/ strategy/ backtest/ analysis/ execution/                 │
└───────────────────────────────────────────────────────────────────┘

关键设计(v4 新增):

保留的设计(v3,依旧成立):核心模块不改,main.py/run_web.py 与 Web 共用 data/pipeline.py、backtest/pipeline.py(带 progress(pct,msg) 回调);长任务一律走 JobManager 线程池;静态资源 ?v= 版本号 + no-cache;因子面板/模拟盘 60s TTL 缓存; 前端 10s 心跳 /api/health。

# 启动方式(三选一,推荐第一条)
python gui.py            # 桌面控制台(单入口,自动拉起服务进程)
python run_web.py        # 兼容 shim:直接启动服务 + 自动启 Web → 5188
python main.py ...       # 兼容 CLI(update/today/backtest/...)

2. 五页面(Web,已实现功能)

2.1 仪表盘 /dashboard

2.2 数据管理 /data

2.3 策略生成 /strategy

三列布局:择股 / 调仓 / 择时 / 自定义因子;中列因子与打分 + 策略保存/加载;右列预览; 底部 LLM 对话面板(OpenAI 兼容,默认 DeepSeek,SSE 流式,会话持久化)。 生成调仓信号 → 模拟盘(后台任务):完整历史信号序列,覆盖式写入。

2.4 策略回测 /backtest

左:策略/日期/资金/复权/基准/成本;主区:6 指标卡、净值对比、回撤/逐年/交易/信号 Tab; 结果缓存 outputs/results/<job_id>.json;“附回测结果→LLM”。

2.5 模拟盘 /paper

策略 + 起始 + 结束 + “开始模拟”;状态卡、净值、持仓/已平仓、调仓记录; 覆盖式记录、时间窗口、合成初始买入、全程空仓保持现金。

3. 策略配置模型(StrategyConfig,与 v3 一致)

pool(择股)· strategy(top_n/div_rank_n/min_div_years/rebalance_freq 等)· factors(form/expression/代码三模式)。执行语义:调仓日生成、cap_only/target 减仓风格、择时空仓目标 {} 为合法信号。

4. 模拟盘数据模型(与 v3 一致)

outputs/paper_account.json:[{signal_date, strategy, generated_at, target}]; 按 strategy 覆盖;回放”次日开盘成交”与回测同口径。

5. 页面状态持久化(localStorage,与 v3 一致)

所有页面表单变化即保存、切换自动恢复(common.js loadPageState/savePageState)。

6. REST API 清单(当前实际,46 条,与 v3 一致)

页面路由 + /api/data、/api/strategies、/api/factors、/api/backtest、 /api/jobs、/api/paper、/api/dashboard、/api/llm、/api/health。 (数据页 /api/data/status 现返回按市场的 markets 概览。)

7. 市场注册表(v4 新增)

config/markets.json —— 配置驱动的市场注册表:

{
  "markets": [
    {"id": "A",          "name": "A股-个股", "kind": "stock",  "enabled": true,
     "tdx": {"dir": "vipdoc", "subdirs": ["sh", "sz", "bj"]},
     "adapter": "ashare", "online": ["akshare"], "note": "个股(含退市股)"},
    {"id": "A_index",    "name": "A股-指数", "kind": "index", "enabled": true,
     "tdx": {"dir": "vipdoc", "subdirs": ["sh", "sz"]}, "adapter": "ashare_index_tdx",
     "online": ["akshare"], "note": "沪深指数,tdx 指数 32B/164B 记录"},
    {"id": "A_sector",   "name": "A股-板块", "kind": "sector", "enabled": true,
     "tdx": {"dir": "vipdoc", "subdirs": ["sh", "sz"]}, "adapter": "ashare_sector_tdx",
     "online": [], "note": "本策略/概念板块(880/885 前缀)"},
    {"id": "HK",         "name": "港股",     "kind": "stock",  "enabled": false,
     "adapter": "hk", "online": ["akshare"], "note": "扩展市场(预留)"},
    {"id": "US",         "name": "美股",     "kind": "stock",  "enabled": false,
     "adapter": "us", "online": ["akshare"], "note": "扩展市场(预留)"},
    {"id": "COMMODITY",  "name": "大宗商品", "kind": "quotes", "enabled": false,
     "adapter": "commodity", "online": [], "note": "扩展市场(预留)"},
    {"id": "CRYPTO",     "name": "虚拟币",   "kind": "quotes", "enabled": false,
     "adapter": "crypto", "online": ["binance"], "note": "扩展市场(预留)"}
  ]
}

8. 代码结构(当前实际)

ashare-quant/
├── config/
│   ├── settings.py          # 策略参数、端口(5188/5190)、TDX_DIR、LOG_BUF_MAX、MARKETS_CONFIG
│   └── markets.json         # 市场注册表(A/A_index/A_sector/HK/US/COMMODITY/CRYPTO)
├── core/                    # 双进程核心(服务进程)
│   ├── loghub.py            # LogHub:独立 logging 线程 + 环形缓冲 + Tee(stdout/stderr) + logging Handler
│   ├── apppool.py           # AppPool:统一 ThreadPoolExecutor + Flask(make_server) 线程启停
│   ├── control.py           # ControlServer:GUI↔服务控制通道(/ctrl/status|logs|flask|jobs|markets|db|shutdown)
│   └── service.py           # ServiceFacade:装配 + 任务派发(_JOB_DISPATCH)+ 市场概览按需刷新
├── data/
│   ├── markets.py           # 注册表加载 + import_tdx/import_all_enabled(market='A' 特判 → pipeline)
│   ├── pipeline.py          # update_data / update_today / backfill / refresh_list / import_tdx_data
│   ├── fetchers/akshare_fetcher.py
│   ├── store/sqlite_store.py# daily(market 列) + symbols 主表 + 迁移 + 市场感知查询
│   └── calendar.py
├── webapp/
│   ├── __init__.py  jobs.py  llm.py  paper.py
│   ├── api/ pages.py data_api.py strategies_api.py backtest_api.py
│   │        paper_api.py dashboard_api.py llm_api.py
│   └── templates/ static/   # Bootstrap5/ECharts/marked
├── factors/ strategy/ backtest/ analysis/ execution/ strategies/ sessions/
├── gui.py                  # 【推荐入口】tkinter 桌面控制台(单入口=双进程)
├── run_web.py              # 兼容 shim:启动服务 + 自动启 Web
├── main.py                 # 兼容 CLI(已接入 LogHub)
├── tests/  outputs/
└── config/llm.json         # LLM 配置(gitignore)

9. 控制通道 API(GUI ↔ 服务进程,v4 新增)

core/control.py,ThreadingHTTPServer,默认 127.0.0.1:5190:

方法 & 路径说明
GET /ctrl/status服务状态(flask/job_running/uptime)
GET /ctrl/logs?after=&level=增量拉取全局日志(seq 游标)
GET /ctrl/flask/status · POST /ctrl/flask/start{port} · POST /ctrl/flask/stopWeb 服务启停/改端口
GET /ctrl/jobs?kind= · POST /ctrl/jobs/submit{kind,params}任务列表/提交(update/today/backfill/refresh_list/markets_import/backtest/signal)
GET /ctrl/markets · POST /ctrl/markets/import{market,dir} · POST /ctrl/markets/toggle{market,enabled}市场注册表/导入/启停
GET /ctrl/db/status数据库大小 + 分市场概览
POST /ctrl/shutdown优雅关闭服务进程

按需刷新:市场概览(各市场标的/K线数)用 market_summary 缓存 + 短 TTL + 进行中保护(_maybe_refresh_summary),GUI 打开”数据/市场”页签时才扫描、导入/更新 完成后立即 _bump_summary_refresh——避免对 3.5GB 库做固定周期全表扫描。

10. 已知限制与注意事项

  1. 本地单用户工具:仅绑定 127.0.0.1;api_key 明文存本机(gitignore)
  2. 控制通道 5190 / Web 5188 端口:GUI 启动服务进程监听 5190;Web 由 GUI 在 5188 启动(可改端口)。关窗会 /ctrl/shutdown 优雅退出并 terminate 子进程。
  3. 每日调仓/全市场信号生成较慢:后台任务,数据量大后更久
  4. 市场概览缓存延迟:导入/更新后概览数字会稍后(按需刷新)更新,非实时
  5. 残留服务器进程:若 GUI 异常退出未关闭,可 taskkill /F /IM python.exe 或重启 (正常关窗无此问题)
  6. 模板改动需检查 div 配平/嵌套;改前端 JS 后 Ctrl+F5(已加 ?v= + no-cache)
  7. 基准对比:000922/000300 为价格指数,红利策略最优基准是 H00922 全收益

分享这篇文章:

上一篇
QuickGEN 智能审查页面使用说明

评论