← 文档库
📄 文档docs/plans/2026-05-12-push-message-ui-redesign.md
🌱 创建于2026-05-29 01:04
✏️ 修改于2026-05-29 01:04
👁️ 浏览量—
🔗 短链接/~learn/s/1bb6c1ef
🔐 可见性

推送消息 UI 重设计实施计划

> For Claude: Use Skill(name="subagent-driven-development") to implement this plan task-by-task.

Goal: 重新设计截面选基策略引擎的推送消息 UI,解决手机端 Markdown 渲染格式异常、行长过长、仓位分级歧义、信息冗余等问题。

架构: 单文件修改 engine.py 的 generate_push_message() 方法(约120行),调整消息格式、修复Markdown兼容性、精简内容、增加调仓提醒。

Tech Stack: Python 3.12, Server酱 Markdown desp

---

Task 1: 重构 generate_push_message() 消息格式

文件:

变更总览(当前格式 → 新格式):

区块 旧版 新版
------------------
标题 📊 截面选基策略引擎 \ 日期 同上 + ETF总数
分隔线 = x 72 = x 48(更紧凑)
市场状态 占3行+空行 压缩到2行,调仓日嵌入
下次调仓 无 ⏰ 下次调仓: MM-DD 周X 前置醒目
TOP 10 序号 #1 → Markdown标题 ① 纯文本序号
TOP 10 每行 单行长行(60-80字) 拆成两行紧凑版
TOP 10 仓位 ○ 中仓 文字分级 配置 11.5% 百分比
BOTTOM 10 #36 格式 ① 格式,一行紧凑
配置方案 有仓位文字分级 纯百分比,加合计行
风格信号 5-8行 ✅❌ 移除
操作建议 多行长行 精简一行一个
调仓提醒底部 无 ▶ 下次调仓: MM-DD 周X

Step 1: 添加 circled number 工具函数

在 engine.py 顶部附近添加:

def _to_circled(n: int) -> str:
    circled = ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩',
               '⑪', '⑫', '⑬', '⑭', '⑮', '⑯', '⑰', '⑱', '⑲', '⑳']
    if 1 <= n <= len(circled):
        return circled[n - 1]
    return str(n)

Step 2: 计算下次调仓日

添加辅助函数:

def _next_rebalance_date(from_date: str = None) -> str:
    """计算下次调仓日(本周五)"""
    if from_date is None:
        from_date = datetime.now().strftime('%Y-%m-%d')
    dt = datetime.strptime(from_date, '%Y-%m-%d')
    days_ahead = 4 - dt.weekday()  # Friday=4
    if days_ahead <= 0:
        days_ahead += 7
    next_friday = dt + timedelta(days=days_ahead)
    weekday_names = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
    return f"{next_friday.strftime('%m-%d')} {weekday_names[next_friday.weekday()]}"

Step 3: 重写 generate_push_message()

完整替换 L198-318。关键变更点:

(a) 标题区 — 加 ETF 总数

lines.append(f"📊 截面选基策略引擎 | {date}")
lines.append(f"   共扫描 {len(result_df)} 只ETF")
lines.append("=" * 48)
lines.append("")

(b) 市场状态 + 下次调仓 — 压缩到两行

lines.append(f"📈 {regime_label} | 仓位上限 {exposure_cap:.0%}")
lines.append(f"   价格vs年线:{price_vs_ma:+.1%}  波动率比:{vol_ratio:.2f}x")
lines.append(f"⏰ 下次调仓: {_next_rebalance_date(date)}")
lines.append("")

(c) TOP 10 — 两行紧凑 + ① 序号 + 百分比仓位

lines.append("🔥 TOP 10 最强品种")
lines.append("-" * 48)
for i, (_, row) in enumerate(result_df.head(10).iterrows()):
    rank = int(row['排名'])
    score = row['综合评分']
    weight = portfolio.loc[portfolio['代码'] == row['代码'], '建议权重'].values
    adj_weight = weight[0] * exposure_cap if len(weight) > 0 else 0
    lines.append(f"{_to_circled(i+1)} {row['代码']:>10s}  {row['名称']:<12s} [{score:.3f}]")
    lines.append(f"   {row['类别']} · 配置 {adj_weight:>5.1%}")
lines.append("")

(d) BOTTOM 10 — 一行紧凑 + ① 序号

lines.append("🧊 BOTTOM 10 最弱品种")
lines.append("-" * 48)
for row in result_df.tail(10).iterrows():
    r = row[1]  # 兼容iterrows返回的(index, Series)
    break
# 实际用:
for i, (_, row) in enumerate(result_df.tail(10).iterrows()):
    lines.append(f"{_to_circled(i+1)} {row['代码']:>10s}  {row['名称']:<12s}  {row['综合评分']:.3f}  {row['类别']}")
lines.append("")

(e) 配置方案 — 纯百分比 + 合计行

lines.append(f"📋 Top 10 配置方案 (总仓位上限 {exposure_cap:.0%})")
lines.append("-" * 48)
total_weight = 0
for _, row in portfolio.head(10).iterrows():
    adj_weight = row['建议权重'] * exposure_cap
    total_weight += adj_weight
    lines.append(f"  {row['代码']:>10s}  {row['名称']:<12s}  {adj_weight:>5.1%}")
