架构图 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)。