Tech Whims

[28] 组合监控 Dashboard 技术方案

2026-03-22


结构风险 · 共 12 篇

tradeSys #28: 组合监控 Dashboard 技术方案

Plan E3-AW (DBMF/GLD/sUSDe/BIL 各25%) 实盘监控系统设计 研究日期: 2026-03-22 研究员: 娃彩 ✨


核心结论(TL;DR)

推荐方案:Python CLI Dashboard + Streamlit 可视化面板 + OpenClaw Heartbeat 告警

决策选择理由
主 UIStreamlit(单文件)零部署成本,Python 原生,Mac 本地 streamlit run 即可
日常监控CLI 脚本 (tradesys-check)cron 驱动,无需开浏览器,输出到 Terminal/日志
告警通道OpenClaw Heartbeat + Terminal 通知已有基础设施,零额外成本
数据存储DuckDB 单文件已选定技术栈,嵌入式无服务器
数据更新日频(ETF)+ 8h频(sUSDe)匹配策略的季度再平衡节奏

不推荐:Grafana(运维重、个人交易者杀鸡用牛刀)、Jupyter Notebook(不适合定期自动化运行)、纯 Web App(Next.js/React 技术栈与 Python 生态割裂)。


1. Dashboard 架构设计

1.1 技术选型对比