lines.append(f"  {'合计':>10s}  {'':<12s}  {total_weight:>5.1%}")
lines.append("")

(f) 移除风格信号块 — 直接删除 L284-292

(g) 操作建议 — 精简 + 调仓提醒

lines.append("💡 操作建议")
lines.append("-" * 48)
# 市场环境建议
if regime in ('BEAR', 'SEVERE_BEAR'):
    lines.append(f"▶ 当前熊市,仓位控制在 {exposure_cap:.0%} 以内,防御为主")
elif regime == 'HIGH_VOL':
    lines.append(f"▶ 高波动环境,缩舱至 {exposure_cap:.0%},优先低波品种")
elif regime == 'BULL':
    lines.append(f"▶ 牛市环境,仓位上限 {exposure_cap:.0%},积极参与强势板块")
else:
    lines.append(f"▶ 震荡市,仓位上限 {exposure_cap:.0%},均衡配置")
# 关注品种(取排名前3,精简格式)
top3 = result_df.head(3)
codes_str = " ".join(f"{r['名称']}({r['代码']})" for _, r in top3.iterrows())
lines.append(f"▶ 关注: {codes_str}")
# 回避品种(取BOTTOM 10中评分最低的3只)
bot3 = result_df.tail(3)
codes_str = " ".join(f"{r['名称']}({r['代码']})" for _, r in bot3.iterrows())
lines.append(f"▶ 回避: {codes_str}")
# 调仓提醒
lines.append(f"▶ 下次调仓: {_next_rebalance_date(date)}")
lines.append("")
lines.append("=" * 48)

Step 4: 验证输出格式

运行:

./run_push.sh -c 399102.SZ

检查 /Users/aohan/PycharmProjects/adata/adata/aohan/quant/backtest/strategy/custom_signal/消息推送.txt 的格式。

预期输出示例:

📊 截面选基策略引擎 | 2026-05-12
   共扫描 45 只ETF
════════════════════════════════════════

📈 🟢 强势牛市 | 仓位上限 97%
   价格vs年线:+7.4%  波动率比:1.10x
⏰ 下次调仓: 05-16 周五

🔥 TOP 10 最强品种
────────────────────────────────
① 159949.SZ  创业板50ETF [0.833]
   宽基指数 · 配置 11.5%
② 159937.SZ  黄金ETF [0.829]
   商品 · 配置 11.5%
③ 515030.SH  新能源车ETF [0.729]
   行业主题 · 配置 10.1%
④ 159915.SZ  创业板ETF [0.720]
   宽基指数 · 配置 9.9%
⑤ 159790.SZ  碳中和ETF [0.671]
   行业主题 · 配置 9.3%
⑥ 515050.SH  5GETF [0.660]
   行业主题 · 配置 9.1%
⑦ 159870.SZ  化工ETF [0.660]
   行业主题 · 配置 9.1%
⑧ 159985.SZ  豆粕ETF [0.658]
   商品 · 配置 9.1%
⑨ 159399.SZ  现金流ETF [0.634]
   策略风格 · 配置 8.8%
⑩ 512480.SH  半导体ETF [0.628]
   行业主题 · 配置 8.7%

🧊 BOTTOM 10 最弱品种
────────────────────────────────
① 512010.SH  医药ETF     0.383  行业主题
② 159920.SZ  恒生ETF     0.377  跨境
③ 159865.SZ  养殖ETF     0.363  行业主题
④ 159928.SZ  消费ETF     0.334  行业主题
⑤ 512880.SH  证券ETF     0.329  行业主题
⑥ 513180.SH  恒生科技ETF 0.315  跨境
⑦ 513500.SH  标普500ETF  0.285  跨境
⑧ 510050.SH  上证50ETF   0.272  宽基指数
⑨ 515060.SH  房地产ETF   0.246  行业主题
⑩ 516160.SH  新能源ETF   0.183  行业主题

📋 Top 10 配置方案 (总仓位上限 97%)
────────────────────────────────
159949.SZ  创业板50ETF   11.5%
159937.SZ  黄金ETF       11.5%
515030.SH  新能源车ETF   10.1%
159915.SZ  创业板ETF      9.9%
159790.SZ  碳中和ETF      9.3%
515050.SH  5GETF         9.1%
159870.SZ  化工ETF       9.1%
159985.SZ  豆粕ETF       9.1%
159399.SZ  现金流ETF      8.8%
512480.SH  半导体ETF      8.7%
合计: 97.0%

💡 操作建议
────────────────────────────────
▶ 牛市环境,仓位上限 97%,积极参与强势板块
▶ 关注: 创业板50ETF(159949) 新能源车ETF(515030) 碳中和ETF(159790)
▶ 回避: 证券ETF(512880) 房地产ETF(515060) 新能源ETF(516160)
▶ 下次调仓: 05-16 周五
════════════════════════════════════════

Step 5: Server酱端线测试(仅限本地验证)

验证清单:

▶ 📜 变更历史(1 次提交)

925d51b2026-05-29 01:04feat: 数据抓取报错复盘;守护进程推送数据;skill保存
🍃quant 知识库
by 伊甸园和枫

🔊 播放设置

勾选音源后调节配比,总和自动归一化
已选 0 个 · 合计:0%
合成中...
00:00/00:00
1.0x

分享图片

生成中...