Skip to content
161 changes: 129 additions & 32 deletions .claude/skills/haoinvest/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,134 @@ user_invocable: true

# /haoinvest — Investment Management

All-in-one investment management via CLI. Run commands with `uv run haoinvest <group> <command>`.

## Market Type Auto-Detection

The CLI auto-detects market type from symbol format:
- **6-digit number** (600519, 000001) → A-share
- **Contains `_USDT`** or known crypto (BTC, ETH, SOL) → Crypto
- **Otherwise** → US market
- Override with `--market-type a_share|crypto|us`
All-in-one investment management via CLI + Claude Code agent. CLI does data + computation; you (the agent) do interpretation + recommendations.

## Agent Workflows

### Workflow 1: "帮我分析 XXX" — Analyze a stock

1. Run comprehensive report:
```bash
uv run haoinvest analyze report <symbol>
```
2. For A-shares, also run peer comparison:
```bash
uv run haoinvest analyze peer <symbol>
```
3. Interpret ALL sections in Chinese:
- 估值: Is it cheap or expensive? Compare PE/PB to peers.
- 财务健康: Is the company profitable and growing?
- 风险: How volatile is it? What's the worst drawdown?
- 技术面: What's the current trend?
- Checklist: What's the buy-readiness score?
4. Point out weak areas and suggest what else to check
5. If data is missing (e.g., financial health = N/A), say so honestly

### Workflow 2: "我有闲钱想投资" — Investment direction

1. Check current portfolio:
```bash
uv run haoinvest portfolio list
```
2. Identify concentration: which sectors are overweight?
3. Scan sector rankings:
```bash
uv run haoinvest market sector-list
```
4. Drill into promising sectors:
```bash
uv run haoinvest market sector <板块名>
```
5. Run reports on 2-3 candidates from underrepresented sectors
6. Explain WHY each candidate diversifies the portfolio

### Workflow 3: "我想买 XXX" — Buy decision

1. Run comprehensive report with checklist:
```bash
uv run haoinvest analyze report <symbol>
```
2. Explain the buy-readiness score dimension by dimension
3. If score is low, explain which dimensions are concerning
4. Compare with peers:
```bash
uv run haoinvest analyze peer <symbol>
```
5. Always remind: **这不是投资建议,最终决定需要你自己判断**

### Workflow 4: "对比 A 和 B" — Compare stocks

1. Batch fundamental comparison:
```bash
uv run haoinvest analyze fundamental <A>,<B> --verbose
```
2. Batch technical comparison:
```bash
uv run haoinvest analyze technical <A>,<B>
```
3. Summarize: who's better on what dimension, and overall recommendation

### Workflow 5: "定期体检" — Portfolio checkup

1. Portfolio holdings + P&L:
```bash
uv run haoinvest portfolio list
uv run haoinvest portfolio returns
```
2. Risk assessment:
```bash
uv run haoinvest analyze risk
```
3. For each holding with poor risk metrics, run a quick report
4. Check allocation via:
```bash
uv run haoinvest strategy optimize
```
5. Suggest rebalancing if needed

### Workflow 6: "情绪复盘" — Decision review

1. Review journal patterns:
```bash
uv run haoinvest journal review --days 30
```
2. Analyze: which emotions led to good/bad decisions?
3. For entries needing retrospective, help add reflections
4. Gently suggest behavioral improvements

## Command Reference

### Market Data
```bash
uv run haoinvest market quote <symbol> # Price + basic info
uv run haoinvest market history <symbol> [--start] [--end] # OHLCV bars (default: 30 days)
uv run haoinvest market quote <symbol(s)> # Price + info (batch: comma-separated)
uv run haoinvest market history <symbol> [--start] [--end] # OHLCV bars (30 days default)
uv run haoinvest market sector-list # A-share industry board ranking
uv run haoinvest market sector <name> # Sector constituents
```

### Portfolio
### Analysis
```bash
uv run haoinvest portfolio list # All holdings
uv run haoinvest portfolio add-trade <symbol> <action> <qty> <price> [--fee] [--tax] [--date] [--note]
uv run haoinvest portfolio returns [--symbol <sym>] # P&L (all or single)
uv run haoinvest analyze report <symbol> # Full report + buy-readiness checklist
uv run haoinvest analyze fundamental <symbol(s)> [--verbose] # Valuation + financial health (batch OK)
uv run haoinvest analyze technical <symbol(s)> # MA/MACD/RSI/BB (batch OK)
uv run haoinvest analyze peer <symbol> # Same-sector peer comparison (A-shares)
uv run haoinvest analyze risk [--symbol <sym>] # Volatility, Sharpe, drawdown
uv run haoinvest analyze correlation <sym1,sym2,...> # Correlation matrix
uv run haoinvest analyze volume <symbol> # Volume anomaly detection
uv run haoinvest analyze signals <symbol> # Aggregated technical signal
```
Actions: `buy`, `sell`, `dividend`, `split`, `transfer_in`, `transfer_out`

