Skill: spyfree/us-value-investing-framework (version 1.1.0)

--- name: us-value-investing-framework description: US stock valuation model skill (English-first + 中文) based on financial report data. Use when you need to apply explicit rules: ROE > 15% for 3+ years, debt ratio < 50%, free cash flow > 80% of net income, moat assessment (brand/network effect/cost advantage), then output investment rating (A/B/C/D) with reasons. --- # US Stock Valuation Model - Value Investing Framework (EN + 中文) This skill is an explicit rule-based value model focused on US stocks. ## Input Company financial report data (structured JSON), including: - 3+ years of ROE - Debt ratio - Free cash flow and net income - Moat assessment: brand / network effect / cost advantage Use the bundled template: `references/input-template.json`. ## Decision Rules (strict) 1. **ROE rule**: ROE > 15% for at least 3 consecutive years 2. **Leverage rule**: Debt ratio < 50% 3. **Cash conversion rule**: Free cash flow > 80% of net income 4. **Moat rule**: evaluate brand/network effect/cost advantage ## Output - Investment rating: **A / B / C / D** - Reasons (pass/fail explanation per rule) - Bilingual summary (EN main + 中文摘要) ## Run ```bash python3 scripts/evaluate_company.py \ --input references/input-template.json \ --out .state/eval.json \ --markdown .state/eval.md ``` ## Rating policy - **A**: all 4 rules pass - **B**: 3 rules pass - **C**: 2 rules pass - **D**: 0-1 rule pass ## Resources - `scripts/evaluate_company.py`: deterministic evaluator - `references/input-template.json`: input schema example

path: references/framework-guide.md
content: # US Value Investing Framework — Extended Guide

## 1) Thesis architecture

Use a 5-line thesis:
1. Business quality
2. Durable advantage (moat)
3. Valuation gap
4. Re-rating trigger
5. Main invalidation condition

## 2) Data fields (minimum)

- Revenue CAGR (3Y)
- FCF CAGR (3Y)
- ROIC
- Gross margin
- FCF margin
- Net debt / EBITDA
- PE (NTM or TTM)
- EV/EBIT
- FCF yield
- Optional fair value estimate

## 3) Expanded qualitative checks

### Moat scoring (0-10)
- Switching costs
- Network effects
- Brand/IP
- Cost advantage
- Distribution lock-in

### Management scoring (0-10)
- Capital allocation discipline
- Buyback/dividend quality
- Guidance credibility
- Incentive alignment

## 4) Valuation logic

Use multiple lenses instead of a single ratio:
- Relative: PE/EV-EBIT vs own history
- Cash lens: FCF yield vs rates and peers
- Scenario lens: base/bull/bear valuation range

## 5) Decision policy

- Buy: score >=75 and no red-line risk
- Watch: score 60-74 or valuation not attractive enough
- Avoid: score <60 or red-line risk present

## 6) Position sizing hints

- High conviction: 4-8%
- Medium conviction: 2-4%
- Tracking: 0.5-2%

Never override risk budget because of narrative excitement.

## 7) Output template (English-first + Chinese summary)

### EN
- Thesis
- Score breakdown
- Risks
- Action and trigger levels

### 中文结论（摘要）
- 一句话结论
- 关键分数与估值区间
- 触发买入/减仓条件


path: references/input-template.json
content: {
  "symbol": "AAPL",
  "company_name": "Apple Inc.",
  "as_of": "2026-02-22",
  "financials": [
    {
      "year": 2023,
      "roe": 0.56,
      "debt_ratio": 0.31,
      "free_cash_flow": 99584000000,
      "net_income": 96995000000
    },
    {
      "year": 2024,
      "roe": 0.52,
      "debt_ratio": 0.33,
      "free_cash_flow": 102600000000,
      "net_income": 100900000000
    },
    {
      "year": 2025,
      "roe": 0.49,
      "debt_ratio": 0.35,
      "free_cash_flow": 104300000000,
      "net_income": 103200000000
    }
  ],
  "moat": {
    "brand_0_10": 9,
    "network_effect_0_10": 7,
    "cost_advantage_0_10": 6
  }
}


path: scripts/evaluate_company.py
content: #!/usr/bin/env python3
import argparse
import json
from pathlib import Path


def consecutive_roe_pass(financials, threshold=0.15, need_years=3):
    # assume already sorted by year ascending
    streak = 0
    best = 0
    for row in financials:
        if row.get("roe", 0) > threshold:
            streak += 1
            best = max(best, streak)
        else:
            streak = 0
    return best >= need_years, best


