Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Python library + Claude Code skills for tracking portfolios, analyzing stocks, a
- **Language**: Python 3.11+
- **Package Manager**: uv (NOT pip)
- **Database**: SQLite (~/.haoinvest/haoinvest.db)
- **Data Sources**: AKShare (A-shares), yfinance (US/HK), Crypto.com MCP (crypto)
- **Data Sources**: Sina/Tencent/eastmoney direct APIs (A-shares), yfinance (US/HK), Crypto.com MCP (crypto)
- **Testing**: pytest

## Quick Commands
Expand Down Expand Up @@ -55,7 +55,7 @@ haoinvest/
│ ├── report.py # Full stock report with buy-readiness checklist
│ ├── signals.py # Aggregate buy/sell signals
│ └── volume.py # Volume analysis
├── market/ # Provider registry — akshare, yfinance, crypto MCP
├── market/ # Provider registry — A-share (Sina/Tencent/eastmoney), yfinance, crypto MCP
└── strategy/ # Optimizer adapter + rebalance logic
```

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Built for a beginner investor in China covering A-shares, US stocks, HK stocks,
## Features

- **Portfolio Management** — Record trades, track positions, calculate time-weighted returns (TWR)
- **Market Data** — Real-time quotes from AKShare (A-shares), Yahoo Finance (US/HK), Crypto.com (crypto)
- **Market Data** — Real-time quotes from Sina/Tencent/eastmoney APIs (A-shares), Yahoo Finance (US/HK), Crypto.com (crypto)
- **Fundamental Analysis** — PE/PB/ROE valuation assessment with financial health scoring; batch support for multi-symbol comparison
- **Peer Comparison** — Find and compare same-sector stocks by valuation and performance
- **Sector Browsing** — Browse A-share industry sectors and their constituent stocks
Expand Down Expand Up @@ -108,7 +108,7 @@ Use the unified `/haoinvest` skill in Claude Code for natural language interacti
| Environment Variable | Default | Description |
|---------------------|---------|-------------|
| `HAOINVEST_DATA_DIR` | `~/.haoinvest/` | Data directory path |
| `HAOINVEST_AKSHARE_TIMEOUT` | `30` | AKShare API timeout (seconds) |
| `HAOINVEST_API_TIMEOUT` | `30` | A-share API timeout (seconds) |
| `HAOINVEST_CACHE_TTL` | `14400` | Analysis cache TTL (seconds) |
| `HAOINVEST_PRICE_CACHE_TTL` | `3600` | Price cache TTL (seconds) |

Expand All @@ -134,7 +134,7 @@ pytest tests/test_fx.py # Single module
│ pandas-ta · QuantStats · PyPfOpt │
├─────────────────────────────────────┤
│ Data (market/, portfolio/, db.py) │ ← Providers, positions, SQLite
AKShare · yfinance · Crypto.com
Sina/Tencent/EM · yfinance · Crypto│
└─────────────────────────────────────┘
```

Expand Down
6 changes: 3 additions & 3 deletions haoinvest/analysis/peer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def find_peers(
) -> list[dict]:
"""Find same-sector peers and compare fundamental metrics.

For A-shares: uses AKShareProvider.get_sector_constituents() to find
For A-shares: uses AShareProvider.get_sector_constituents() to find
stocks in the same industry board, sorted by market cap.

Returns list of dicts suitable for TSV output, with the target stock
Expand All @@ -26,7 +26,7 @@ def find_peers(
{"message": f"Peer comparison not yet supported for {market_type.value}"}
]

from ..market.akshare_provider import AKShareProvider
from ..market.ashare_provider import AShareProvider

# Get target stock info to determine sector
target = analyze_stock(symbol, market_type)
Expand All @@ -36,7 +36,7 @@ def find_peers(

# Get sector constituents
try:
constituents = AKShareProvider.get_sector_constituents(sector)
constituents = AShareProvider.get_sector_constituents(sector)
except Exception as e:
logger.debug("Failed to get sector constituents for %s: %s", sector, e)
return [{"message": f"Failed to get sector data for {sector}: {e}"}]
Expand Down
8 changes: 4 additions & 4 deletions haoinvest/cli/market.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,10 @@ def sector_list(
use_json: bool = typer.Option(False, "--json", help="Output as JSON"),
) -> None:
"""行业板块排行 — list all A-share industry sectors with performance."""
from ..market.akshare_provider import AKShareProvider
from ..market.ashare_provider import AShareProvider

try:
rows = AKShareProvider.get_sector_list()
rows = AShareProvider.get_sector_list()
except Exception as e:
error_output(str(e))
raise typer.Exit(1)
Expand All @@ -169,10 +169,10 @@ def sector(
use_json: bool = typer.Option(False, "--json", help="Output as JSON"),
) -> None:
"""行业板块成分股 — show constituents of a specific A-share sector."""
from ..market.akshare_provider import AKShareProvider
from ..market.ashare_provider import AShareProvider

try:
rows = AKShareProvider.get_sector_constituents(name)
rows = AShareProvider.get_sector_constituents(name)
except Exception as e:
error_output(str(e))
raise typer.Exit(1)
Expand Down
5 changes: 2 additions & 3 deletions haoinvest/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ def get_db_path() -> Path:
return get_data_dir() / "haoinvest.db"


# AKShare has unstable APIs — pin version in pyproject.toml
# and handle errors gracefully in providers.
AKSHARE_TIMEOUT = int(os.environ.get("HAOINVEST_AKSHARE_TIMEOUT", "30"))
# API timeout for A-share data sources (Sina/Tencent/eastmoney)
API_TIMEOUT = int(os.environ.get("HAOINVEST_API_TIMEOUT", "30"))

# Cache expiry in seconds
ANALYSIS_CACHE_TTL = int(
Expand Down
4 changes: 2 additions & 2 deletions haoinvest/market/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ def get_provider(market_type: MarketType) -> MarketProvider:
def _auto_register() -> None:
"""Register built-in providers."""
try:
from .akshare_provider import AKShareProvider
from .ashare_provider import AShareProvider

register_provider(MarketType.A_SHARE, AKShareProvider)
register_provider(MarketType.A_SHARE, AShareProvider)
except ImportError:
pass

Expand Down
Loading
Loading