架构图 Mermaid · 六图速览

用例 / 上下文 / 类图(结构)/ 时序图(交互)/ 状态机 / ER。全部依据现有代码绘制, 每张图下方标注对应源码位置。库已本地化(/static/mermaid.min.js),离线可看。

跳转: 用例图 · 上下文图 · 类图 · 时序图 · 状态机图 · ER 图

① 用例图 Use Case — 谁能用系统做什么

flowchart LR User(("量化研究员
浏览器")) Sched(("APScheduler
定时调度")) Src(("外部数据源
AKShare / FRED / multpl")) subgraph SYS["lianghua Web 平台"] direction TB UC1(("查看大盘看板")) UC2(("查日K / 分时图")) UC3(("管理自选 watchlist")) UC4(("浏览策略库")) UC5(("运行回测")) UC6(("查看回测结果")) UC7(("启动模拟盘")) UC8(("查看持仓 / 净值 / 流水")) UC9(("推进 / 停止 / 恢复模拟盘")) UC10(("查看宏观四维看板")) UC11(("盘中实时行情 SSE")) UC12(("定时同步数据缓存")) UC13(("定时推进模拟盘")) UCF(("取日线 / 分时数据")) UCS(("生成策略信号")) end User --- UC1 User --- UC2 User --- UC3 User --- UC4 User --- UC5 User --- UC6 User --- UC7 User --- UC8 User --- UC9 User --- UC10 User --- UC11 Sched --- UC12 Sched --- UC13 UC5 -. include .-> UCF UC5 -. include .-> UCS UC7 -. include .-> UCS UC13 -. include .-> UCF UCF --- Src UC11 --- Src UC12 --- Src

源码:src/web/routes/{market,backtest,paper,strategy,macro}.py · src/web/scheduler.py · src/web/sse.py

② 系统上下文图 Context — 系统边界与外部依赖

flowchart TB User(["量化研究员
浏览器访问 :8000"]) Sched(["APScheduler
进程内定时器"]) subgraph boundary["系统边界"] LH["lianghua Web 平台
FastAPI 单进程
行情 / 策略 / 回测 / 模拟盘 / 宏观"] DB[("SQLite web.db
日线 / 分钟 / 回测 / job / 自选 / 名称")] FS[("paper/
账户JSON + 净值/流水CSV")] LH --- DB LH --- FS end AKShare(["AKShare
新浪 / 东财 / 美股 / 港股"]) FRED(["FRED API
宏观利率 / 信用"]) Multpl(["multpl.com
Shiller CAPE"]) User -->|"浏览 / 操作 / 实时SSE"| LH Sched -.->|"每日同步 + 17:00 推进"| LH LH -->|"拉日线 / 分时 / 快照"| AKShare LH -->|"拉宏观指标"| FRED LH -->|"抓 CAPE 估值"| Multpl

源码:src/web/app.py(服务装配)· src/web/store.py(DB)· src/data/fetcher.py · src/data/fred.py · src/data/cape.py

③ 类图 Class — 核心结构(分层 + 依赖)

classDiagram class StrategyDef { +name : str +description : str +params : tuple +signal_fn : callable +defaults() : dict } class Param { +name : str +type : str +default : float +min : float +max : float } class Store { -_conn : sqlite3.Connection +upsert_daily_bars() +query_daily() +daily_watermark() +insert_backtest_run() +insert_job() +update_job() +toggle_watch() } class DataService { -store : Store -fetch_daily_fn -fetch_minute_fn +get_daily() : DataFrame +get_minute() : DataFrame +get_realtime() : dict } class JobRunner { -_pool : ThreadPoolExecutor +submit() : job_id -_run() +wait() } class Account { +name : str +symbol : str +kind : str +market : str +strategy : str +strategy_params : dict +cash : float +initial_capital : float +shares : int +last_date : str } class MarketRules { +market : str +t1 : bool +lot(price) : int +buy_cost(turnover) : float +sell_cost(turnover, shares) : float } class run_backtest { +run_backtest(ds, strategy, params) : dict } class apply_signal { +apply_signal(acc, rules, signal, price) } StrategyDef "1" o-- "many" Param : params DataService --> Store : 读写缓存 JobRunner --> Store : job 状态机 run_backtest ..> DataService : get_daily run_backtest ..> StrategyDef : signal_fn apply_signal ..> Account : 调仓 apply_signal ..> MarketRules : lot 与 cost Account ..> MarketRules : infer_market

源码:src/strategy/catalog.py(StrategyDef/Param)· src/web/{data_service,store,jobs}.py · src/paper/{account,market_rules,engine}.py

④ 时序图 Sequence — 一次异步回测的完整调用链

sequenceDiagram autonumber actor U as 研究员 participant W as 浏览器 participant R as /backtest 路由 participant JR as JobRunner participant BS as backtest_service participant DS as DataService participant DB as Store(web.db) participant AK as AKShare participant VT as vector_bt U->>W: 配置 策略/标的/区间,点运行 W->>R: POST /backtest/run R->>JR: submit("backtest", payload, work_fn) JR->>DB: INSERT job(status=pending) JR-->>R: job_id R-->>W: 返回 job_id(前端轮询) W->>R: GET /backtest/job/{id} Note over JR,VT: ── 线程池异步执行 work_fn ── JR->>BS: run_backtest(ds, strategy, symbol, ...) BS->>DS: get_daily(symbol, kind, qfq, start, end) DS->>DB: daily_watermark() opt 水位线外有缺口 DS->>AK: fetch_daily(缺口区间) AK-->>DS: 日K DataFrame DS->>DB: upsert_daily_bars() end DB-->>DS: 合并后的日线 DS-->>BS: DataFrame BS->>BS: strat.signal_fn(df, params) → position BS->>VT: run_backtest(df[close, position]) VT-->>BS: nav / buy_hold + 指标 BS->>DB: insert_backtest_run(指标 + 曲线) JR->>DB: UPDATE job(status=done, result_ref) W->>R: GET /backtest/job/{id}(命中 done) R->>DB: get_backtest_run(run_id) DB-->>R: 曲线 / 指标 R-->>W: 渲染 ECharts 净值曲线

源码:src/web/routes/backtest.py · src/web/jobs.py · src/web/backtest_service.py · src/web/data_service.py · src/backtest/vector_bt.py

⑤ 状态机图 State Machine — dip_buy 抄底策略的持仓状态

stateDiagram-v2 [*] --> Flat state "空仓 (position=0)" as Flat state "持仓 (position=1)" as Long Flat --> Long : close < buy(入场满仓) Long --> Flat : close ≥ take_profit(止盈清仓) Long --> Flat : close ≤ stop_loss(止损清仓) Flat --> Flat : close ≥ buy(继续观望) Long --> Long : 区间内(继续持有) note right of Long 同一根 K 线不会既买又卖 (代码 if/elif 互斥保证) end note

源码:src/strategy/dip_buy.py(另:src/web/jobs.py 的 job 状态机 pending→running→done/failed、src/web/paper_service.py 的 运行中↔已停止)

⑥ ER 图 Entity-Relationship — web.db 的 6 张表(SQLite,无强制外键,关系为逻辑关联)

erDiagram DAILY_BARS { TEXT symbol PK TEXT kind PK TEXT adjust PK TEXT date PK REAL open REAL high REAL low REAL close INTEGER volume } MINUTE_BARS { TEXT symbol PK TEXT kind PK TEXT date PK TEXT minute PK REAL close INTEGER volume } NAMES { TEXT code PK TEXT kind PK TEXT name } WATCHLIST { TEXT symbol PK TEXT kind PK TEXT added_at } BACKTEST_RUNS { TEXT id PK TEXT strategy TEXT symbol TEXT kind TEXT start TEXT end TEXT params REAL total_return REAL sharpe TEXT curve } JOBS { TEXT id PK TEXT type TEXT status TEXT payload TEXT result_ref TEXT error } NAMES ||--o{ DAILY_BARS : "标的-日线" NAMES ||--o{ MINUTE_BARS : "标的-分钟" NAMES ||--o{ WATCHLIST : "标的-自选" NAMES ||--o{ BACKTEST_RUNS : "回测标的" JOBS ||--o| BACKTEST_RUNS : "result_ref 指向"

源码:src/web/store.py(_SCHEMA 建表)。逻辑主键 = symbol + kind(NAMES 为标的概念锚点,串起日线/分钟/自选/回测;JOBS.result_ref 指向 BACKTEST_RUNS.id)。