def debt_ratio_pass(financials, threshold=0.50):
    latest = financials[-1]
    v = latest.get("debt_ratio", 1)
    return v < threshold, v


def fcf_to_ni_pass(financials, threshold=0.80):
    latest = financials[-1]
    ni = latest.get("net_income", 0)
    fcf = latest.get("free_cash_flow", 0)
    ratio = 0 if ni == 0 else fcf / ni
    return ratio > threshold, ratio


def moat_pass(moat):
    b = moat.get("brand_0_10", 0)
    n = moat.get("network_effect_0_10", 0)
    c = moat.get("cost_advantage_0_10", 0)
    strong_count = sum(1 for x in [b, n, c] if x >= 7)
    avg = (b + n + c) / 3
    passed = strong_count >= 2 or avg >= 7
    return passed, {"brand": b, "network_effect": n, "cost_advantage": c, "strong_dimensions": strong_count, "avg": round(avg, 2)}


def to_rating(pass_count):
    if pass_count == 4:
        return "A"
    if pass_count == 3:
        return "B"
    if pass_count == 2:
        return "C"
    return "D"


def evaluate(payload):
    fin = sorted(payload.get("financials", []), key=lambda x: x.get("year", 0))
    if len(fin) < 3:
        raise ValueError("Need at least 3 years of financial data")

    r1, streak = consecutive_roe_pass(fin)
    r2, debt = debt_ratio_pass(fin)
    r3, ratio = fcf_to_ni_pass(fin)
    r4, moat_detail = moat_pass(payload.get("moat", {}))

    checks = [r1, r2, r3, r4]
    pass_count = sum(1 for x in checks if x)
    rating = to_rating(pass_count)

    reasons = [
        f"ROE > 15% for 3+ years: {'PASS' if r1 else 'FAIL'} (best streak={streak})",
        f"Debt ratio < 50%: {'PASS' if r2 else 'FAIL'} (latest={debt:.2%})",
        f"FCF > 80% of Net Income: {'PASS' if r3 else 'FAIL'} (latest ratio={ratio:.2f})",
        f"Moat (brand/network effect/cost advantage): {'PASS' if r4 else 'FAIL'} (detail={moat_detail})",
    ]

    cn_reasons = [
        f"ROE连续3年以上大于15%：{'通过' if r1 else '未通过'}（最长连续={streak}年）",
        f"负债率低于50%：{'通过' if r2 else '未通过'}（最新={debt:.2%}）",
        f"自由现金流>净利润80%：{'通过' if r3 else '未通过'}（最新比值={ratio:.2f}）",
        f"护城河（品牌/网络效应/成本优势）：{'通过' if r4 else '未通过'}",
    ]

    return {
        "symbol": payload.get("symbol"),
        "company_name": payload.get("company_name"),
        "as_of": payload.get("as_of"),
        "rating": rating,
        "pass_count": pass_count,
        "reasons_en": reasons,
        "reasons_zh": cn_reasons,
        "rule_results": {
            "roe_3y_gt_15pct": r1,
            "debt_ratio_lt_50pct": r2,
            "fcf_gt_80pct_net_income": r3,
            "moat_pass": r4,
        },
    }


def to_markdown(res):
    en = "\n".join([f"- {x}" for x in res["reasons_en"]])
    zh = "\n".join([f"- {x}" for x in res["reasons_zh"]])
    return f"""# {res.get('symbol','N/A')} US Stock Valuation Result

## English Result
- Investment Rating: **{res['rating']}**
- Passed Rules: **{res['pass_count']} / 4**

### Reasons
{en}

## 中文结论（摘要）
- 投资评级：**{res['rating']}**
- 通过规则：**{res['pass_count']} / 4**

### 理由
{zh}
"""


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--input", required=True)
    ap.add_argument("--out", required=True)
    ap.add_argument("--markdown")
    args = ap.parse_args()

    payload = json.loads(Path(args.input).read_text(encoding="utf-8"))
    res = evaluate(payload)

    out = Path(args.out)
    out.parent.mkdir(parents=True, exist_ok=True)
    out.write_text(json.dumps(res, ensure_ascii=False, indent=2), encoding="utf-8")

    if args.markdown:
        md = Path(args.markdown)
        md.parent.mkdir(parents=True, exist_ok=True)
        md.write_text(to_markdown(res), encoding="utf-8")

    print(f"{res['symbol']} => rating {res['rating']} ({res['pass_count']}/4)")


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)