上海非凸智能 2026-06-23 开源的 FTShare Python SDK(MIT),用 mixin 组合、endpoint registry、DataFrame 优先把 176 个金融接口统一为数据访问层。
FTShare Python SDK:把 176 个金融数据接口封装成 pandas 一行调用
核心判断
2026 年 6 月 23 日,上海非凸智能(ft.tech)在 GitHub 开源 ftshare-python-sdk[1],解决一个具体问题:把 176 个金融数据 REST 接口变成一行 pandas 调用。ft.market_api().baidu_financial_calendar(...) 直接返回 DataFrame,可 .groupby().merge().plot()。
它在 ftshare 4 层栈里是「数据访问层」:FTShare 数据服务 → ftshare-python-sdk(本文主角)→ ftshare-mcp(MCP 工具层)→ ftshare-skills(投研任务层)→ Agent 应用。
截至 2026-06-28,GitHub 11 stars/1 fork,非常早期,但已立起 176 个 endpoint、14 个业务域 mixin 和统一 client。4 个设计点:
- Mixin 组合:14 业务域 mixin +
BaseClient 拼到 FtshareClient - Endpoint registry:176 接口元数据登记在
endpoints.ENDPOINTS - DataFrame 优先:默认 DataFrame,
as_dataframe=False 退到 rows,raw=True 退到原始 JSON - 分页 4 模式:
page/page_size、limit、all_pages、fetch_all
边界:MIT 协议,依赖 pandas>=1.5/requests>=2.31.0,Python 3.9+;market_api() 默认访问 https://market.ft.tech/data/;CI 跑 mock 单测,真实接口测试需 FTSHARE_RUN_INTEGRATION=1。
生态卡位:4 层栈中的数据访问层
SDK 定位决定取舍:向下对接 FTShare 数据服务(采集清洗存储在服务端),向上为 ftshare-mcp/ftshare-skills 提供统一数据形态,横向面向量化研究员。
和 akshare/tushare/baostock 的关键差异在于 FTShare 同时照顾上层 agent 工具链:as_dataframe=False 返回 rows、headers 可注入、base_url 可切换,MCP/Skill 能把结果按 tool calling 协议塞回 agent 上下文。
需要这一层有三个原因:
- 数据形态适配:agent 要 list[dict],quant 要 DataFrame
- 演进隔离:服务端改 URL 时 SDK 升级,上层不改
Mixin 组合模式:一个 client 覆盖 14 个业务域
FtshareClient 用多继承把 14 业务域 mixin(CorporateApiMixin/.../StockApiMixin)+ BaseClient 拼到一个类,ft.market_api() 返回的实例支持 176 个方法。
对比 6000 行大类、14 个独立 client、plugin registry + 动态方法挂载等方案,mixin 更合适:
- 静态可分析:IDE 补全 + mypy/pyright
- 业务域物理隔离:
apis/market.py 改动只影响 MarketApiMixin - 加新 mixin 不改现有代码:写 mixin → export → 继承列表加一项
代价是 mixin 不能共享私有状态,但 SDK 场景 mixin 只通过 self.method() 调 BaseClient,无此需求。
Endpoint registry:176 个接口的单一事实源
方法体里不写死 path,而是把所有接口元数据收拢到 ENDPOINTS: dict[str, Endpoint]。Endpoint 是 @dataclass(frozen=True),字段:name/path/method(默认 GET)/title/params/max_page_size(默认 200,stk_limit/stk_premarket 是 500)。mixin 方法体只做:构造参数 + 查 ENDPOINTS 拿 path + 调 self.get_paginated(path, **kwargs)。
三大理由:
- 接口元数据自动化生成:
docs/API_REFERENCE.md 由 SDK docstring + ENDPOINTS 生成(脚本未开源),新增接口不碰 get_paginated/get - 文档一致:
title/doc_file/original_api 让文档、SDK 方法、客户端代码同源更新 - 运行时反射:
from ftshare.endpoints import ENDPOINTS 看到 176 条;调试 404 时 print(ENDPOINTS['xxx'].path) 看正确 URL
不用 __getattr__ 动态生成会失去 IDE 补全、静态检查和文档生成。
任务如何经过系统:一次完整调用
以 market.baidu_financial_calendar(..., limit=5) 为例,4 步:
market_api() 工厂——BASE_URL(默认 https://market.ft.tech/data/)+ 参数组装成 FtshareClient,可用 ft.set_base_url(...) 切换。BaseClient.__init__——normalize_base_url 带尾斜杠;requests.Session() 共享 TCP;headers 每次注入以透传 trace id。- mixin 方法体——构造
request_params、查 ENDPOINTS 拿 URL、调 get_paginated(不传 limit/all_pages 直接请求;传则走分页路径,raw=True 拿每页 payload 合并 rows)。 get 单次 HTTP——过滤 None、拼 URL、session 发请求。非 2xx 抛 FtshareHTTPError,JSON 失败抛 FtshareDecodeError,业务 code!=0 抛 FtshareAPIError。随后走 extract_tabular → select_fields → to_dataframe 三段管道,按优先级提取 data.records/data.items/顶层 items,返回 DataFrame。
DataFrame 优先 + 三层返回控制
三层返回:
- 默认 DataFrame(pandas 流水线 / quant 研究)
as_dataframe=False 返回 list[dict](MCP tool 输出 JSON-Lines)raw=True 返回 原始 JSON(调试 / 字段映射研究)
默认 DataFrame 有两个原因:一是中国 quant 圈事实标准(akshare/tushare/baostock 都是),二是 agent toolchain 适配(list[dict] 可直接塞进 tool result)。to_dataframe 懒加载 pandas。MCP Tool 推荐 as_dataframe=False。
分页 4 模式
四个模式语义差异:
page + page_size:精确单页,调试/单页验证limit:结果数优先,「最多要 N 条」,SDK 决定翻几页all_pages:全量拉取,翻到最后一页,max_pages 是安全阀fetch_all:跨接口通用,字符串方法名调任意 endpoint,适合同步脚本
性能建议:批量用 limit 而非 all_pages;page_size 设为 max_page_size;生产必设 max_pages。
约束:默认单页最大 200(stk_limit/stk_premarket 是 500),超限抛 ValueError。
全量不一定拿完:total_pages 不准、翻页期间数据更新、max_pages 太小静默截断,生产拉全量要对账。
异常三层分类
基类 FtshareError 下三类,都带上下文:
FtshareHTTPError:HTTP 非 2xxFtshareDecodeError:响应非合法 JSONFtshareAPIError:业务 code!=0
raise_for_api_error 认 0/"0"/200/"200" 兼容服务端不同时期业务码格式。FtshareAPIError(参数错)可转 tool 错误信息让 agent 重试;其余两类适合抛给外层告警或人工介入。
实战踩坑笔记
extract_tabular envelope 适配:按 data.records → data.items → 顶层 items 优先级试三种路径,不匹配返回 payload 本身(不吞成空列表)。all_pages=True 翻页期间数据变化:每次请求有时间差,「全量数据」非同一快照,同步脚本记录时间戳。market.ft.tech 超时:SDK 只把 HTTP 非 2xx 封成 FtshareHTTPError,未包装连接/DNS/读超时。批量拉建议 timeout=30,外层同时捕获 requests.exceptions.RequestException 和 ft.FtshareError 做退避重试。
与同类 SDK 的差异点
对比 akshare/tushare/baostock:
- 协议:FTShare MIT/零凭据(akshare MIT/无、tushare 积分制/token、baostock BSD/无)
- 接口数:176(akshare 1000+/tushare 200+/baostock 几十)
- 分页/异常:4 模式 + 3 类(其余均手动/1 类)
短板:接口数远小于 akshare。优势:三层返回控制(raw=True 逃生)、endpoint registry(schema 变了不手改)、MIT + 零凭据(零合规摩擦)。
决策启示与采用顺序
- Skill 作者:
pip install ftshare 当数据源,默认 as_dataframe=False 输出 list[dict]。 - 数据团队:endpoint registry + mixin 模式可借鉴——接口登记到
ENDPOINTS,业务域用 mixin 拆,留 raw=True。 - 量化研究者:基本面(balance/cashflow/income)、宏观对冲(
consumer_*_monthly)、技术面+资金面(涨跌停/龙虎榜/资金流向)、跨市场(港股/全球指数)。ENDPOINTS['xxx'] 看 path+params。
采用顺序:
pip install ftshare,用 baidu_financial_calendar 拿 DataFrame 验证- quant 裸
requests.get 换成 SDK 调用(fields 替代手写提取) - 包成 MCP tool(
as_dataframe=False + JSON 序列化)
不要做:不一次性集成 176 个 endpoint(选 5-10 个深用);不锁版本到 patch 号;不绕过 ENDPOINTS 手动构造 URL。
边界:HTTP polling 不适合实时行情(需 WebSocket SDK);技术指标/回测是 quant 自己的事;market.ft.tech 境外访问可能被墙,需国内代理或 ft.set_base_url() 切镜像。
常见问题解答
Q1:SDK 免费吗?有限制吗?——SDK 本身 MIT 免费;底层数据服务 market.ft.tech 限制看 FTShare 服务条款。目前公开访问不需 token,生产建议联系 ft.tech 确认 SLA。
Q2:和 akshare 比用哪个?——akshare 已覆盖但 FTShare 还没的冷门接口用 akshare;做 agent skill 或需稳定 SDK 架构用 FTShare。可共存。
Q3:MCP tool 返回 DataFrame 还是 list[dict]?——list[dict](as_dataframe=False)。MCP tool result 是 JSON,DataFrame 需序列化可能丢信息。
参考资料
- ftshare-python-sdk GitHub 仓库[2]——MIT;11 stars
- FTShare 数据服务[3] / 非凸智能[4] / API_REFERENCE.md[5] / CHANGELOG.md[6]
引用链接
[1]ftshare-python-sdk: https://github.com/ftshare-lab/ftshare-python-sdk
[2]ftshare-python-sdk GitHub 仓库: https://github.com/ftshare-lab/ftshare-python-sdk
[3]FTShare 数据服务: https://market.ft.tech/
[4]非凸智能: https://ft.tech/
[5]API_REFERENCE.md: https://github.com/ftshare-lab/ftshare-python-sdk/blob/main/docs/API_REFERENCE.md
[6]CHANGELOG.md: https://github.com/ftshare-lab/ftshare-python-sdk/blob/main/CHANGELOG.md