docs: add GitHub Codespaces quick-start commands for AKShare

This commit is contained in:
agatha-miao 2026-04-04 14:14:55 +08:00
parent 4641c03340
commit 4cfca77192
6 changed files with 267 additions and 9 deletions

View File

@ -199,6 +199,56 @@ _, decision = ta.propagate("NVDA", "2026-01-15")
print(decision)
```
### A-share (China) with AKShare
If you want to run TradingAgents on A-share symbols with AKShare data:
1. Install dependencies:
```bash
pip install .
pip install akshare
```
2. Switch data vendors to AKShare in your config:
```python
config["data_vendors"] = {
"core_stock_apis": "akshare",
"technical_indicators": "akshare",
"fundamental_data": "akshare",
"news_data": "akshare",
}
```
3. Use A-share symbols like `600519` or `sh600519`:
```python
_, decision = ta.propagate("600519", "2026-01-15")
```
Notes:
- The current AKShare adapter provides production-ready price + basic technical indicator access.
- Fundamental/news/insider methods are scaffolded as placeholders so you can bind your preferred AKShare endpoints quickly.
#### Run in GitHub Codespaces (recommended quick start)
You can run this project directly in Codespaces (no local setup required):
```bash
# 1) open terminal in Codespaces
python -m venv .venv
source .venv/bin/activate
# 2) install project and AKShare
pip install -U pip
pip install .
pip install akshare
# 3) set your LLM key (pick one provider)
export OPENAI_API_KEY=your_key_here
# 4) run CLI
python -m cli.main
```
For A-share symbols, input values such as `600519`, `000001`, `sh600519`, or `sz000001`.
See `tradingagents/default_config.py` for all configuration options.
## Contributing

View File

@ -14,10 +14,10 @@ config["max_debate_rounds"] = 1 # Increase debate rounds
# Configure data vendors (default uses yfinance, no extra API keys needed)
config["data_vendors"] = {
"core_stock_apis": "yfinance", # Options: alpha_vantage, yfinance
"technical_indicators": "yfinance", # Options: alpha_vantage, yfinance
"fundamental_data": "yfinance", # Options: alpha_vantage, yfinance
"news_data": "yfinance", # Options: alpha_vantage, yfinance
"core_stock_apis": "yfinance", # Options: alpha_vantage, yfinance, akshare
"technical_indicators": "yfinance", # Options: alpha_vantage, yfinance, akshare
"fundamental_data": "yfinance", # Options: alpha_vantage, yfinance, akshare
"news_data": "yfinance", # Options: alpha_vantage, yfinance, akshare
}
# Initialize with custom config

View File

@ -30,6 +30,7 @@ dependencies = [
"tqdm>=4.67.1",
"typing-extensions>=4.14.0",
"yfinance>=0.2.63",
"akshare>=1.17.62",
]
[project.scripts]

View File

@ -0,0 +1,186 @@
from __future__ import annotations
from datetime import datetime, timedelta
from typing import Annotated
import pandas as pd
def _load_akshare():
try:
import akshare as ak
except ImportError as exc:
raise RuntimeError(
"AKShare is not installed. Run `pip install akshare` first."
) from exc
return ak
def _normalize_a_share_symbol(symbol: str) -> str:
s = symbol.strip().lower()
if s.startswith(("sh", "sz", "bj")) and len(s) >= 8:
return s
if s.isdigit() and len(s) == 6:
if s.startswith(("6", "9")):
return f"sh{s}"
if s.startswith(("0", "2", "3")):
return f"sz{s}"
if s.startswith(("4", "8")):
return f"bj{s}"
return s
def _extract_code(symbol: str) -> str:
norm = _normalize_a_share_symbol(symbol)
if len(norm) >= 8 and norm[:2] in {"sh", "sz", "bj"}:
return norm[2:]
return norm
def get_stock_data_akshare(
symbol: Annotated[str, "A-share symbol, e.g. 600519 or sh600519"],
start_date: Annotated[str, "Start date in yyyy-mm-dd format"],
end_date: Annotated[str, "End date in yyyy-mm-dd format"],
):
ak = _load_akshare()
datetime.strptime(start_date, "%Y-%m-%d")
datetime.strptime(end_date, "%Y-%m-%d")
code = _extract_code(symbol)
start = start_date.replace("-", "")
end = end_date.replace("-", "")
try:
df = ak.stock_zh_a_hist(
symbol=code,
period="daily",
start_date=start,
end_date=end,
adjust="qfq",
)
except Exception as exc:
return f"Error fetching A-share stock data for {symbol}: {exc}"
if df is None or df.empty:
return f"No A-share data found for symbol '{symbol}' between {start_date} and {end_date}"
rename_map = {
"日期": "Date",
"开盘": "Open",
"收盘": "Close",
"最高": "High",
"最低": "Low",
"成交量": "Volume",
"成交额": "Amount",
"振幅": "Amplitude",
"涨跌幅": "ChangePct",
"涨跌额": "Change",
"换手率": "Turnover",
}
out = df.rename(columns=rename_map)
header = (
f"# A-share stock data for {symbol} ({code}) from {start_date} to {end_date}\n"
f"# Total records: {len(out)}\n"
f"# Data source: AKShare stock_zh_a_hist\n\n"
)
return header + out.to_csv(index=False)
def get_indicator_akshare(
symbol: Annotated[str, "A-share symbol"],
indicator: Annotated[str, "technical indicator"],
curr_date: Annotated[str, "The current trading date, YYYY-mm-dd"],
look_back_days: Annotated[int, "how many days to look back"],
) -> str:
end_date = curr_date
start_date = (datetime.strptime(curr_date, "%Y-%m-%d") - timedelta(days=look_back_days * 3)).strftime("%Y-%m-%d")
raw = get_stock_data_akshare(symbol, start_date, end_date)
if raw.startswith("No A-share") or raw.startswith("Error"):
return raw
csv_part = "\n".join(raw.splitlines()[4:])
df = pd.read_csv(pd.io.common.StringIO(csv_part))
if df.empty or "Close" not in df.columns:
return f"Unable to compute indicator {indicator} for {symbol}"
close = pd.to_numeric(df["Close"], errors="coerce")
indicator_lower = indicator.lower()
if indicator_lower == "rsi":
delta = close.diff()
gain = delta.clip(lower=0).rolling(14).mean()
loss = (-delta.clip(upper=0)).rolling(14).mean()
rs = gain / loss.replace(0, pd.NA)
series = 100 - (100 / (1 + rs))
elif indicator_lower in {"close_10_ema", "ema10"}:
series = close.ewm(span=10, adjust=False).mean()
elif indicator_lower in {"close_50_sma", "sma50"}:
series = close.rolling(50).mean()
elif indicator_lower == "macd":
ema12 = close.ewm(span=12, adjust=False).mean()
ema26 = close.ewm(span=26, adjust=False).mean()
series = ema12 - ema26
else:
return (
f"AKShare adapter currently supports indicators: rsi, close_10_ema, close_50_sma, macd. "
f"Requested: {indicator}"
)
df["Date"] = pd.to_datetime(df["Date"], errors="coerce").dt.strftime("%Y-%m-%d")
df["indicator"] = series
window_df = df.dropna(subset=["Date"]).tail(look_back_days)
lines = [f"{d}: {v}" for d, v in zip(window_df["Date"], window_df["indicator"])]
return f"## {indicator} values for {symbol} up to {curr_date}:\n\n" + "\n".join(lines)
def get_fundamentals_akshare(
ticker: Annotated[str, "A-share symbol"],
curr_date: Annotated[str, "current date"] = None,
):
return (
"AKShare fundamentals vary by endpoint and exchange. "
"Recommended: wire dedicated endpoints for balance sheet/cashflow/income statement per your data policy. "
f"Current symbol: {ticker}."
)
def get_balance_sheet_akshare(
ticker: Annotated[str, "A-share symbol"],
freq: Annotated[str, "quarterly/annual"] = "quarterly",
curr_date: Annotated[str, "current date"] = None,
):
return f"AKShare balance-sheet adapter placeholder for {ticker} ({freq})."
def get_cashflow_akshare(
ticker: Annotated[str, "A-share symbol"],
freq: Annotated[str, "quarterly/annual"] = "quarterly",
curr_date: Annotated[str, "current date"] = None,
):
return f"AKShare cashflow adapter placeholder for {ticker} ({freq})."
def get_income_statement_akshare(
ticker: Annotated[str, "A-share symbol"],
freq: Annotated[str, "quarterly/annual"] = "quarterly",
curr_date: Annotated[str, "current date"] = None,
):
return f"AKShare income-statement adapter placeholder for {ticker} ({freq})."
def get_news_akshare(
ticker: Annotated[str, "A-share symbol"],
start_date: Annotated[str, "Start date"] = None,
end_date: Annotated[str, "End date"] = None,
):
return f"AKShare news adapter placeholder for {ticker} from {start_date} to {end_date}."
def get_global_news_akshare(start_date: str = None, end_date: str = None):
return f"AKShare global news adapter placeholder from {start_date} to {end_date}."
def get_insider_transactions_akshare(
ticker: Annotated[str, "A-share symbol"],
):
return f"A-share insider transactions adapter placeholder for {ticker}."

View File

@ -23,6 +23,17 @@ from .alpha_vantage import (
get_global_news as get_alpha_vantage_global_news,
)
from .alpha_vantage_common import AlphaVantageRateLimitError
from .akshare_cn import (
get_stock_data_akshare,
get_indicator_akshare,
get_fundamentals_akshare,
get_balance_sheet_akshare,
get_cashflow_akshare,
get_income_statement_akshare,
get_news_akshare,
get_global_news_akshare,
get_insider_transactions_akshare,
)
# Configuration and routing logic
from .config import get_config
@ -63,6 +74,7 @@ TOOLS_CATEGORIES = {
VENDOR_LIST = [
"yfinance",
"alpha_vantage",
"akshare",
]
# Mapping of methods to their vendor-specific implementations
@ -71,41 +83,50 @@ VENDOR_METHODS = {
"get_stock_data": {
"alpha_vantage": get_alpha_vantage_stock,
"yfinance": get_YFin_data_online,
"akshare": get_stock_data_akshare,
},
# technical_indicators
"get_indicators": {
"alpha_vantage": get_alpha_vantage_indicator,
"yfinance": get_stock_stats_indicators_window,
"akshare": get_indicator_akshare,
},
# fundamental_data
"get_fundamentals": {
"alpha_vantage": get_alpha_vantage_fundamentals,
"yfinance": get_yfinance_fundamentals,
"akshare": get_fundamentals_akshare,
},
"get_balance_sheet": {
"alpha_vantage": get_alpha_vantage_balance_sheet,
"yfinance": get_yfinance_balance_sheet,
"akshare": get_balance_sheet_akshare,
},
"get_cashflow": {
"alpha_vantage": get_alpha_vantage_cashflow,
"yfinance": get_yfinance_cashflow,
"akshare": get_cashflow_akshare,
},
"get_income_statement": {
"alpha_vantage": get_alpha_vantage_income_statement,
"yfinance": get_yfinance_income_statement,
"akshare": get_income_statement_akshare,
},
# news_data
"get_news": {
"alpha_vantage": get_alpha_vantage_news,
"yfinance": get_news_yfinance,
"akshare": get_news_akshare,
},
"get_global_news": {
"yfinance": get_global_news_yfinance,
"alpha_vantage": get_alpha_vantage_global_news,
"akshare": get_global_news_akshare,
},
"get_insider_transactions": {
"alpha_vantage": get_alpha_vantage_insider_transactions,
"yfinance": get_yfinance_insider_transactions,
"akshare": get_insider_transactions_akshare,
},
}
@ -159,4 +180,4 @@ def route_to_vendor(method: str, *args, **kwargs):
except AlphaVantageRateLimitError:
continue # Only rate limits trigger fallback
raise RuntimeError(f"No available vendor for '{method}'")
raise RuntimeError(f"No available vendor for '{method}'")

View File

@ -26,10 +26,10 @@ DEFAULT_CONFIG = {
# Data vendor configuration
# Category-level configuration (default for all tools in category)
"data_vendors": {
"core_stock_apis": "yfinance", # Options: alpha_vantage, yfinance
"technical_indicators": "yfinance", # Options: alpha_vantage, yfinance
"fundamental_data": "yfinance", # Options: alpha_vantage, yfinance
"news_data": "yfinance", # Options: alpha_vantage, yfinance
"core_stock_apis": "yfinance", # Options: alpha_vantage, yfinance, akshare
"technical_indicators": "yfinance", # Options: alpha_vantage, yfinance, akshare
"fundamental_data": "yfinance", # Options: alpha_vantage, yfinance, akshare
"news_data": "yfinance", # Options: alpha_vantage, yfinance, akshare
},
# Tool-level configuration (takes precedence over category-level)
"tool_vendors": {