新增公司资料/指数/重大事项等 13 个接口, 文档全面对齐

- 新增 fin_mda/fin_equity/fin_company/fin_belong_index/fin_major_events 5 个模块
- 覆盖: 管理层讨论、股本结构、公司介绍、所属行业、指数分类/统计/成分、并购/股权激励/诉讼/关联交易/违规/担保
- _emchoice.fetch_report 支持"数据为空"按空结果处理
- api.py 增加 _simple_endpoint 统一生成纯 stocks 参数接口, 路由达 29 个 /fin 端点
- 冒烟测试扩展至 56 用例, 全部通过
- api_manual/blueprint/SKILLS/待优化 文档与代码路径 100% 对齐
This commit is contained in:
2026-08-15 11:34:11 +08:00
parent 797369bbed
commit 2ce68b7b5d
13 changed files with 1147 additions and 11 deletions
+74
View File
@@ -29,6 +29,18 @@ from utils.fin_dividend import get_dividend_detail, get_dividend_statics
from utils.fin_free_holders import get_free_holders
from utils.fin_holders import get_holders
from utils.fin_holder_num import get_holder_num
from utils.fin_mda import get_mda
from utils.fin_equity import get_equity
from utils.fin_company import get_company_info, get_industry
from utils.fin_belong_index import get_index_classif, get_belong_index, get_index_membership
from utils.fin_major_events import (
get_acquisitions,
get_equity_incentive,
get_litigation,
get_related_transaction,
get_violation,
get_guarantee,
)
app = FastAPI(
@@ -137,6 +149,19 @@ def root():
"GET /fin/free-holders": "拉取十大流通股东",
"GET /fin/holders": "拉取十大股东明细",
"GET /fin/holder-num": "拉取股东户数",
"GET /fin/mda": "拉取管理层讨论与分析(年报/中报)",
"GET /fin/equity": "拉取股本结构",
"GET /fin/company-info": "拉取公司介绍",
"GET /fin/industry": "拉取所属行业",
"GET /fin/index-classif": "拉取所属指数分类",
"GET /fin/belong-index": "拉取纳入指数统计",
"GET /fin/index-membership": "拉取指数成分权重",
"GET /fin/acquisitions": "拉取并购事件",
"GET /fin/equity-incentive": "拉取股权激励",
"GET /fin/litigation": "拉取诉讼仲裁",
"GET /fin/related-transaction": "拉取关联交易",
"GET /fin/violation": "拉取违规处罚",
"GET /fin/guarantee": "拉取对外担保",
"GET /health": "健康检查",
},
"usage": {
@@ -145,6 +170,8 @@ def root():
"fin_main_business": "/fin/main-business?stocks=603233.SH&classify_type=产品&years=3",
"fin_balance": "/fin/balance?stocks=603233.SH&years=3",
"fin_dividend_detail": "/fin/dividend-detail?stocks=603233.SH&years=5",
"fin_mda": "/fin/mda?stocks=603233.SH&years=5",
"fin_company_info": "/fin/company-info?stocks=603233.SH",
},
}
@@ -564,6 +591,53 @@ def fin_holder_num(
return payload
def _split_codes(stocks: str) -> list[str]:
"""解析逗号分隔的股票代码参数."""
codes = [code.strip() for code in stocks.split(",") if code.strip()]
if not codes:
raise HTTPException(400, detail="stocks 参数不能为空")
return codes
def _simple_endpoint(path: str, fetch, label: str, default_years: int, has_years: bool = True):
"""生成统一的 GET 端点: 只有 stocks (+years) 参数的接口."""
def endpoint(
stocks: str = Query(..., description="股票代码,逗号分隔,例如 '603233.SH'。仅支持代码,不需要 ORG_CODE。", examples=["603233.SH"]),
years: Optional[int] = Query(default_years if has_years else None, ge=1, le=20, description=f"拉取最近多少年的{label}"),
):
codes = _split_codes(stocks)
df = fetch(codes) if years is None else fetch(codes, years=years)
if df.empty:
extra = {"years": years} if years is not None else {}
return _empty_response(f"无{label}数据, 请检查股票代码或筛选条件", codes, **extra)
payload = _df_to_json_payload(df)
payload["codes_requested"] = codes
if years is not None:
payload["years"] = years
return payload
app.get(path)(endpoint)
return endpoint
# ---- 管理层讨论与分析 / 股本结构 (无 years) ----
_simple_endpoint("/fin/mda", get_mda, "管理层讨论与分析", default_years=5)
_simple_endpoint("/fin/equity", get_equity, "股本结构", default_years=3, has_years=False)
_simple_endpoint("/fin/company-info", get_company_info, "公司介绍", default_years=3, has_years=False)
_simple_endpoint("/fin/industry", get_industry, "所属行业", default_years=3, has_years=False)
_simple_endpoint("/fin/index-classif", get_index_classif, "所属指数分类", default_years=3, has_years=False)
_simple_endpoint("/fin/belong-index", get_belong_index, "纳入指数统计", default_years=3, has_years=False)
_simple_endpoint("/fin/index-membership", get_index_membership, "指数成分权重", default_years=3, has_years=False)
# ---- 重大事项六类 ----
_simple_endpoint("/fin/acquisitions", get_acquisitions, "并购事件", default_years=3)
_simple_endpoint("/fin/equity-incentive", get_equity_incentive, "股权激励", default_years=3)
_simple_endpoint("/fin/litigation", get_litigation, "诉讼仲裁", default_years=3)
_simple_endpoint("/fin/related-transaction", get_related_transaction, "关联交易", default_years=3)
_simple_endpoint("/fin/violation", get_violation, "违规处罚", default_years=3)
_simple_endpoint("/fin/guarantee", get_guarantee, "对外担保", default_years=3)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8765, log_level="info")