### Analysis
### Portfolio
```bash
uv run haoinvest analyze fundamental <symbol> # PE/PB + valuation assessment
uv run haoinvest analyze risk [--symbol <sym>] [--start] [--end] # Volatility, Sharpe, drawdown
uv run haoinvest analyze correlation <sym1,sym2,...> # Correlation matrix
uv run haoinvest portfolio list # All holdings
uv run haoinvest portfolio add-trade <symbol> <action> <qty> <price> [--fee] [--tax] [--date] [--note]
uv run haoinvest portfolio returns [--symbol <sym>] # P&L
```
Actions: `buy`, `sell`, `dividend`, `split`, `transfer_in`, `transfer_out`

### Strategy
```bash
uv run haoinvest strategy optimize [--method equal_weight|risk_parity|min_volatility|max_sharpe] [--symbols <syms>]
uv run haoinvest strategy optimize [--method equal_weight|risk_parity|min_volatility|max_sharpe]
uv run haoinvest strategy rebalance --target '{"600519": 0.5, "BTC_USDT": 0.5}'
```

Expand All @@ -52,33 +144,38 @@ uv run haoinvest journal list [--symbol <sym>] [--limit <n>]
uv run haoinvest journal review [--entry-id <id>] [--days <n>]
```

## Global Options
## Market Type Auto-Detection

All commands support `--json` flag for structured JSON output.
- **6-digit number** (600519, 000001) → A-share
- **Contains `_USDT`** or known crypto (BTC, ETH, SOL) → Crypto
- **Otherwise** → US market
- Override with `--market-type a_share|crypto|us`

## Output Format

- Default: **Key-Value** text (single records) or **TSV** (tables/lists)
- Default: **Key-Value** (single records) or **TSV** (tables)
- `--json`: Full JSON output
- **Prefer TSV (default) over `--json` for list commands** (`portfolio list`, `journal list`, `market history`, `strategy rebalance`). TSV is more compact and easier for LLMs to parse. Use `--json` only when you need nested data or programmatic processing.
- You (Claude) should interpret the data and respond in **Chinese**, explaining concepts in beginner-friendly terms
- **Prefer TSV for list commands** more compact for LLM parsing
- All commands support `--json`

## Crypto Special Handling

For crypto prices, **prefer Crypto.com MCP tools** when available:
- `mcp__claude_ai_Crypto_com__get_ticker` — single ticker
- `mcp__claude_ai_Crypto_com__get_tickers` — multiple tickers
- `mcp__claude_ai_Crypto_com__get_ticker` / `get_tickers`

Fall back to CLI `haoinvest market quote BTC_USDT` if MCP is unavailable.
Fall back to CLI if MCP is unavailable.

## Sandbox Mode
## Teaching Mode

For analyzing someone else's stocks (not your portfolio), just use `haoinvest analyze` or `haoinvest market` commands — they don't touch portfolio data. Set `HAOINVEST_DATA_DIR=/tmp/haoinvest_sandbox` if you need a temp database for trades.
When explaining metrics, always:
- Include "这意味着..." explanations for beginners
- Use analogies (e.g., "PE就像买房时的租售比,越低说明回本越快")
- Start with overall assessment, then detail on request
- Progressive disclosure: don't overwhelm with all metrics at once

## Response Guidelines

- Always respond in **Chinese**
- Explain what each metric means for beginners (e.g., "PE 20 意味着...")
- Show appropriate precision: A-shares 2 decimals, crypto 8 decimals
- For journal entries, gently ask about emotion and decision type if not specified
- For strategy recommendations, explain WHY each approach is suggested
Expand Down
150 changes: 149 additions & 1 deletion haoinvest/analysis/fundamental.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
"""Fundamental analysis: PE/PB/ROE and valuation assessment."""

from ..market import get_provider
from ..models import FundamentalAnalysis, MarketType, ValuationAssessment
from ..models import (
BasicInfo,
FinancialHealthAssessment,
FundamentalAnalysis,
MarketType,
ValuationAssessment,
)


def analyze_stock(symbol: str, market_type: MarketType) -> FundamentalAnalysis:
Expand All @@ -15,18 +21,32 @@ def analyze_stock(symbol: str, market_type: MarketType) -> FundamentalAnalysis:
pb = _safe_float(info.pb_ratio)

valuation = _assess_valuation(pe, pb, market_type)
financial_health = _assess_financial_health(info)

return FundamentalAnalysis(
symbol=symbol,
name=info.name,
sector=info.sector,
industry=info.industry,
market_type=market_type.value,
current_price=price,
currency=info.currency,
pe_ratio=pe,
pb_ratio=pb,
total_market_cap=info.total_market_cap,
valuation=valuation,
roe=info.roe,
roa=info.roa,
debt_to_equity=info.debt_to_equity,
revenue_growth=info.revenue_growth,
profit_margin=info.profit_margin,
gross_margin=info.gross_margin,
operating_margin=info.operating_margin,
current_ratio=info.current_ratio,
free_cash_flow=info.free_cash_flow,
operating_cash_flow=info.operating_cash_flow,
peg_ratio=info.peg_ratio,
financial_health=financial_health,
)


Expand Down Expand Up @@ -101,6 +121,134 @@ def _assess_valuation(
)


def _assess_financial_health(info: BasicInfo) -> FinancialHealthAssessment:
"""Multi-dimensional financial health assessment with Chinese labels."""
profitability = _assess_profitability(info.roe, info.profit_margin)
growth = _assess_growth(info.revenue_growth)
leverage = _assess_leverage(info.debt_to_equity, info.current_ratio)
cash_flow = _assess_cash_flow(info.free_cash_flow, info.operating_cash_flow)

# Overall: count how many dimensions are positive
assessments = [profitability, growth, leverage, cash_flow]
known = [a for a in assessments if a != "N/A"]
if not known:
overall = "无法评估"
else:
positive_keywords = (
"优秀",
"良好",
"高速增长",
"稳定增长",
"保守",
"适中",
"充裕",
"正常",
)
positive = sum(1 for a in known if any(k in a for k in positive_keywords))
ratio = positive / len(known)
if ratio >= 0.75:
overall = "财务健康"
elif ratio >= 0.5:
overall = "财务一般"
elif ratio >= 0.25:
overall = "财务偏弱"
else:
overall = "财务风险较高"

return FinancialHealthAssessment(
profitability=profitability,
growth=growth,
leverage=leverage,
cash_flow=cash_flow,
overall=overall,
)


def _assess_profitability(roe: float | None, profit_margin: float | None) -> str:
"""Assess profitability based on ROE and net profit margin."""
if roe is None and profit_margin is None:
return "N/A"
# ROE is the primary indicator
if roe is not None:
if roe > 15:
return f"优秀 (ROE {roe:.1f}%)"
elif roe > 10:
return f"良好 (ROE {roe:.1f}%)"
elif roe > 5:
return f"一般 (ROE {roe:.1f}%)"
else:
return f"偏弱 (ROE {roe:.1f}%)"
# Fallback to profit margin
if profit_margin is not None:
if profit_margin > 20:
return f"优秀 (净利率 {profit_margin:.1f}%)"
elif profit_margin > 10:
return f"良好 (净利率 {profit_margin:.1f}%)"
elif profit_margin > 5:
return f"一般 (净利率 {profit_margin:.1f}%)"
else:
return f"偏弱 (净利率 {profit_margin:.1f}%)"
return "N/A"


def _assess_growth(revenue_growth: float | None) -> str:
"""Assess growth based on YoY revenue growth (percentage, e.g. 15.0 = 15%)."""
if revenue_growth is None:
return "N/A"
g = revenue_growth
if g > 20:
return f"高速增长 ({g:.1f}%)"
elif g > 10:
return f"稳定增长 ({g:.1f}%)"
elif g > 0:
return f"低增长 ({g:.1f}%)"
else:
return f"负增长 ({g:.1f}%)"


def _assess_leverage(debt_to_equity: float | None, current_ratio: float | None) -> str:
"""Assess leverage based on debt-to-equity and current ratio."""
if debt_to_equity is None and current_ratio is None:
return "N/A"
parts = []
if debt_to_equity is not None:
if debt_to_equity < 50:
parts.append(f"保守 (D/E {debt_to_equity:.0f}%)")
elif debt_to_equity < 100:
parts.append(f"适中 (D/E {debt_to_equity:.0f}%)")
elif debt_to_equity < 200:
parts.append(f"偏高 (D/E {debt_to_equity:.0f}%)")
else:
parts.append(f"高杠杆 (D/E {debt_to_equity:.0f}%)")
if current_ratio is not None:
if current_ratio >= 2:
parts.append(f"流动性充足 (CR {current_ratio:.1f})")
elif current_ratio >= 1:
parts.append(f"流动性正常 (CR {current_ratio:.1f})")
else:
parts.append(f"流动性紧张 (CR {current_ratio:.1f})")
return "; ".join(parts) if parts else "N/A"


def _assess_cash_flow(
free_cash_flow: float | None, operating_cash_flow: float | None
) -> str:
"""Assess cash flow health."""
if free_cash_flow is None and operating_cash_flow is None:
return "N/A"
if free_cash_flow is not None:
if free_cash_flow > 0:
return "充裕 (自由现金流为正)"
else:
return "紧张 (自由现金流为负)"
if operating_cash_flow is not None:
if operating_cash_flow > 0:
return "正常 (经营现金流为正)"
else:
return "紧张 (经营现金流为负)"
return "N/A"


def _safe_float(val) -> float | None:
"""Convert a value to float, returning None if not possible."""
if val is None or val == "":
Expand Down
Loading
Loading