维度StreamlitGrafanaCLI DashboardJupyter Notebook
部署复杂度⭐ 极低(pip install streamlit⛔ 高(Docker/Homebrew + 配置数据源)⭐ 极低(纯 Python 脚本)⭐ 低(pip install jupyter
维护成本低(单 .py 文件)高(版本升级、数据源插件管理)极低(无依赖)中(notebook 版本管理混乱)
可视化能力⭐⭐⭐ 丰富(Plotly/Altair 原生集成)⭐⭐⭐ 最强(专业仪表盘)⛔ 弱(ASCII 图表)⭐⭐⭐ 丰富(matplotlib/plotly)
移动端查看✅ 浏览器访问(局域网 IP)✅ 原生响应式⛔ 需要 SSH/Terminal⚠️ 勉强可用
自动化集成⭐⭐ 可 cron 触发生成报告⭐⭐⭐ 原生告警系统⭐⭐⭐ 天然 cron 友好⛔ 不适合自动化
与 Python/DuckDB 集成⭐⭐⭐ 原生⚠️ 需要插件或 API 层⭐⭐⭐ 原生⭐⭐⭐ 原生
适合个人交易者⛔ 过度工程✅(日常监控)⚠️ 探索性分析用

1.2 推荐方案:双层架构

Layer 1: CLI Monitor (tradesys-check)
├── cron 每日运行
├── 输出:Terminal 文本 + 日志文件
├── 触发条件告警 → OpenClaw Heartbeat
└── 零依赖,可靠性最高

Layer 2: Streamlit Dashboard (tradesys-dashboard)
├── 按需启动:streamlit run dashboard.py
├── 输出:浏览器交互式面板
├── 周度/月度深度分析时使用
└── 可从手机浏览器访问(同一 WiFi)

为什么是双层而不是只选一个?

1.3 为什么不选 Grafana

Grafana 是优秀的监控工具,但它为 DevOps/SRE 设计,不为个人交易者设计:

  1. 运维负担:需要持续运行的服务进程(Grafana Server),Mac 上要么 Docker 要么 Homebrew service。个人交易者不应该为了看组合状态而维护一个服务器
  2. 数据源适配:DuckDB 没有原生 Grafana 数据源插件。需要写 API 中间层或用 JSON API 数据源——额外 500+ 行代码
  3. 学习成本:Grafana 的 Query Editor、Panel 配置、Dashboard JSON 都需要学习。Streamlit 直接写 Python,老板已熟悉
  4. 杀鸡用牛刀:Grafana 设计用来监控几千台服务器、几百个微服务。我们监控 4 个标的、~10 个指标

唯一适合 Grafana 的场景:如果未来 tradeSys 扩展到 20+ 标的、需要实时(秒级)监控、多人协作查看——但那已经不是"个人交易者"了。

1.4 系统架构图

┌─────────────────────────────────────────────────────────────┐
│                     数据源层                                  │
│  IBKR TWS API ─┐                                            │
│  Stooq.com    ─┤── data_fetcher.py ──→ DuckDB (tradesys.db) │
│  FRED API     ─┤                                            │
│  Binance API  ─┤                                            │
│  Ethena API   ─┘                                            │
└───────────────────────────┬─────────────────────────────────┘
                            │
                            ▼
┌─────────────────────────────────────────────────────────────┐
│                     计算层                                    │
│  metrics_engine.py                                           │
│  ├── calc_portfolio_value()     组合净值                      │
│  ├── calc_drawdown()            回撤计算                      │
│  ├── calc_rolling_sharpe()      滚动Sharpe                   │
│  ├── calc_drift()               配比偏离度                    │
│  ├── calc_factor_beta()         因子暴露                      │
│  └── calc_rebalance_signal()    再平衡信号                    │
└───────────────────────────┬─────────────────────────────────┘
                            │
                  ┌─────────┴─────────┐
                  ▼                   ▼
┌────────────────────────┐  ┌─────────────────────────┐
│  Layer 1: CLI Monitor  │  │  Layer 2: Streamlit     │
│  tradesys-check        │  │  tradesys-dashboard     │
│  ├── 日度P0检查        │  │  ├── 组合总览页          │
│  ├── 告警判定          │  │  ├── 回撤分析页          │
│  └── 输出到Terminal    │  │  ├── 因子暴露页          │
│       + OpenClaw       │  │  └── 再平衡建议页        │
└────────────────────────┘  └─────────────────────────┘

2. 核心监控指标体系

2.1 指标分层总表

从 tradeSys 已有研究(#24 配比优化、#25 执行成本、#26 回撤管理、#18 Crypto Funding)中提取所有可编程监控的指标,按优先级分层:

P0 指标(每日必看,CLI 自动输出)

#指标计算方式触发条件来源研究
1组合净值 & 日收益率Σ(持仓市值)基础
2当前回撤深度(当前净值 - 历史最高) / 历史最高>-5% 黄灯, >-10% 红灯#26 回撤管理
3回撤持续天数从最后一次创新高至今的自然日>180天 红灯#26 §2.3
4各标的配比偏离度abs(当前权重 - 25%)任一标的 >5% 触发再平衡#24 配比优化, #25 §5.2
5sUSDe 价格/锚定状态sUSDe 相对于 USDT 的偏离脱锚 >2% 红灯#18 Crypto

P1 指标(每周检查,CLI + Streamlit)

#指标计算方式阈值来源研究
66个月滚动 Sharpe126日窗口年化 Sharpe<-0.5 黄灯, 连续2窗口<0 红灯#26 §2.2
7DBMF vs SG CTA Beta60日滚动回归 β<0.5 红灯, <0 熔断#26 §2.4
8组合子策略回撤贡献各标的对组合回撤的边际贡献单标的贡献 >组合回撤的60%#26 §3.2
9Ethena TVL & 占OI比例Ethena Dashboard 数据TVL <$3B 或 OI占比 >15% 黄灯#18 §2.3
10BTC/ETH Funding RateBinance API 8h funding连续 7 天为负 黄灯#18 §1.1

P2 指标(每月回顾,Streamlit 深度分析)

#指标计算方式用途来源研究
11月度/季度收益归因Brinson 模型简化版理解哪个标的贡献了收益/亏损#24
12年化执行成本追踪累计 Spread + 佣金 + Gas验证 <0.5% 年化目标#25 §5.1
13相关性矩阵变化60日滚动相关性 vs 长期相关性检测相关性结构崩坏#24 相关性矩阵
14VIX 水平 & Spread 扩张VIX 当前 vs 30/90日均值高波动环境下延迟非紧急再平衡#25 §1.3
15Monte Carlo 路径模拟1000条路径, 基于历史波动率目标达成概率更新#24 风险提示

2.2 P0 指标计算示例代码

"""tradesys P0 指标计算引擎"""
import duckdb
from dataclasses import dataclass
from datetime import date

@dataclass
class P0Report:
    date: date
    portfolio_value: float
    daily_return: float
    drawdown_pct: float          # 负数
    drawdown_days: int
    drift: dict                  # {"DBMF": 0.02, ...}
    susde_peg_deviation: float
    alert_level: int             # 1-4
    alerts: list

TARGET_WEIGHTS = {"DBMF": 0.25, "GLD": 0.25, "sUSDe": 0.25, "BIL": 0.25}
DRIFT_THRESHOLD = 0.05
DD_DURATION_THRESHOLD = 180

def calc_p0(db_path: str = "tradesys.db") -> P0Report:
    con = duckdb.connect(db_path, read_only=True)
    
    # 1. 当前组合净值
    row = con.execute("""
        SELECT trade_date, total_value FROM portfolio_daily
        ORDER BY trade_date DESC LIMIT 1
    """).fetchone()
    today, portfolio_value = row
    
    # 2. 日收益率
    prev = con.execute("""
        SELECT total_value FROM portfolio_daily
        ORDER BY trade_date DESC LIMIT 1 OFFSET 1
    """).fetchone()
    daily_return = (portfolio_value / prev[0] - 1) if prev else 0.0
    
    # 3. 回撤
    peak = con.execute("SELECT MAX(total_value) FROM portfolio_daily").fetchone()[0]
    drawdown_pct = (portfolio_value / peak - 1)
    
    # 4. 回撤持续天数
    peak_date = con.execute("""
        SELECT trade_date FROM portfolio_daily
        WHERE total_value = (SELECT MAX(total_value) FROM portfolio_daily)
        ORDER BY trade_date DESC LIMIT 1
    """).fetchone()[0]
    drawdown_days = (today - peak_date).days if isinstance(peak_date, date) else 0
    
    # 5. 配比偏离度
    holdings = con.execute("SELECT asset, market_value FROM holdings_latest").fetchall()
    total = sum(h[1] for h in holdings)
    drift = {asset: mv/total - TARGET_WEIGHTS.get(asset, 0.25) for asset, mv in holdings}
    
    # 6. 告警判定
    dd_abs = abs(drawdown_pct)
    if dd_abs >= 0.15: alert_level = 4
    elif dd_abs >= 0.10: alert_level = 3
    elif dd_abs >= 0.05: alert_level = 2
    else: alert_level = 1
    
    alerts = []
    if alert_level >= 2:
        alerts.append(f"⚠️ 回撤 {drawdown_pct:.1%} 达到 Level {alert_level}")
    if drawdown_days > DD_DURATION_THRESHOLD:
        alerts.append(f"⚠️ 回撤已持续 {drawdown_days} 天")
    for asset, d in drift.items():
        if abs(d) > DRIFT_THRESHOLD:
            alerts.append(f"📊 {asset} 配比偏离 {d:+.1%}")
    
    con.close()
    return P0Report(today, portfolio_value, daily_return, drawdown_pct,
                    drawdown_days, drift, 0.0, alert_level, alerts)

2.3 CLI 输出格式设计

═══════════════════════════════════════════════════════
  tradeSys Daily Monitor | 2026-03-22 | Level 1 ✅
═══════════════════════════════════════════════════════

  Portfolio Value:  $51,234.56  (+0.23%)
  Peak Value:       $51,500.00
  Drawdown:         -0.52% (3 days)

  ┌──────────┬──────────┬──────────┬──────────┐
  │  DBMF    │  GLD     │  sUSDe   │  BIL     │
  │  24.8%   │  25.3%   │  24.9%   │  25.0%   │
  │  -0.2%   │  +0.3%   │  -0.1%   │  +0.0%   │
  │  ✅ OK   │  ✅ OK   │  ✅ OK   │  ✅ OK   │
  └──────────┴──────────┴──────────┴──────────┘

  Alerts: None
  Next Rebalance: Not needed (max drift 0.3%)

═══════════════════════════════════════════════════════

3. 告警系统设计

3.1 告警通道选择

通道成本实时性实现复杂度推荐等级
Terminal 输出 + macOS 通知$0cron 频率⭐ 极低P0 日常
OpenClaw Heartbeat$0Heartbeat 频率⭐ 极低P0 日常
Telegram Bot$0即时⭐⭐ 低P0 紧急 (Level 3+)
Email (SMTP)$0分钟级⭐⭐ 低P1 周报

推荐组合

3.2 告警与回撤管理4级框架的映射

直接复用 #26 回撤管理的分级框架:

ALERT_CONFIG = {
    1: {  # 观察 (DD < 5%)
        "channels": ["log"],
        "frequency": "daily",
        "action": "LOG_ONLY",
    },
    2: {  # 警戒 (DD 5-10%)
        "channels": ["log", "terminal_notification", "openclaw"],
        "frequency": "daily",
        "action": "DIAGNOSE",
        "cooldown_hours": 24,
    },
    3: {  # 干预 (DD 10-15%)
        "channels": ["log", "terminal_notification", "openclaw", "telegram"],
        "frequency": "4h",
        "action": "PAUSE_REBALANCE",
        "cooldown_hours": 4,
    },
    4: {  # 熔断 (DD > 15%)
        "channels": ["log", "terminal_notification", "openclaw", "telegram"],
        "frequency": "1h",
        "action": "CIRCUIT_BREAK",
        "cooldown_hours": 1,
        "require_ack": True,
    },
}

3.3 误报控制策略

“狼来了"效应是告警系统的头号杀手。

策略实现方式预期效果
冷却期 (Cooldown)同级别告警在冷却期内不重复发送避免 Level 2 每天轰炸
升级确认从 Level 1→2 需连续 2 天触发阈值过滤单日噪声
周末静默周末不发送 Level 1-2 告警减少无效通知
状态变化通知只在级别变化时发送消息最优:最多 2-3 条
def should_alert(current_level: int, last_level: int, last_alert_time: float) -> bool:
    """只在级别变化或超过冷却期时告警"""
    import time
    if current_level != last_level:
        return True
    if current_level >= 3:
        cooldown = ALERT_CONFIG[current_level]["cooldown_hours"] * 3600
        return (time.time() - last_alert_time) > cooldown
    return False

3.4 macOS Terminal 通知实现

import subprocess

def macos_notify(title: str, message: str, sound: str = "default"):
    """macOS 原生通知"""
    script = f'display notification "{message}" with title "{title}" sound name "{sound}"'
    subprocess.run(["osascript", "-e", script], check=True)

# 使用
macos_notify("tradeSys ⚠️ Level 2", "回撤 -6.2%, 持续 15 天")

3.5 OpenClaw Heartbeat 集成

HEARTBEAT.md 中添加:

## tradeSys 组合监控
- 运行 `python3 ~/tradesys/tradesys_check.py`
- 如果输出包含 "Level 2" 或以上,将结果发送给老板
- 如果输出 "Level 1",忽略

4. 数据管道设计

4.1 数据源接入方案

数据源获取内容API/方式频率认证
Stooq.comDBMF/GLD/BIL 日频价格HTTP CSV 下载日频 (收盘后)无需
IBKR TWS API持仓、订单状态、账户余额ib_insync Python 库日频/按需TWS 运行时
Binance APIsUSDe 价格、BTC/ETH Funding RateREST API + ccxt8h (funding) / 日频API Key
Ethena APIsUSDe APY、TVL、Reserve Fund公开 REST API日频无需
FRED API联邦基金利率、VIXfredapi Python 库日频免费 API Key
Yahoo Finance备用价格源 + SG CTA Index proxyyfinance日频无需

4.2 数据获取代码示例

"""tradesys 数据获取器"""
import pandas as pd
from datetime import date, timedelta

# Stooq 日频价格
def fetch_stooq(symbol: str, start: date, end: date) -> pd.DataFrame:
    url = f"https://stooq.com/q/d/l/?s={symbol}.us&d1={start:%Y%m%d}&d2={end:%Y%m%d}&i=d"
    df = pd.read_csv(url)
    df["Date"] = pd.to_datetime(df["Date"])
    df = df.rename(columns={"Close": "close", "Date": "trade_date"})
    df["asset"] = symbol.upper()
    return df[["trade_date", "asset", "close"]]

# Binance Funding Rate
def fetch_funding_rate(symbol: str = "BTCUSDT", limit: int = 30):
    import ccxt
    exchange = ccxt.binance({"options": {"defaultType": "swap"}})
    rates = exchange.fetch_funding_rate_history(symbol, limit=limit)
    return pd.DataFrame([{
        "timestamp": r["timestamp"],
        "symbol": symbol,
        "funding_rate": r["fundingRate"],
    } for r in rates])

# Ethena sUSDe 数据
def fetch_ethena_stats():
    import requests
    resp = requests.get("https://app.ethena.fi/api/yields/protocol-and-staking-yield")
    data = resp.json()
    return {
        "susde_apy": data.get("stakingYield", {}).get("value", 0),
        "tvl": data.get("tvl", 0),
    }

4.3 数据更新频率设计

数据类型更新频率触发方式理由
ETF 日频价格每日 17:00 ETcron日内价格对季度再平衡无意义
sUSDe 价格每 8 小时cron匹配 Funding Rate 结算周期
BTC/ETH Funding Rate每 8 小时cronFunding 每 8h 结算
Ethena TVL/APY每日cron变化缓慢
VIX每日cronSpread 扩张参考

cron 调度示例 (Mac crontab -e):

# tradeSys 数据更新 (北京时间)
# 日频数据 (美股收盘后 ~06:00 CST)
0 6 * * 2-6 cd ~/tradesys && python3 fetch_daily.py >> logs/fetch.log 2>&1

# 8h Funding Rate (00:00, 08:00, 16:00 CST)
0 0,8,16 * * * cd ~/tradesys && python3 fetch_funding.py >> logs/fetch.log 2>&1

# 日度 P0 检查 (06:30 CST)
30 6 * * 2-6 cd ~/tradesys && python3 tradesys_check.py >> logs/check.log 2>&1

# 周度 P1 检查 (每周六 10:00 CST)
0 10 * * 6 cd ~/tradesys && python3 tradesys_weekly.py >> logs/weekly.log 2>&1

4.4 DuckDB 表结构设计

-- ═══════════════════════════════════════════════════
-- tradeSys DuckDB Schema
-- 文件: tradesys.db (单文件,本地存储)
-- ═══════════════════════════════════════════════════

-- 1. 资产日频价格
CREATE TABLE IF NOT EXISTS asset_prices (
    trade_date  DATE NOT NULL,
    asset       VARCHAR NOT NULL,
    open_price  DOUBLE,
    high_price  DOUBLE,
    low_price   DOUBLE,
    close_price DOUBLE NOT NULL,
    volume      BIGINT,
    source      VARCHAR DEFAULT 'stooq',
    fetched_at  TIMESTAMP DEFAULT current_timestamp,
    PRIMARY KEY (trade_date, asset)
);

-- 2. 组合每日快照
CREATE TABLE IF NOT EXISTS portfolio_daily (
    trade_date     DATE PRIMARY KEY,
    total_value    DOUBLE NOT NULL,
    daily_return   DOUBLE,
    cumulative_return DOUBLE,
    peak_value     DOUBLE,
    drawdown_pct   DOUBLE,
    drawdown_days  INTEGER,
    alert_level    INTEGER DEFAULT 1,
    created_at     TIMESTAMP DEFAULT current_timestamp
);

-- 3. 持仓明细
CREATE TABLE IF NOT EXISTS holdings (
    trade_date     DATE NOT NULL,
    asset          VARCHAR NOT NULL,
    quantity       DOUBLE NOT NULL,
    avg_cost       DOUBLE NOT NULL,
    market_price   DOUBLE NOT NULL,
    market_value   DOUBLE NOT NULL,
    weight         DOUBLE NOT NULL,
    target_weight  DOUBLE DEFAULT 0.25,
    drift          DOUBLE,
    unrealized_pnl DOUBLE,
    PRIMARY KEY (trade_date, asset)
);

-- 4. 策略健康度指标(P1 周度)
CREATE TABLE IF NOT EXISTS strategy_health (
    check_date         DATE PRIMARY KEY,
    rolling_sharpe_6m  DOUBLE,
    dbmf_cta_beta      DOUBLE,
    dbmf_cta_r_squared DOUBLE,
    max_single_asset_dd_contrib DOUBLE,
    correlation_dbmf_gld DOUBLE,
    vix_current        DOUBLE,
    created_at         TIMESTAMP DEFAULT current_timestamp
);

-- 5. Crypto Funding & Ethena 监控
CREATE TABLE IF NOT EXISTS crypto_monitor (
    check_time         TIMESTAMP PRIMARY KEY,
    btc_funding_rate   DOUBLE,
    eth_funding_rate   DOUBLE,
    btc_funding_7d_avg DOUBLE,
    ethena_tvl         DOUBLE,
    ethena_oi_pct      DOUBLE,
    susde_apy          DOUBLE,
    susde_price        DOUBLE,
    susde_peg_ok       BOOLEAN DEFAULT true,
    created_at         TIMESTAMP DEFAULT current_timestamp
);

-- 6. 交易记录 (执行成本追踪)
CREATE TABLE IF NOT EXISTS trades (
    trade_id       VARCHAR PRIMARY KEY,
    trade_date     DATE NOT NULL,
    asset          VARCHAR NOT NULL,
    side           VARCHAR NOT NULL,
    quantity       DOUBLE NOT NULL,
    price          DOUBLE NOT NULL,
    commission     DOUBLE DEFAULT 0,
    spread_cost    DOUBLE DEFAULT 0,
    gas_fee        DOUBLE DEFAULT 0,
    total_cost     DOUBLE,
    order_type     VARCHAR,
    execution_venue VARCHAR,
    notes          VARCHAR,
    created_at     TIMESTAMP DEFAULT current_timestamp
);

-- 7. 告警日志
CREATE TABLE IF NOT EXISTS alert_log (
    alert_id       INTEGER PRIMARY KEY,
    alert_time     TIMESTAMP NOT NULL,
    alert_level    INTEGER NOT NULL,
    prev_level     INTEGER,
    channel        VARCHAR NOT NULL,
    message        VARCHAR NOT NULL,
    acknowledged   BOOLEAN DEFAULT false,
    created_at     TIMESTAMP DEFAULT current_timestamp
);

-- 8. 再平衡记录
CREATE TABLE IF NOT EXISTS rebalance_log (
    rebalance_id   INTEGER PRIMARY KEY,
    rebalance_date DATE NOT NULL,
    trigger_type   VARCHAR NOT NULL,
    pre_weights    VARCHAR,
    post_weights   VARCHAR,
    total_cost     DOUBLE,
    notes          VARCHAR,
    created_at     TIMESTAMP DEFAULT current_timestamp
);

-- 视图:最新持仓
CREATE OR REPLACE VIEW holdings_latest AS
SELECT h.* FROM holdings h
INNER JOIN (SELECT MAX(trade_date) as max_date FROM holdings) m
ON h.trade_date = m.max_date;

-- 索引优化
CREATE INDEX IF NOT EXISTS idx_prices_asset_date ON asset_prices(asset, trade_date);
CREATE INDEX IF NOT EXISTS idx_portfolio_date ON portfolio_daily(trade_date);

4.5 历史数据回填策略

数据回填范围数据源预估时间
GLD 日频2019-06-03 起Stooq<1 分钟
DBMF 日频2019-06-03 起Stooq<1 分钟
BIL 日频2019-06-03 起Stooq<1 分钟
sUSDe 价格2024-01-01 起Binance/CoinGecko~2 分钟
BTC Funding Rate2020-01-01 起Binance API~5 分钟
"""一次性历史回填脚本"""
def backfill_etf_prices(db_path: str = "tradesys.db"):
    import duckdb
    con = duckdb.connect(db_path)
    for symbol in ["dbmf", "gld", "bil"]:
        df = fetch_stooq(symbol, date(2019, 6, 3), date.today())
        con.execute("""
            INSERT OR REPLACE INTO asset_prices
            (trade_date, asset, close_price, volume, source)
            SELECT trade_date, asset, close, volume, 'stooq' FROM df
        """)
        print(f"Backfilled {symbol}: {len(df)} rows")
    con.close()

5. 实操部署方案

5.1 项目目录结构

~/tradesys/
├── tradesys.db              # DuckDB 数据库文件
├── config.yaml              # 配置文件
├── tradesys_check.py        # CLI P0 日度检查
├── tradesys_weekly.py       # P1 周度检查
├── dashboard.py             # Streamlit Dashboard
├── data/
│   ├── fetcher.py           # 数据获取器
│   ├── backfill.py          # 历史回填
│   └── schema.sql           # DuckDB 建表语句
├── engine/
│   ├── metrics.py           # 指标计算引擎
│   ├── alerts.py            # 告警系统
│   └── rebalance.py         # 再平衡信号生成
├── logs/
│   ├── fetch.log
│   ├── check.log
│   └── weekly.log
└── requirements.txt

5.2 config.yaml 设计

portfolio:
  initial_capital: 50000
  target_weights:
    DBMF: 0.25
    GLD: 0.25
    sUSDe: 0.25
    BIL: 0.25
  rebalance_drift_threshold: 0.05

drawdown:
  level_2_threshold: 0.05
  level_3_threshold: 0.10
  level_4_threshold: 0.15
  duration_threshold_days: 180

strategy_health:
  rolling_sharpe_window: 126
  factor_beta_window: 60
  sharpe_yellow_threshold: -0.5
  beta_red_threshold: 0.5

alerts:
  telegram:
    enabled: false
    bot_token: ""
    chat_id: ""
  openclaw:
    enabled: true
  terminal_notification:
    enabled: true

api_keys:
  fred: ""
  binance_key: ""
  binance_secret: ""

data:
  db_path: "./tradesys.db"
  log_dir: "./logs"

5.3 冷启动流程(从零到 Dashboard 可用)

# ═══════════════════════════════════════════════════
# tradeSys 冷启动步骤清单
# 预计耗时:30 分钟
# ═══════════════════════════════════════════════════

# Step 1: 创建项目目录 (1 分钟)
mkdir -p ~/tradesys/{data,engine,logs}
cd ~/tradesys

# Step 2: Python 环境 (3 分钟)
python3 -m venv .venv
source .venv/bin/activate
pip install duckdb pandas streamlit ccxt yfinance fredapi requests plotly pyyaml

# Step 3: 初始化数据库 (1 分钟)
python3 -c "
import duckdb
con = duckdb.connect('tradesys.db')
con.execute(open('data/schema.sql').read())
con.close()
print('✅ Database initialized')
"

# Step 4: 历史数据回填 (5 分钟)
python3 data/backfill.py

# Step 5: 配置 API Keys (5 分钟)
cp config.example.yaml config.yaml
# 编辑 config.yaml

# Step 6: 验证数据 (2 分钟)
python3 -c "
import duckdb
con = duckdb.connect('tradesys.db')
for table in ['asset_prices', 'portfolio_daily']:
    count = con.execute(f'SELECT COUNT(*) FROM {table}').fetchone()[0]
    print(f'{table}: {count} rows')
con.close()
"

# Step 7: 首次运行 P0 检查 (1 分钟)
python3 tradesys_check.py

# Step 8: 配置 cron (2 分钟)
crontab -e
# 粘贴 §4.3 的 cron 配置

# Step 9: 启动 Dashboard (即时)
streamlit run dashboard.py
# 浏览器自动打开 http://localhost:8501

# Step 10: 手机访问 (可选)
# 同一 WiFi 下,手机浏览器访问 http://<Mac-IP>:8501

5.4 requirements.txt

duckdb>=1.1.0
pandas>=2.0
streamlit>=1.35
plotly>=5.18
ccxt>=4.0
yfinance>=0.2.36
fredapi>=0.5
requests>=2.31
pyyaml>=6.0

5.5 与 OpenClaw 集成方案

方案 A:Heartbeat 集成(推荐)

HEARTBEAT.md 中添加:

## tradeSys 监控
- [ ] 运行 `cd ~/tradesys && .venv/bin/python tradesys_check.py --json`
- [ ] 如果返回的 alert_level >= 2,告诉老板
- [ ] 如果返回的 alert_level == 1,忽略

方案 B:Cron + OpenClaw 消息(备选)

30 6 * * 2-6 cd ~/tradesys && \
  RESULT=$(.venv/bin/python tradesys_check.py --json) && \
  LEVEL=$(echo $RESULT | python3 -c "import sys,json; print(json.load(sys.stdin)['alert_level'])") && \
  [ "$LEVEL" -ge 2 ] && \
  openclaw message send --channel webchat --message "tradeSys Alert: $RESULT"

6. 参考案例

6.1 GitHub 开源 Portfolio Dashboard 对比

通过搜索 GitHub 上 portfolio-tracker topic(138 个公开仓库),筛选出与 tradeSys 需求最相关的项目:

项目语言Stars特点适用性
WealthfolioRust/TS~4K+桌面应用,本地数据,多账户,精美 UI⭐⭐ 通用 tracker,无风险指标
RotkiPython~3K+Crypto+传统资产,隐私优先,开源⭐⭐ 功能全但过重
portfolio-daily-trackerPython新项目Streamlit,A/HK/US 股,AI 助手,OpenClaw 集成⭐⭐⭐ 最接近需求
stonks-cliPython新项目纯 CLI TUI,Yahoo Finance,极简⭐⭐ 轻量但无分析功能
QuantStatsPython~5K+量化分析库,Sharpe/DD/Monte Carlo⭐⭐⭐ 作为计算引擎集成

关键判断

  1. 没有一个现成项目完全满足 tradeSys 的需求——因为我们需要的不是通用 Portfolio Tracker,而是针对 Plan E3-AW 的策略监控系统(含策略失效检测、4级回撤响应、sUSDe/Funding 专项监控)

  2. 最佳策略是自建 + 借鉴

    • QuantStats 作为指标计算引擎(Sharpe、DD、Monte Carlo 已实现)
    • 参考 portfolio-daily-tracker 的 Streamlit 结构(已有 OpenClaw 集成方案)
    • stonks-cli 借鉴 CLI TUI 的呈现方式
  3. 不建议直接使用 Wealthfolio/Rotki——它们是通用理财工具,不是交易策略监控工具。缺少:滚动 Sharpe、因子 beta 检测、回撤分级响应、Funding Rate 监控等核心功能

6.2 专业量化基金 Risk Dashboard 指标借鉴

专业量化基金的 risk dashboard 远比个人交易者需要的复杂。以下是筛选出的个人交易者也应该监控的指标:

来源指标个人交易者版本是否纳入 tradeSys
AQR Risk Parity杠杆率实时监控无杠杆,不需要
Bridgewater All Weather宏观 regime 检测VIX 水平 + 利率方向作为 proxy✅ P2
Two Sigma因子拥挤度Ethena 占 OI 比例作为 sUSDe 拥挤度✅ P1
Man AHL (CTA)趋势信号强度DBMF vs SG CTA Beta✅ P1
Citadel Multi-Strategy子策略 Sharpe 分布各标的滚动 Sharpe✅ P1
Renaissance交易成本归因年化执行成本追踪✅ P2

关键洞察:量化基金 risk dashboard 的核心不是"看得多”,而是"分层看"——

这恰好就是我们 P0/P1/P2 分层的设计理念。专业基金用 100 人团队盯 1000 个指标;个人交易者用自动化脚本盯 15 个指标——效果一样,成本差 1000 倍。

6.3 QuantStats 集成示例

"""利用 QuantStats 生成月度报告"""
import quantstats as qs
import duckdb
import pandas as pd

def generate_monthly_report(db_path: str = "tradesys.db", output: str = "report.html"):
    con = duckdb.connect(db_path, read_only=True)
    df = con.execute("""
        SELECT trade_date, daily_return FROM portfolio_daily ORDER BY trade_date
    """).fetchdf()
    con.close()

    returns = df.set_index("trade_date")["daily_return"]
    returns.index = pd.to_datetime(returns.index)

    # 生成完整 HTML 报告(含 Sharpe、DD、月度热力图等 30+ 指标)
    qs.reports.html(returns, benchmark="SPY", output=output,
                    title="tradeSys Plan E3-AW Monthly Report")
    print(f"✅ Report saved to {output}")

检查线自检

1. 事实对不对

数据点来源可验证
Streamlit 零部署成本pip install streamlit,真实体验
Grafana 需要服务进程Grafana 官方文档
DuckDB 无 Grafana 原生插件Grafana 官方插件市场搜索
Wealthfolio: Rust/TS, 桌面应用GitHub README (2026-03-21 访问)
Rotki: Python, 隐私优先GitHub README (2026-03-21 访问)
portfolio-daily-tracker: Streamlit + OpenClawGitHub README (2026-03-21 访问)
QuantStats: Sharpe/DD/Monte Carlo 库GitHub README (2026-03-21 访问)
4级回撤阈值 5%/10%/15%tradeSys #26 回撤管理✅ 内部一致
配比偏离 5% 再平衡阈值tradeSys #25 执行成本模型✅ 内部一致
DBMF vs SG CTA Beta 0.6-1.0 正常范围tradeSys #26 §2.4✅ 内部一致

2. 判断有没有独到

  1. 双层架构(CLI + Streamlit):不是二选一,而是各司其职——CLI 做每日自动化,Streamlit 做深度分析。多数文章推荐单一方案
  2. 不选 Grafana:给出了具体的不适用理由(DuckDB 无原生插件、运维负担、杀鸡用牛刀),而非泛泛地说"都可以"
  3. 状态变化通知模式:只在告警级别变化时通知,而非每次检查都通知——这是 SRE 实战中的最佳实践
  4. 指标分层来自已有研究:不是凭空设计的 15 个指标,而是从 #24/#25/#26/#18 四篇研究中逐一提取
  5. “没有现成方案"的诚实判断:搜索了 GitHub 138 个项目,结论是自建 + 借鉴,而非盲目推荐某个现成工具

3. 收件人视角

4. 有没有考虑风险

5. 建议能不能直接执行


报告完成时间: 2026-03-22 05:45 CST 研究时间: ~2 小时 参考文献: tradeSys #18, #24, #25, #26; GitHub portfolio-tracker topic; QuantStats/Wealthfolio/Rotki 官方文档