Files
Hermes-Skills/dividend-investing/references/dividend-stability-score.md
T
mike b660debd06 v2026-07-21: 实战教训汇总 (push 11 文件)
新增 8 reference:
  - dividend-stability-score: A 股 5 维评分 (派息年数/CAGR/波动/最近/连续) → 0-100 分 + 5 星
  - dividend-yield-rate-sort: 按股息率% 倒序 (用户偏好 2026-07-13)
  - longport-http-module: longport_http.py 公共模块 (替代 SDK WSS)
  - leverage-pass-through-bug: process_signal.py 丢失 leverage 字段 (5x 实际 10x)
  - follow-trading-iron-laws: 跟单铁律 (用户原话 5+ 次 2026-07-21)
  - forced-skill-entry-okx-trade: okx_trade.sh 强制入口 (替代 ccxt 裸调)
  - mihomo-clash-node-supplier-dns: Clash 节点供应商 DNS 失败处理
  - mihomo-ssl-reconnect-pattern: mihomo 反复 SSL/Timeout 模式
  - v4.5.44-mu-add-to-75pct-cap: MU 加仓 75% 单币种 cap 标准流程

改 2 SKILL.md:
  - dividend-investing: 加 5 维评分 + 长桥 http 模块
  - longbridge-cli: 标注 '不要写 openapi.QuoteContext' + 迁移说明
2026-07-22 13:22:45 +08:00

5.6 KiB
Raw Blame History

name, description, version, type
name description version type
dividend-stability-score 5 维综合分红稳定性评分 0-100 (派息年数/CAGR/波动/最近/连续) + 5 星等级. 用于 A 股 — 港美股可扩展 (占位) 1.0.0 reference

分红稳定性评分 (Stability Score)

用户原话 (2026-07-22): 推送要加分红稳定性,综合评分。

设计 (5 维, 100 分总分)

维度 分值 说明
派息年数 30 派过 15 年满分
派息 CAGR 20 最新/最早比, 复合年增长 ≥10% 满分
波动率(CV) 25 派息标准差/均值, ≤0.2 满分
最近 ≥ 上次 15 latest_div >= prev_div
连续性 10 最近 3 年都派

等级 (0-100 → 1-5 星)

分数 等级 标签
80-100 5★ 长期稳定
60-79 4★ 基本稳定
40-59 3★ 不稳定
20-39 2★ 风险大
0-19 1★ 不推荐

实现 (dividend_alert.py 已部署)

def score_dividend_stability(symbol: str, market: str) -> dict:
    """返回: {"score": 75, "level": 4, "label": "基本稳定", "years": 10, "cagr": 5.2, "cv": 0.3, "latest_div": 3.5}"""
    try:
        if market != "CN":
            return None  # 暂时只 A 股 (akshare)

        import akshare as ak
        code = symbol.replace(".SH", "").replace(".SZ", "").replace(".BJ", "")
        df = ak.stock_history_dividend_detail(symbol=code, indicator="分红")
        if df is None or len(df) < 3:
            return None

        df = df[df["进度"] == "实施"].copy()
        df["派息"] = pd.to_numeric(df["派息"], errors="coerce")
        df = df.dropna(subset=["派息"])
        df = df[df["派息"] > 0]
        if len(df) < 3:
            return None

        df["年份"] = pd.to_datetime(df["公告日期"]).dt.year
        df = df.sort_values("年份", ascending=False).reset_index(drop=True)
        years_count = df["年份"].nunique()
        latest_div = df["派息"].iloc[0]
        oldest_div = df["派息"].iloc[-1]

        years_score = min(30, years_count * 2)  # 15 年满分

        if years_count >= 2 and oldest_div > 0:
            cagr = (latest_div / oldest_div) ** (1 / (years_count - 1)) - 1
            if cagr >= 0.10: cagr_score = 20
            elif cagr >= 0.05: cagr_score = 15
            elif cagr >= 0.02: cagr_score = 10
            elif cagr >= 0: cagr_score = 5
            else: cagr_score = 0
        else:
            cagr = 0
            cagr_score = 0

        if len(df) >= 3:
            mean_div = df["派息"].mean()
            std_div = df["派息"].std()
            cv = std_div / mean_div if mean_div > 0 else 1
            if cv <= 0.2: vol_score = 25
            elif cv <= 0.4: vol_score = 20
            elif cv <= 0.6: vol_score = 15
            elif cv <= 0.8: vol_score = 10
            else: vol_score = 5
        else:
            cv = 1
            vol_score = 5

        recent_score = 15 if (len(df) >= 2 and df["派息"].iloc[0] >= df["派息"].iloc[1]) else 5
        consecutive_score = 10 if (years_count >= 3 and len(df["年份"].head(3).unique()) >= 3) else 0

        total = years_score + cagr_score + vol_score + recent_score + consecutive_score
        if total >= 80: level, label = 5, "长期稳定"
        elif total >= 60: level, label = 4, "基本稳定"
        elif total >= 40: level, label = 3, "不稳定"
        elif total >= 20: level, label = 2, "风险大"
        else: level, label = 1, "不推荐"

        return {"score": total, "level": level, "label": label, "years": years_count, "cagr": cagr * 100, "cv": cv, "latest_div": latest_div}
    except Exception as e:
        print(f"  [WARN] score_dividend_stability {symbol} failed: {e}", file=sys.stderr)
        return None

推送格式

集成到 dividend_alert.py fmt():

600033 福建高速 [3★不稳定 25年CAGR-2%]
    💰每10股派0.71元 | 📊3.53 | 股息率 2.01%

格式: [<level>★<label> <years>年CAGR<cagr:+int>%] 在股票名后, 派息行前。

缓存 (避免重复 akshare 调用)

_stability_cache = {}

def score_dividend_stability(symbol, market):
    cache_key = f"{market}:{symbol}"
    if cache_key in _stability_cache:
        return _stability_cache[cache_key]
    ...
    _stability_cache[cache_key] = result
    return result

为什么:dividend_alert.py 跑 1 次 12 只 A 股, 每次 23 秒。AKShare 历史派息 API 1 只 1-2 秒。12 只 × 1.5s = 18 秒纯 akshare 调用。用 cache 减少到 0 (单次 cron 内重复)。

限制

  • A 股只(akshare 历史数据完整, HK/US 缺)
  • 要 ≥ 3 年派息 才评分 (样本不足跳过, 显示没标签)
  • CAGR 受疫情/异常影响大(2020+ 多数公司派息都降, CAGR 全负)。以后经济恢复, 这部分会变好

实际效果 (2026-07-22 测试)

股票 分数 等级 年数 CAGR
河钢股份 4★ 基本稳定 22年 -12%
福建高速 3★ 不稳定 25年 -2%
南玻 A 3★ 不稳定 31年 -4%

注意:CAGR 全负是因为疫情后多数公司派息下降——4★ 河钢 22 年 CAGR -12% 还是"基本稳定", 当前阈值偏松。等经济恢复后再调严。

调参选项

如果觉得阈值不对:

  • 调严 改分数区间(比如 total >= 90 → 5★)
  • 调 CAGR 权重cagr >= 0.10 等条件
  • 加新维度: 派息比率(payout ratio)= 派息/净利润, 现金流覆盖 = 经营现金流/派息

如果要扩到港美股, 需要单独 API:

  • 港股: AKShare 没历史, 用 ccxtyfinance 替代
  • 美股: yfinance.dividends 列 (但只含过去 5 年)