From 041b106728e3ad0446710f0d7a855b469bcbffb6 Mon Sep 17 00:00:00 2001 From: zhuhao Date: Fri, 17 Jul 2026 09:31:01 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20ETF/=E5=8F=AF?= =?UTF-8?q?=E8=BD=AC=E5=80=BA/=E6=8C=87=E6=95=B0=20K=20=E7=BA=BF=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E5=B9=B6=E6=89=A9=E5=B1=95=E6=89=93=E6=9D=BF=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=20trade=5Fdate=20=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - endpoints/apis: 新增 etf_candlesticks[_batch]、convertible_bond_candlesticks[_batch]、index_candlesticks[_batch] 共 6 个方法 - limit_up_pool/limit_up_break_pool/limit_down_pool/limit_event_timeline_3s 增加可选 trade_date 参数 - tests/test_client.py 补充 POST 批量 K 线与打板 trade_date mock 覆盖 - docs/API_REFERENCE.md 同步条目与计数 --- docs/API_REFERENCE.md | 268 ++++++++++++++++++++++++++++++--- src/ftshare/apis/bond.py | 98 ++++++++++++ src/ftshare/apis/etf.py | 98 ++++++++++++ src/ftshare/apis/index.py | 98 ++++++++++++ src/ftshare/apis/stock.py | 40 +++-- src/ftshare/endpoints/bond.py | 16 ++ src/ftshare/endpoints/etf.py | 16 ++ src/ftshare/endpoints/index.py | 16 ++ src/ftshare/endpoints/stock.py | 5 +- tests/test_client.py | 151 +++++++++++++++++++ 10 files changed, 765 insertions(+), 41 deletions(-) diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index d059c30..e1cf676 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -6,7 +6,7 @@ | 指标 | 数量 | |---|---:| -| SDK 方法总数 | 180 | +| SDK 方法总数 | 186 | ## 专题分布 @@ -17,11 +17,11 @@ | 股票数据 | 96 | `ftshare.apis.stock` | `ftshare.endpoints.stock` | | 港股数据 | 14 | `ftshare.apis.hk` | `ftshare.endpoints.hk` | | 美股数据 | 9 | `ftshare.apis.us` | `ftshare.endpoints.us` | -| 指数专题 | 8 | `ftshare.apis.index` | `ftshare.endpoints.index` | -| ETF专题 | 8 | `ftshare.apis.etf` | `ftshare.endpoints.etf` | +| 指数专题 | 10 | `ftshare.apis.index` | `ftshare.endpoints.index` | +| ETF专题 | 10 | `ftshare.apis.etf` | `ftshare.endpoints.etf` | | 公募基金 | 5 | `ftshare.apis.fund` | `ftshare.endpoints.fund` | | 期货数据 | 9 | `ftshare.apis.futures` | `ftshare.endpoints.futures` | -| 债券专题 | 2 | `ftshare.apis.bond` | `ftshare.endpoints.bond` | +| 债券专题 | 4 | `ftshare.apis.bond` | `ftshare.endpoints.bond` | | 宏观经济 | 17 | `ftshare.apis.economic` | `ftshare.endpoints.economic` | | 大模型语料 | 5 | `ftshare.apis.llm_corpus` | `ftshare.endpoints.llm_corpus` | | 现货数据 | 2 | `ftshare.apis.spot` | `ftshare.endpoints.spot` | @@ -76,10 +76,10 @@ df = market.baidu_financial_calendar( | [`hk_sh_stock_connect_members`](#api-hk-sh-stock-connect-members) | 沪港通成份 | `GET` | `api/v1/market/data/hk-sh-stock-connect-members` | - | `沪港通成份.md` | | [`hk_sz_stock_connect_members`](#api-hk-sz-stock-connect-members) | 深港通成份 | `GET` | `api/v1/market/data/hk-sz-stock-connect-members` | - | `深港通成份.md` | | [`income`](#api-income) | A股利润表 | `GET` | `api/v1/market/data/finance/income` | `stock_code`, `year`, `report_type`, `page`, `page_size` | `A股利润表.md` | -| [`limit_down_pool`](#api-limit-down-pool) | 跌停池 | `GET` | `api/v1/market/data/limit-down-pool` | - | `跌停池.md` | -| [`limit_event_timeline_3s`](#api-limit-event-timeline-3s) | 涨跌停事件时间线 | `GET` | `api/v1/market/data/limit-event-timeline-3s` | `symbol` | `涨跌停事件时间线.md` | -| [`limit_up_break_pool`](#api-limit-up-break-pool) | 炸板池 | `GET` | `api/v1/market/data/limit-up-break-pool` | - | `炸板池.md` | -| [`limit_up_pool`](#api-limit-up-pool) | 涨停池 | `GET` | `api/v1/market/data/limit-up-pool` | - | `涨停池.md` | +| [`limit_down_pool`](#api-limit-down-pool) | 跌停池 | `GET` | `api/v1/market/data/limit-down-pool` | `trade_date` | `跌停池.md` | +| [`limit_event_timeline_3s`](#api-limit-event-timeline-3s) | 涨跌停事件时间线 | `GET` | `api/v1/market/data/limit-event-timeline-3s` | `symbol`, `trade_date` | `涨跌停事件时间线.md` | +| [`limit_up_break_pool`](#api-limit-up-break-pool) | 炸板池 | `GET` | `api/v1/market/data/limit-up-break-pool` | `trade_date` | `炸板池.md` | +| [`limit_up_pool`](#api-limit-up-pool) | 涨停池 | `GET` | `api/v1/market/data/limit-up-pool` | `trade_date` | `涨停池.md` | | [`limit_up_pool_yesterday`](#api-limit-up-pool-yesterday) | 昨日涨停池 | `GET` | `api/v1/market/data/limit-up-pool-yesterday` | - | `昨日涨停池.md` | | [`margin_trading_details`](#api-margin-trading-details) | 融资融券明细 | `GET` | `api/v1/market/data/margin-trading-details` | `date`, `page`, `page_size` | `融资融券明细.md` | | [`margin_trading_details_paginated`](#api-margin-trading-details-paginated) | 融资融券明细分页 | `GET` | `api/v1/market/data/margin-trading-details` | `date`, `page`, `page_size` | `融资融券明细分页.md` | @@ -183,6 +183,8 @@ df = market.baidu_financial_calendar( | SDK 方法 | 接口名称 | HTTP | Path | 参数 | 来源文档 | |---|---|---|---|---|---| | [`global_index_daily_kline`](#api-global-index-daily-kline) | 全球指数日K线 | `GET` | `api/v1/market/data/global-index/daily-kline` | `secid`, `start_date`, `end_date` | `全球指数日K线.md` | +| [`index_candlesticks`](#api-index-candlesticks) | 指数K线 | `POST` | `api/v1/market/data/index-candlesticks` | `symbol`, `interval_unit`, `interval_value`, `adjust_kind`, `since_ts_millis`, `until_ts_millis`, `limit` | `指数K线.md` | +| [`index_candlesticks_batch`](#api-index-candlesticks-batch) | 批量指数K线 | `POST` | `api/v1/market/data/index-candlesticks/batch` | `symbols`, `interval_unit`, `interval_value`, `adjust_kind`, `since_ts_millis`, `until_ts_millis`, `limit` | `批量指数K线.md` | | [`index_description_all`](#api-index-description-all) | 指数基础信息 | `GET` | `api/v1/market/data/index-description-all` | - | `指数基础信息.md` | | [`index_description_list`](#api-index-description-list) | 中证指数描述列表 | `GET` | `api/v1/market/data/index/index_description` | `page`, `page_size` | `中证指数描述列表.md` | | [`index_weight_list`](#api-index-weight-list) | 指数权重列表 | `GET` | `api/v1/market/data/index/index_weight` | `index_code`, `date`, `page`, `page_size` | `指数权重列表.md` | @@ -196,6 +198,8 @@ df = market.baidu_financial_calendar( | SDK 方法 | 接口名称 | HTTP | Path | 参数 | 来源文档 | |---|---|---|---|---|---| | [`etf_adjust_factor`](#api-etf-adjust-factor) | ETF复权因子 | `GET` | `api/v1/market/data/etf-adjust-factor` | `symbol`, `trade_date`, `start_date`, `end_date`, `offset`, `limit` | `ETF复权因子.md` | +| [`etf_candlesticks`](#api-etf-candlesticks) | ETFK线 | `POST` | `api/v1/market/data/etf-candlesticks` | `symbol`, `interval_unit`, `interval_value`, `adjust_kind`, `since_ts_millis`, `until_ts_millis`, `limit` | `ETFK线.md` | +| [`etf_candlesticks_batch`](#api-etf-candlesticks-batch) | 批量ETFK线 | `POST` | `api/v1/market/data/etf-candlesticks/batch` | `symbols`, `interval_unit`, `interval_value`, `adjust_kind`, `since_ts_millis`, `until_ts_millis`, `limit` | `批量ETFK线.md` | | [`etf_components`](#api-etf-components) | ETF成份股 | `GET` | `api/v1/market/data/etf-component` | `symbol` | `ETF成份股.md` | | [`etf_components_all`](#api-etf-components-all) | ETF成份列表 | `GET` | `api/v1/market/data/etf-components-all` | - | `ETF成份列表.md` | | [`etf_description_all`](#api-etf-description-all) | ETF基础信息 | `GET` | `api/v1/market/data/etf-description-all` | - | `ETF基础信息.md` | @@ -234,6 +238,8 @@ df = market.baidu_financial_calendar( |---|---|---|---|---|---| | [`cb_base_data`](#api-cb-base-data) | 可转债基础数据 | `GET` | `api/v1/market/data/cb/cb-base-data` | `symbol_code` | `可转债基础数据.md` | | [`cb_lists`](#api-cb-lists) | 可转债列表 | `GET` | `api/v1/market/data/cb/cb-lists` | - | `可转债列表.md` | +| [`convertible_bond_candlesticks`](#api-convertible-bond-candlesticks) | 可转债K线 | `POST` | `api/v1/market/data/convertible-bond-candlesticks` | `symbol`, `interval_unit`, `interval_value`, `adjust_kind`, `since_ts_millis`, `until_ts_millis`, `limit` | `可转债K线.md` | +| [`convertible_bond_candlesticks_batch`](#api-convertible-bond-candlesticks-batch) | 批量可转债K线 | `POST` | `api/v1/market/data/convertible-bond-candlesticks/batch` | `symbols`, `interval_unit`, `interval_value`, `adjust_kind`, `since_ts_millis`, `until_ts_millis`, `limit` | `批量可转债K线.md` | ### 宏观经济 @@ -1222,7 +1228,7 @@ Returns: - 接口名称:跌停池 - HTTP:`GET` - Path:`api/v1/market/data/limit-down-pool` -- 参数:- +- 参数:`trade_date` - 来源文档:`跌停池.md` - 原始接口:`limit_down_pool` @@ -1234,6 +1240,7 @@ Method: ``GET``. Documented endpoint: ``limit_down_pool``. Args: + trade_date: 交易日期,格式 YYYYMMDD;不传或传当日时查询实时数据 (type: string; required: N). raw: Return the decoded JSON payload without tabular extraction. fields: Optional field list or comma-separated field string applied after extraction. as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. @@ -1250,7 +1257,7 @@ Returns: - 接口名称:涨跌停事件时间线 - HTTP:`GET` - Path:`api/v1/market/data/limit-event-timeline-3s` -- 参数:`symbol` +- 参数:`symbol`, `trade_date` - 来源文档:`涨跌停事件时间线.md` - 原始接口:`limit_event_timeline_3s` @@ -1263,6 +1270,7 @@ Documented endpoint: ``limit_event_timeline_3s``. Args: symbol: 标的代码,如 000001.XSHE;不传返回全市场 (type: string; required: N). + trade_date: 交易日期,格式 YYYYMMDD;不传或传当日时查询实时数据 (type: string; required: N). raw: Return the decoded JSON payload without tabular extraction. fields: Optional field list or comma-separated field string applied after extraction. as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. @@ -1279,7 +1287,7 @@ Returns: - 接口名称:炸板池 - HTTP:`GET` - Path:`api/v1/market/data/limit-up-break-pool` -- 参数:- +- 参数:`trade_date` - 来源文档:`炸板池.md` - 原始接口:`limit_up_break_pool` @@ -1291,6 +1299,7 @@ Method: ``GET``. Documented endpoint: ``limit_up_break_pool``. Args: + trade_date: 交易日期,格式 YYYYMMDD;不传或传当日时查询实时数据 (type: string; required: N). raw: Return the decoded JSON payload without tabular extraction. fields: Optional field list or comma-separated field string applied after extraction. as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. @@ -1307,7 +1316,7 @@ Returns: - 接口名称:涨停池 - HTTP:`GET` - Path:`api/v1/market/data/limit-up-pool` -- 参数:- +- 参数:`trade_date` - 来源文档:`涨停池.md` - 原始接口:`limit_up_pool` @@ -1319,6 +1328,7 @@ Method: ``GET``. Documented endpoint: ``limit_up_pool``. Args: + trade_date: 交易日期,格式 YYYYMMDD;不传或传当日时查询实时数据 (type: string; required: N). raw: Return the decoded JSON payload without tabular extraction. fields: Optional field list or comma-separated field string applied after extraction. as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. @@ -1863,13 +1873,13 @@ Method: ``POST``. Documented endpoint: ``stock_candlesticks``. Args: - symbol: 标的代码,如 000001.SZ (type: SymbolKey; required: Y). + symbol: 标的代码,如 000001.SZ、600519.XSHG;长短市场后缀均支持 (type: SymbolKey; required: Y). interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). - interval_value: 间隔数值(默认1,如 Day+1=日K,Minute+5=5分钟) (type: int; required: N). - adjust_kind: 复权:None(默认,除权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). - since_ts_millis: 开始时间戳(毫秒);与 until 跨度 ≤3 天 (type: DateTime(ms); required: N). - until_ts_millis: 结束时间戳(毫秒) (type: DateTime(ms); required: Y). - limit: 返回条数上限 (type: int; required: N). + interval_value: 间隔数值(默认 1,如 Day+1=日 K,Minute+5=5 分钟) (type: int; required: N). + adjust_kind: 复权:None(默认,除权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳,单位毫秒;分钟 K 线与 until 跨度 ≤3 天 (type: DateTime(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: DateTime(ms); required: Y). + limit: 返回条数上限;未传 since 和 limit 时默认 50 (type: int; required: N). raw: Return the decoded JSON payload without tabular extraction. fields: Optional field list or comma-separated field string applied after extraction. as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. @@ -1898,13 +1908,13 @@ Method: ``POST``. Documented endpoint: ``stock_candlesticks_batch``. Args: - symbols: 标的代码列表,如 ["000001.SZ","600000.SH"] (type: array[SymbolKey]; required: Y). + symbols: 标的代码列表,允许股票、ETF、可转债和指数混合,例如 ["600519.SH","510300.SH","113027.SH","000300.SH"] (type: string[]; required: Y). interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). - interval_value: 间隔数值(默认1) (type: int; required: N). - adjust_kind: 复权:None(默认)/Forward(前复权)/Backward(后复权) (type: enum; required: N). - since_ts_millis: 开始时间戳(毫秒);与 until 跨度 ≤3 天 (type: DateTime(ms); required: N). - until_ts_millis: 结束时间戳(毫秒) (type: DateTime(ms); required: Y). - limit: 每标的返回条数上限 (type: int; required: N). + interval_value: 间隔数值,默认 1;例如 Minute+5 表示 5 分钟 K 线 (type: int; required: N). + adjust_kind: 复权类型:None(默认)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳;分钟 K 线与 until 的跨度不超过 3 天 (type: int(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: int(ms); required: Y). + limit: 每个标的的返回条数上限;未传 since 和 limit 时默认 50 (type: int; required: N). raw: Return the decoded JSON payload without tabular extraction. fields: Optional field list or comma-separated field string applied after extraction. as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. @@ -4292,6 +4302,76 @@ Returns: payloads when multi-page fetching is used with ``raw=True``. ``` +

index_candlesticks

+ +- 接口名称:指数K线 +- HTTP:`POST` +- Path:`api/v1/market/data/index-candlesticks` +- 参数:`symbol`, `interval_unit`, `interval_value`, `adjust_kind`, `since_ts_millis`, `until_ts_millis`, `limit` +- 来源文档:`指数K线.md` +- 原始接口:`index_candlesticks` + +```text +指数K线. + +Endpoint: ``api/v1/market/data/index-candlesticks``. +Method: ``POST``. +Documented endpoint: ``index_candlesticks``. + +Args: + symbol: 指数代码,如 000300.XSHG、399001.XSHE;也接受 .SH、.SZ 短后缀 (type: string; required: Y). + interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). + interval_value: 间隔数值,默认 1;例如 Minute+5 表示 5 分钟 K 线 (type: int; required: N). + adjust_kind: 复权:None(默认,不复权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳,单位毫秒;分钟 K 线与 until 的跨度 ≤3 天 (type: int(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: int(ms); required: Y). + limit: 返回条数上限;未传 since 和 limit 时默认最多返回 50 根 K 线 (type: int; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + +Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. +``` + +

index_candlesticks_batch

+ +- 接口名称:批量指数K线 +- HTTP:`POST` +- Path:`api/v1/market/data/index-candlesticks/batch` +- 参数:`symbols`, `interval_unit`, `interval_value`, `adjust_kind`, `since_ts_millis`, `until_ts_millis`, `limit` +- 来源文档:`批量指数K线.md` +- 原始接口:`index_candlesticks_batch` + +```text +批量指数K线. + +Endpoint: ``api/v1/market/data/index-candlesticks/batch``. +Method: ``POST``. +Documented endpoint: ``index_candlesticks_batch``. + +Args: + symbols: 指数代码列表,如 ["000300.XSHG","399001.XSHE"];也接受 .SH、.SZ 短后缀 (type: string[]; required: Y). + interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). + interval_value: 间隔数值,默认 1;例如 Minute+5 表示 5 分钟 K 线 (type: int; required: N). + adjust_kind: 复权:None(默认,不复权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳,单位毫秒;分钟 K 线与 until 的跨度 ≤3 天 (type: int(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: int(ms); required: Y). + limit: 每个标的的返回条数上限;未传 since 和 limit 时默认最多返回 50 根 K 线 (type: int; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + +Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. +``` +

index_description_all

- 接口名称:指数基础信息 @@ -4558,6 +4638,76 @@ Returns: payloads when multi-page fetching is used with ``raw=True``. ``` +

etf_candlesticks

+ +- 接口名称:ETFK线 +- HTTP:`POST` +- Path:`api/v1/market/data/etf-candlesticks` +- 参数:`symbol`, `interval_unit`, `interval_value`, `adjust_kind`, `since_ts_millis`, `until_ts_millis`, `limit` +- 来源文档:`ETFK线.md` +- 原始接口:`etf_candlesticks` + +```text +ETFK线. + +Endpoint: ``api/v1/market/data/etf-candlesticks``. +Method: ``POST``. +Documented endpoint: ``etf_candlesticks``. + +Args: + symbol: ETF 代码,如 510300.XSHG、159915.XSHE;也接受 .SH、.SZ 短后缀 (type: string; required: Y). + interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). + interval_value: 间隔数值,默认 1;例如 Minute+5 表示 5 分钟 K 线 (type: int; required: N). + adjust_kind: 复权:None(默认,不复权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳,单位毫秒;分钟 K 线与 until 的跨度 ≤3 天 (type: int(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: int(ms); required: Y). + limit: 返回条数上限;未传 since 和 limit 时默认最多返回 50 根 K 线 (type: int; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + +Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. +``` + +

etf_candlesticks_batch

+ +- 接口名称:批量ETFK线 +- HTTP:`POST` +- Path:`api/v1/market/data/etf-candlesticks/batch` +- 参数:`symbols`, `interval_unit`, `interval_value`, `adjust_kind`, `since_ts_millis`, `until_ts_millis`, `limit` +- 来源文档:`批量ETFK线.md` +- 原始接口:`etf_candlesticks_batch` + +```text +批量ETFK线. + +Endpoint: ``api/v1/market/data/etf-candlesticks/batch``. +Method: ``POST``. +Documented endpoint: ``etf_candlesticks_batch``. + +Args: + symbols: ETF 代码列表,如 ["510300.XSHG","159915.XSHE"];也接受 .SH、.SZ 短后缀 (type: string[]; required: Y). + interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). + interval_value: 间隔数值,默认 1;例如 Minute+5 表示 5 分钟 K 线 (type: int; required: N). + adjust_kind: 复权:None(默认,不复权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳,单位毫秒;分钟 K 线与 until 的跨度 ≤3 天 (type: int(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: int(ms); required: Y). + limit: 每个标的的返回条数上限;未传 since 和 limit 时默认最多返回 50 根 K 线 (type: int; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + +Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. +``` +

etf_components

- 接口名称:ETF成份股 @@ -5299,6 +5449,76 @@ Returns: payloads when multi-page fetching is used with ``raw=True``. ``` +

convertible_bond_candlesticks

+ +- 接口名称:可转债K线 +- HTTP:`POST` +- Path:`api/v1/market/data/convertible-bond-candlesticks` +- 参数:`symbol`, `interval_unit`, `interval_value`, `adjust_kind`, `since_ts_millis`, `until_ts_millis`, `limit` +- 来源文档:`可转债K线.md` +- 原始接口:`convertible_bond_candlesticks` + +```text +可转债K线. + +Endpoint: ``api/v1/market/data/convertible-bond-candlesticks``. +Method: ``POST``. +Documented endpoint: ``convertible_bond_candlesticks``. + +Args: + symbol: 可转债代码,如 113027.XSHG、128048.XSHE;也接受 .SH、.SZ 短后缀 (type: string; required: Y). + interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). + interval_value: 间隔数值,默认 1;例如 Minute+5 表示 5 分钟 K 线 (type: int; required: N). + adjust_kind: 复权:None(默认,不复权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳,单位毫秒;分钟 K 线与 until 的跨度 ≤3 天 (type: int(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: int(ms); required: Y). + limit: 返回条数上限;未传 since 和 limit 时默认最多返回 50 根 K 线 (type: int; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + +Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. +``` + +

convertible_bond_candlesticks_batch

+ +- 接口名称:批量可转债K线 +- HTTP:`POST` +- Path:`api/v1/market/data/convertible-bond-candlesticks/batch` +- 参数:`symbols`, `interval_unit`, `interval_value`, `adjust_kind`, `since_ts_millis`, `until_ts_millis`, `limit` +- 来源文档:`批量可转债K线.md` +- 原始接口:`convertible_bond_candlesticks_batch` + +```text +批量可转债K线. + +Endpoint: ``api/v1/market/data/convertible-bond-candlesticks/batch``. +Method: ``POST``. +Documented endpoint: ``convertible_bond_candlesticks_batch``. + +Args: + symbols: 可转债代码列表,如 ["113027.XSHG","128048.XSHE"];也接受 .SH、.SZ 短后缀 (type: string[]; required: Y). + interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). + interval_value: 间隔数值,默认 1;例如 Minute+5 表示 5 分钟 K 线 (type: int; required: N). + adjust_kind: 复权:None(默认,不复权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳,单位毫秒;分钟 K 线与 until 的跨度 ≤3 天 (type: int(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: int(ms); required: Y). + limit: 每个标的的返回条数上限;未传 since 和 limit 时默认最多返回 50 根 K 线 (type: int; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + +Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. +``` + ### 宏观经济

baidu_financial_calendar

diff --git a/src/ftshare/apis/bond.py b/src/ftshare/apis/bond.py index ce485bf..13ce1b6 100644 --- a/src/ftshare/apis/bond.py +++ b/src/ftshare/apis/bond.py @@ -82,3 +82,101 @@ def cb_lists( as_dataframe=as_dataframe, **request_params, ) + + def convertible_bond_candlesticks( + self, + symbol: Any | None = None, + interval_unit: Any | None = None, + interval_value: Any | None = None, + adjust_kind: Any | None = None, + since_ts_millis: Any | None = None, + until_ts_millis: Any | None = None, + limit: Any | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """可转债K线. + + Endpoint: ``api/v1/market/data/convertible-bond-candlesticks``. + Method: ``POST``. + Documented endpoint: ``convertible_bond_candlesticks``. + + Args: + symbol: 可转债代码,如 113027.XSHG、128048.XSHE;也接受 .SH、.SZ 短后缀 (type: string; required: Y). + interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). + interval_value: 间隔数值,默认 1;例如 Minute+5 表示 5 分钟 K 线 (type: int; required: N). + adjust_kind: 复权:None(默认,不复权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳,单位毫秒;分钟 K 线与 until 的跨度 ≤3 天 (type: int(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: int(ms); required: Y). + limit: 返回条数上限;未传 since 和 limit 时默认最多返回 50 根 K 线 (type: int; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = {'symbol': symbol, 'interval_unit': interval_unit, 'interval_value': interval_value, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} + request_params.update(kwargs) + return self._call_endpoint( + 'convertible_bond_candlesticks', + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def convertible_bond_candlesticks_batch( + self, + symbols: Any | None = None, + interval_unit: Any | None = None, + interval_value: Any | None = None, + adjust_kind: Any | None = None, + since_ts_millis: Any | None = None, + until_ts_millis: Any | None = None, + limit: Any | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """批量可转债K线. + + Endpoint: ``api/v1/market/data/convertible-bond-candlesticks/batch``. + Method: ``POST``. + Documented endpoint: ``convertible_bond_candlesticks_batch``. + + Args: + symbols: 可转债代码列表,如 ["113027.XSHG","128048.XSHE"];也接受 .SH、.SZ 短后缀 (type: string[]; required: Y). + interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). + interval_value: 间隔数值,默认 1;例如 Minute+5 表示 5 分钟 K 线 (type: int; required: N). + adjust_kind: 复权:None(默认,不复权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳,单位毫秒;分钟 K 线与 until 的跨度 ≤3 天 (type: int(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: int(ms); required: Y). + limit: 每个标的的返回条数上限;未传 since 和 limit 时默认最多返回 50 根 K 线 (type: int; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = {'symbols': symbols, 'interval_unit': interval_unit, 'interval_value': interval_value, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} + request_params.update(kwargs) + return self._call_endpoint( + 'convertible_bond_candlesticks_batch', + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) diff --git a/src/ftshare/apis/etf.py b/src/ftshare/apis/etf.py index 74ebaaf..89f0fee 100644 --- a/src/ftshare/apis/etf.py +++ b/src/ftshare/apis/etf.py @@ -58,6 +58,104 @@ def etf_adjust_factor( **request_params, ) + def etf_candlesticks( + self, + symbol: Any | None = None, + interval_unit: Any | None = None, + interval_value: Any | None = None, + adjust_kind: Any | None = None, + since_ts_millis: Any | None = None, + until_ts_millis: Any | None = None, + limit: Any | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """ETFK线. + + Endpoint: ``api/v1/market/data/etf-candlesticks``. + Method: ``POST``. + Documented endpoint: ``etf_candlesticks``. + + Args: + symbol: ETF 代码,如 510300.XSHG、159915.XSHE;也接受 .SH、.SZ 短后缀 (type: string; required: Y). + interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). + interval_value: 间隔数值,默认 1;例如 Minute+5 表示 5 分钟 K 线 (type: int; required: N). + adjust_kind: 复权:None(默认,不复权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳,单位毫秒;分钟 K 线与 until 的跨度 ≤3 天 (type: int(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: int(ms); required: Y). + limit: 返回条数上限;未传 since 和 limit 时默认最多返回 50 根 K 线 (type: int; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = {'symbol': symbol, 'interval_unit': interval_unit, 'interval_value': interval_value, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} + request_params.update(kwargs) + return self._call_endpoint( + 'etf_candlesticks', + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def etf_candlesticks_batch( + self, + symbols: Any | None = None, + interval_unit: Any | None = None, + interval_value: Any | None = None, + adjust_kind: Any | None = None, + since_ts_millis: Any | None = None, + until_ts_millis: Any | None = None, + limit: Any | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """批量ETFK线. + + Endpoint: ``api/v1/market/data/etf-candlesticks/batch``. + Method: ``POST``. + Documented endpoint: ``etf_candlesticks_batch``. + + Args: + symbols: ETF 代码列表,如 ["510300.XSHG","159915.XSHE"];也接受 .SH、.SZ 短后缀 (type: string[]; required: Y). + interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). + interval_value: 间隔数值,默认 1;例如 Minute+5 表示 5 分钟 K 线 (type: int; required: N). + adjust_kind: 复权:None(默认,不复权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳,单位毫秒;分钟 K 线与 until 的跨度 ≤3 天 (type: int(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: int(ms); required: Y). + limit: 每个标的的返回条数上限;未传 since 和 limit 时默认最多返回 50 根 K 线 (type: int; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = {'symbols': symbols, 'interval_unit': interval_unit, 'interval_value': interval_value, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} + request_params.update(kwargs) + return self._call_endpoint( + 'etf_candlesticks_batch', + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + def etf_components( self, symbol: Any | None = None, diff --git a/src/ftshare/apis/index.py b/src/ftshare/apis/index.py index 52fd952..9cd2f15 100644 --- a/src/ftshare/apis/index.py +++ b/src/ftshare/apis/index.py @@ -52,6 +52,104 @@ def global_index_daily_kline( **request_params, ) + def index_candlesticks( + self, + symbol: Any | None = None, + interval_unit: Any | None = None, + interval_value: Any | None = None, + adjust_kind: Any | None = None, + since_ts_millis: Any | None = None, + until_ts_millis: Any | None = None, + limit: Any | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """指数K线. + + Endpoint: ``api/v1/market/data/index-candlesticks``. + Method: ``POST``. + Documented endpoint: ``index_candlesticks``. + + Args: + symbol: 指数代码,如 000300.XSHG、399001.XSHE;也接受 .SH、.SZ 短后缀 (type: string; required: Y). + interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). + interval_value: 间隔数值,默认 1;例如 Minute+5 表示 5 分钟 K 线 (type: int; required: N). + adjust_kind: 复权:None(默认,不复权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳,单位毫秒;分钟 K 线与 until 的跨度 ≤3 天 (type: int(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: int(ms); required: Y). + limit: 返回条数上限;未传 since 和 limit 时默认最多返回 50 根 K 线 (type: int; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = {'symbol': symbol, 'interval_unit': interval_unit, 'interval_value': interval_value, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} + request_params.update(kwargs) + return self._call_endpoint( + 'index_candlesticks', + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def index_candlesticks_batch( + self, + symbols: Any | None = None, + interval_unit: Any | None = None, + interval_value: Any | None = None, + adjust_kind: Any | None = None, + since_ts_millis: Any | None = None, + until_ts_millis: Any | None = None, + limit: Any | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """批量指数K线. + + Endpoint: ``api/v1/market/data/index-candlesticks/batch``. + Method: ``POST``. + Documented endpoint: ``index_candlesticks_batch``. + + Args: + symbols: 指数代码列表,如 ["000300.XSHG","399001.XSHE"];也接受 .SH、.SZ 短后缀 (type: string[]; required: Y). + interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). + interval_value: 间隔数值,默认 1;例如 Minute+5 表示 5 分钟 K 线 (type: int; required: N). + adjust_kind: 复权:None(默认,不复权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳,单位毫秒;分钟 K 线与 until 的跨度 ≤3 天 (type: int(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: int(ms); required: Y). + limit: 每个标的的返回条数上限;未传 since 和 limit 时默认最多返回 50 根 K 线 (type: int; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = {'symbols': symbols, 'interval_unit': interval_unit, 'interval_value': interval_value, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} + request_params.update(kwargs) + return self._call_endpoint( + 'index_candlesticks_batch', + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + def index_description_list( self, page: int | None = None, diff --git a/src/ftshare/apis/stock.py b/src/ftshare/apis/stock.py index 48960d7..b4245b5 100644 --- a/src/ftshare/apis/stock.py +++ b/src/ftshare/apis/stock.py @@ -2672,6 +2672,7 @@ def block_trades( def limit_down_pool( self, + trade_date: Any | None = None, *, raw: bool = False, fields: Sequence[str] | str | None = None, @@ -2685,6 +2686,7 @@ def limit_down_pool( Documented endpoint: ``limit_down_pool``. Args: + trade_date: 交易日期,格式 YYYYMMDD;不传或传当日时查询实时数据 (type: string; required: N). raw: Return the decoded JSON payload without tabular extraction. fields: Optional field list or comma-separated field string applied after extraction. as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. @@ -2695,7 +2697,7 @@ def limit_down_pool( ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page payloads when multi-page fetching is used with ``raw=True``. """ - request_params = {} + request_params = {'trade_date': trade_date} request_params.update(kwargs) return self._call_endpoint( 'limit_down_pool', @@ -2708,6 +2710,7 @@ def limit_down_pool( def limit_event_timeline_3s( self, symbol: Any | None = None, + trade_date: Any | None = None, *, raw: bool = False, fields: Sequence[str] | str | None = None, @@ -2722,6 +2725,7 @@ def limit_event_timeline_3s( Args: symbol: 标的代码,如 000001.XSHE;不传返回全市场 (type: string; required: N). + trade_date: 交易日期,格式 YYYYMMDD;不传或传当日时查询实时数据 (type: string; required: N). raw: Return the decoded JSON payload without tabular extraction. fields: Optional field list or comma-separated field string applied after extraction. as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. @@ -2732,7 +2736,7 @@ def limit_event_timeline_3s( ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page payloads when multi-page fetching is used with ``raw=True``. """ - request_params = {'symbol': symbol} + request_params = {'symbol': symbol, 'trade_date': trade_date} request_params.update(kwargs) return self._call_endpoint( 'limit_event_timeline_3s', @@ -2744,6 +2748,7 @@ def limit_event_timeline_3s( def limit_up_break_pool( self, + trade_date: Any | None = None, *, raw: bool = False, fields: Sequence[str] | str | None = None, @@ -2757,6 +2762,7 @@ def limit_up_break_pool( Documented endpoint: ``limit_up_break_pool``. Args: + trade_date: 交易日期,格式 YYYYMMDD;不传或传当日时查询实时数据 (type: string; required: N). raw: Return the decoded JSON payload without tabular extraction. fields: Optional field list or comma-separated field string applied after extraction. as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. @@ -2767,7 +2773,7 @@ def limit_up_break_pool( ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page payloads when multi-page fetching is used with ``raw=True``. """ - request_params = {} + request_params = {'trade_date': trade_date} request_params.update(kwargs) return self._call_endpoint( 'limit_up_break_pool', @@ -2779,6 +2785,7 @@ def limit_up_break_pool( def limit_up_pool( self, + trade_date: Any | None = None, *, raw: bool = False, fields: Sequence[str] | str | None = None, @@ -2792,6 +2799,7 @@ def limit_up_pool( Documented endpoint: ``limit_up_pool``. Args: + trade_date: 交易日期,格式 YYYYMMDD;不传或传当日时查询实时数据 (type: string; required: N). raw: Return the decoded JSON payload without tabular extraction. fields: Optional field list or comma-separated field string applied after extraction. as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. @@ -2802,7 +2810,7 @@ def limit_up_pool( ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page payloads when multi-page fetching is used with ``raw=True``. """ - request_params = {} + request_params = {'trade_date': trade_date} request_params.update(kwargs) return self._call_endpoint( 'limit_up_pool', @@ -3222,13 +3230,13 @@ def stock_candlesticks( Documented endpoint: ``stock_candlesticks``. Args: - symbol: 标的代码,如 000001.SZ (type: SymbolKey; required: Y). + symbol: 标的代码,如 000001.SZ、600519.XSHG;长短市场后缀均支持 (type: SymbolKey; required: Y). interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). - interval_value: 间隔数值(默认1,如 Day+1=日K,Minute+5=5分钟) (type: int; required: N). - adjust_kind: 复权:None(默认,除权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). - since_ts_millis: 开始时间戳(毫秒);与 until 跨度 ≤3 天 (type: DateTime(ms); required: N). - until_ts_millis: 结束时间戳(毫秒) (type: DateTime(ms); required: Y). - limit: 返回条数上限 (type: int; required: N). + interval_value: 间隔数值(默认 1,如 Day+1=日 K,Minute+5=5 分钟) (type: int; required: N). + adjust_kind: 复权:None(默认,除权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳,单位毫秒;分钟 K 线与 until 跨度 ≤3 天 (type: DateTime(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: DateTime(ms); required: Y). + limit: 返回条数上限;未传 since 和 limit 时默认 50 (type: int; required: N). raw: Return the decoded JSON payload without tabular extraction. fields: Optional field list or comma-separated field string applied after extraction. as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. @@ -3271,13 +3279,13 @@ def stock_candlesticks_batch( Documented endpoint: ``stock_candlesticks_batch``. Args: - symbols: 标的代码列表,如 ["000001.SZ","600000.SH"] (type: array[SymbolKey]; required: Y). + symbols: 标的代码列表,允许股票、ETF、可转债和指数混合,例如 ["600519.SH","510300.SH","113027.SH","000300.SH"] (type: string[]; required: Y). interval_unit: 周期单位:Minute/Day/Week/Month/Year (type: enum; required: Y). - interval_value: 间隔数值(默认1) (type: int; required: N). - adjust_kind: 复权:None(默认)/Forward(前复权)/Backward(后复权) (type: enum; required: N). - since_ts_millis: 开始时间戳(毫秒);与 until 跨度 ≤3 天 (type: DateTime(ms); required: N). - until_ts_millis: 结束时间戳(毫秒) (type: DateTime(ms); required: Y). - limit: 每标的返回条数上限 (type: int; required: N). + interval_value: 间隔数值,默认 1;例如 Minute+5 表示 5 分钟 K 线 (type: int; required: N). + adjust_kind: 复权类型:None(默认)/Forward(前复权)/Backward(后复权) (type: enum; required: N). + since_ts_millis: 开始时间戳;分钟 K 线与 until 的跨度不超过 3 天 (type: int(ms); required: N). + until_ts_millis: 结束时间戳,单位毫秒 (type: int(ms); required: Y). + limit: 每个标的的返回条数上限;未传 since 和 limit 时默认 50 (type: int; required: N). raw: Return the decoded JSON payload without tabular extraction. fields: Optional field list or comma-separated field string applied after extraction. as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. diff --git a/src/ftshare/endpoints/bond.py b/src/ftshare/endpoints/bond.py index d292886..b3ad339 100644 --- a/src/ftshare/endpoints/bond.py +++ b/src/ftshare/endpoints/bond.py @@ -19,4 +19,20 @@ 'doc_file': '可转债列表.md', 'original_api': 'get_cb_lists_handler', }, + 'convertible_bond_candlesticks': { + 'path': 'api/v1/market/data/convertible-bond-candlesticks', + 'title': '可转债K线', + 'doc_file': '可转债K线.md', + 'original_api': 'convertible_bond_candlesticks', + 'method': 'POST', + 'params': ('symbol', 'interval_unit', 'interval_value', 'adjust_kind', 'since_ts_millis', 'until_ts_millis', 'limit'), + }, + 'convertible_bond_candlesticks_batch': { + 'path': 'api/v1/market/data/convertible-bond-candlesticks/batch', + 'title': '批量可转债K线', + 'doc_file': '批量可转债K线.md', + 'original_api': 'convertible_bond_candlesticks_batch', + 'method': 'POST', + 'params': ('symbols', 'interval_unit', 'interval_value', 'adjust_kind', 'since_ts_millis', 'until_ts_millis', 'limit'), + }, }) diff --git a/src/ftshare/endpoints/etf.py b/src/ftshare/endpoints/etf.py index b9ac0c7..3f1f92d 100644 --- a/src/ftshare/endpoints/etf.py +++ b/src/ftshare/endpoints/etf.py @@ -13,6 +13,22 @@ 'original_api': 'etf_adjust_factor', 'params': ('symbol', 'trade_date', 'start_date', 'end_date', 'offset', 'limit'), }, + 'etf_candlesticks': { + 'path': 'api/v1/market/data/etf-candlesticks', + 'title': 'ETFK线', + 'doc_file': 'ETFK线.md', + 'original_api': 'etf_candlesticks', + 'method': 'POST', + 'params': ('symbol', 'interval_unit', 'interval_value', 'adjust_kind', 'since_ts_millis', 'until_ts_millis', 'limit'), + }, + 'etf_candlesticks_batch': { + 'path': 'api/v1/market/data/etf-candlesticks/batch', + 'title': '批量ETFK线', + 'doc_file': '批量ETFK线.md', + 'original_api': 'etf_candlesticks_batch', + 'method': 'POST', + 'params': ('symbols', 'interval_unit', 'interval_value', 'adjust_kind', 'since_ts_millis', 'until_ts_millis', 'limit'), + }, 'etf_components': { 'path': 'api/v1/market/data/etf-component', 'title': 'ETF成份股', diff --git a/src/ftshare/endpoints/index.py b/src/ftshare/endpoints/index.py index f8999d8..c06a02c 100644 --- a/src/ftshare/endpoints/index.py +++ b/src/ftshare/endpoints/index.py @@ -13,6 +13,22 @@ 'original_api': 'global_index_daily_kline', 'params': ('secid', 'start_date', 'end_date'), }, + 'index_candlesticks': { + 'path': 'api/v1/market/data/index-candlesticks', + 'title': '指数K线', + 'doc_file': '指数K线.md', + 'original_api': 'index_candlesticks', + 'method': 'POST', + 'params': ('symbol', 'interval_unit', 'interval_value', 'adjust_kind', 'since_ts_millis', 'until_ts_millis', 'limit'), + }, + 'index_candlesticks_batch': { + 'path': 'api/v1/market/data/index-candlesticks/batch', + 'title': '批量指数K线', + 'doc_file': '批量指数K线.md', + 'original_api': 'index_candlesticks_batch', + 'method': 'POST', + 'params': ('symbols', 'interval_unit', 'interval_value', 'adjust_kind', 'since_ts_millis', 'until_ts_millis', 'limit'), + }, 'index_description_all': { 'path': 'api/v1/market/data/index-description-all', 'title': '指数基础信息', diff --git a/src/ftshare/endpoints/stock.py b/src/ftshare/endpoints/stock.py index 4dddcee..31a3429 100644 --- a/src/ftshare/endpoints/stock.py +++ b/src/ftshare/endpoints/stock.py @@ -206,25 +206,28 @@ 'title': '跌停池', 'doc_file': '跌停池.md', 'original_api': 'limit_down_pool', + 'params': ('trade_date',), }, 'limit_event_timeline_3s': { 'path': 'api/v1/market/data/limit-event-timeline-3s', 'title': '涨跌停事件时间线', 'doc_file': '涨跌停事件时间线.md', 'original_api': 'limit_event_timeline_3s', - 'params': ('symbol',), + 'params': ('symbol', 'trade_date'), }, 'limit_up_break_pool': { 'path': 'api/v1/market/data/limit-up-break-pool', 'title': '炸板池', 'doc_file': '炸板池.md', 'original_api': 'limit_up_break_pool', + 'params': ('trade_date',), }, 'limit_up_pool': { 'path': 'api/v1/market/data/limit-up-pool', 'title': '涨停池', 'doc_file': '涨停池.md', 'original_api': 'limit_up_pool', + 'params': ('trade_date',), }, 'limit_up_pool_yesterday': { 'path': 'api/v1/market/data/limit-up-pool-yesterday', diff --git a/tests/test_client.py b/tests/test_client.py index fb65dc5..0e91daa 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -38,6 +38,17 @@ def get(self, url, params=None, timeout=None, headers=None): ) return self.responses.pop(0) + def post(self, url, json=None, timeout=None, headers=None): + self.calls.append( + { + "url": url, + "json": json, + "timeout": timeout, + "headers": headers, + } + ) + return self.responses.pop(0) + def paginated_records(records, page=1, pages=1): return { @@ -646,3 +657,143 @@ def test_as_dataframe_true_returns_dataframe(): assert list(df.columns) == ["ts_code"] assert df.iloc[0]["ts_code"] == "000001.SZ" + + +def test_etf_candlesticks_posts_json_body_to_candlesticks_path(): + session = FakeSession([FakeResponse(payload=[{"close": "4.5"}])]) + client = FtshareClient(session=session) + + client.etf_candlesticks( + symbol="510300.XSHG", + interval_unit="Day", + until_ts_millis=1756791000000, + limit=5, + as_dataframe=False, + ) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/etf-candlesticks" + assert session.calls[0]["json"] == { + "symbol": "510300.XSHG", + "interval_unit": "Day", + "until_ts_millis": 1756791000000, + "limit": 5, + } + + +def test_etf_candlesticks_batch_posts_symbols_array(): + session = FakeSession([FakeResponse(payload=[["510300.XSHG", []]])]) + client = FtshareClient(session=session) + + client.etf_candlesticks_batch( + symbols=["510300.XSHG", "159915.XSHE"], + interval_unit="Day", + until_ts_millis=1756791000000, + as_dataframe=False, + ) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/etf-candlesticks/batch" + assert session.calls[0]["json"] == { + "symbols": ["510300.XSHG", "159915.XSHE"], + "interval_unit": "Day", + "until_ts_millis": 1756791000000, + } + + +def test_convertible_bond_candlesticks_posts_json_body(): + session = FakeSession([FakeResponse(payload=[{"close": "200"}])]) + client = FtshareClient(session=session) + + client.convertible_bond_candlesticks( + symbol="113027.XSHG", + interval_unit="Day", + until_ts_millis=1756791000000, + as_dataframe=False, + ) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/convertible-bond-candlesticks" + assert session.calls[0]["json"]["symbol"] == "113027.XSHG" + + +def test_convertible_bond_candlesticks_batch_posts_json_body(): + session = FakeSession([FakeResponse(payload=[[]])]) + client = FtshareClient(session=session) + + client.convertible_bond_candlesticks_batch( + symbols=["113027.XSHG", "128048.XSHE"], + interval_unit="Day", + until_ts_millis=1756791000000, + as_dataframe=False, + ) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/convertible-bond-candlesticks/batch" + assert session.calls[0]["json"]["symbols"] == ["113027.XSHG", "128048.XSHE"] + + +def test_index_candlesticks_posts_json_body(): + session = FakeSession([FakeResponse(payload=[{"close": "4500"}])]) + client = FtshareClient(session=session) + + client.index_candlesticks( + symbol="000300.XSHG", + interval_unit="Day", + until_ts_millis=1756791000000, + as_dataframe=False, + ) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/index-candlesticks" + assert session.calls[0]["json"]["symbol"] == "000300.XSHG" + + +def test_index_candlesticks_batch_posts_json_body(): + session = FakeSession([FakeResponse(payload=[[]])]) + client = FtshareClient(session=session) + + client.index_candlesticks_batch( + symbols=["000300.XSHG", "399001.XSHE"], + interval_unit="Day", + until_ts_millis=1756791000000, + as_dataframe=False, + ) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/index-candlesticks/batch" + assert session.calls[0]["json"]["symbols"] == ["000300.XSHG", "399001.XSHE"] + + +def test_limit_up_pool_forwards_trade_date_query_parameter(): + session = FakeSession([FakeResponse(payload=[])]) + client = FtshareClient(session=session) + + client.limit_up_pool(trade_date="20260713", as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/limit-up-pool" + assert session.calls[0]["params"] == {"trade_date": "20260713"} + + +def test_limit_up_break_pool_forwards_trade_date_query_parameter(): + session = FakeSession([FakeResponse(payload=[])]) + client = FtshareClient(session=session) + + client.limit_up_break_pool(trade_date="20260713", as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/limit-up-break-pool" + assert session.calls[0]["params"] == {"trade_date": "20260713"} + + +def test_limit_down_pool_forwards_trade_date_query_parameter(): + session = FakeSession([FakeResponse(payload=[])]) + client = FtshareClient(session=session) + + client.limit_down_pool(trade_date="20260713", as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/limit-down-pool" + assert session.calls[0]["params"] == {"trade_date": "20260713"} + + +def test_limit_event_timeline_3s_forwards_symbol_and_trade_date(): + session = FakeSession([FakeResponse(payload=[])]) + client = FtshareClient(session=session) + + client.limit_event_timeline_3s(symbol="000504.XSHE", trade_date="20260713", as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/limit-event-timeline-3s" + assert session.calls[0]["params"] == {"symbol": "000504.XSHE", "trade_date": "20260713"} From 3a521eee0831fcf7a989478612d309828062994d Mon Sep 17 00:00:00 2001 From: zhuhao Date: Sat, 18 Jul 2026 10:27:48 +0800 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=85=AC?= =?UTF-8?q?=E5=8B=9F=E5=9F=BA=E9=87=91=E6=8E=A5=E5=8F=A3=E5=B9=B6=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E8=82=A1=E7=A5=A8=E6=95=B0=E6=8D=AE=E5=A5=91=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 15 个公募基金 SDK 方法,更新股票筛选、股东、股本及股东增减持接口参数与元数据,并补充 API 文档和单元测试。 --- docs/API_REFERENCE.md | 270 ++++++++++- src/ftshare/apis/fund.py | 842 +++++++++++++++++++++++++++++++++ src/ftshare/apis/stock.py | 16 +- src/ftshare/endpoints/fund.py | 105 ++++ src/ftshare/endpoints/stock.py | 14 +- tests/test_client.py | 195 ++++++++ 6 files changed, 1413 insertions(+), 29 deletions(-) diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index e1cf676..a9551b9 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -6,7 +6,7 @@ | 指标 | 数量 | |---|---:| -| SDK 方法总数 | 186 | +| SDK 方法总数 | 201 | ## 专题分布 @@ -19,7 +19,7 @@ | 美股数据 | 9 | `ftshare.apis.us` | `ftshare.endpoints.us` | | 指数专题 | 10 | `ftshare.apis.index` | `ftshare.endpoints.index` | | ETF专题 | 10 | `ftshare.apis.etf` | `ftshare.endpoints.etf` | -| 公募基金 | 5 | `ftshare.apis.fund` | `ftshare.endpoints.fund` | +| 公募基金 | 20 | `ftshare.apis.fund` | `ftshare.endpoints.fund` | | 期货数据 | 9 | `ftshare.apis.futures` | `ftshare.endpoints.futures` | | 债券专题 | 4 | `ftshare.apis.bond` | `ftshare.endpoints.bond` | | 宏观经济 | 17 | `ftshare.apis.economic` | `ftshare.endpoints.economic` | @@ -104,7 +104,7 @@ df = market.baidu_financial_calendar( | [`stock_comment_focus_em`](#api-stock-comment-focus-em) | 千股千评关注度 | `GET` | `api/v1/market/data/stock-comment/focus` | `symbol` | `千股千评关注度.md` | | [`stock_comment_org_participate_em`](#api-stock-comment-org-participate-em) | 机构参与度 | `GET` | `api/v1/market/data/stock-comment/org-participate` | `symbol` | `机构参与度.md` | | [`stock_comment_score_em`](#api-stock-comment-score-em) | 千股千评评分 | `GET` | `api/v1/market/data/stock-comment/score` | `symbol` | `千股千评评分.md` | -| [`stock_filter`](#api-stock-filter) | 股票筛选 | `GET` | `api/v1/market/data/stock-list/filter` | `board`, `listing_date_since`, `page`, `page_size` | `股票筛选.md` | +| [`stock_filter`](#api-stock-filter) | 股票筛选 | `GET` | `api/v1/market/data/stock-list/filter` | `symbol`, `board`, `listing_date_since`, `page`, `page_size` | `股票筛选.md` | | [`stock_float_holders`](#api-stock-float-holders) | 十大流通股东 | `GET` | `api/v1/market/data/holder/stock-holder-ften` | `stock_code`, `is_last`, `page`, `page_size` | `十大流通股东.md` | | [`stock_ggcg_em`](#api-stock-ggcg-em) | 东方财富股东增减持 | `GET` | `api/v1/market/data/holder/stock-ggcg-em` | `symbol`, `page`, `page_size` | `东方财富股东增减持.md` | | [`stock_ggmx`](#api-stock-ggmx) | 董监高持股变动 | `GET` | `api/v1/market/data/holder/stock-ggmx` | `stock_code`, `change_direction`, `start_date`, `end_date`, `page`, `page_size` | `董监高持股变动.md` | @@ -217,6 +217,21 @@ df = market.baidu_financial_calendar( | [`fund_nav`](#api-fund-nav) | 基金净值 | `GET` | `api/v1/market/data/fund/fund-nav` | `institution_code`, `page`, `page_size` | `基金净值.md` | | [`fund_overview`](#api-fund-overview) | 基金总览 | `GET` | `api/v1/market/data/fund/fund-overview` | `page`, `page_size` | `基金总览.md` | | [`fund_support_symbols`](#api-fund-support-symbols) | 基金支持标的 | `GET` | `api/v1/market/data/fund/fund-support-symbols` | `page`, `page_size` | `基金支持标的.md` | +| [`fund_share`](#api-fund-share) | 基金份额 | `GET` | `api/v1/market/data/fund/fund-share` | `fund_code`, `stati_perd`, `start_date`, `end_date`, `page`, `page_size` | `基金份额.md` | +| [`fund_company`](#api-fund-company) | 基金公司 | `GET` | `api/v1/market/data/fund/fund-company` | `fund_company`, `page`, `page_size` | `基金公司.md` | +| [`fund_net_value_performance`](#api-fund-net-value-performance) | 基金净值收益表现 | `GET` | `api/v1/market/data/fund/fund-net-value-performance` | `fund_code`, `stat_date`, `start_date`, `end_date`, `page`, `page_size` | `基金净值收益表现.md` | +| [`fund_net_value`](#api-fund-net-value) | 基金净值明细 | `GET` | `api/v1/market/data/fund/fund-net-value` | `fund_code`, `nav_date`, `start_date`, `end_date`, `page`, `page_size` | `基金净值明细.md` | +| [`fund_classification`](#api-fund-classification) | 基金分类 | `GET` | `api/v1/market/data/fund/fund-classification` | `fund_code`, `classify_std` | `基金分类.md` | +| [`fund_list`](#api-fund-list) | 基金列表 | `GET` | `api/v1/market/data/fund/fund-list` | `fund_code`, `fund_type`, `page`, `page_size` | `基金列表.md` | +| [`fund_portfolio`](#api-fund-portfolio) | 基金持仓明细 | `GET` | `api/v1/market/data/fund/fund-portfolio` | `fund_code`, `report_date`, `publish_date`, `start_date`, `end_date`, `page`, `page_size` | `基金持仓明细.md` | +| [`fund_holder_structure`](#api-fund-holder-structure) | 基金持有人结构 | `GET` | `api/v1/market/data/fund/fund-holder-structure` | `fund_code`, `report_type`, `start_date`, `end_date` | `基金持有人结构.md` | +| [`fund_new_found`](#api-fund-new-found) | 基金新发 | `GET` | `api/v1/market/data/fund/fund-new-found` | `start_date`, `end_date`, `fund_type`, `page`, `page_size` | `基金新发.md` | +| [`fund_manager`](#api-fund-manager) | 基金经理任职关系 | `GET` | `api/v1/market/data/fund/fund-manager` | `fund_code`, `fund_manager`, `is_inoffice`, `page`, `page_size` | `基金经理任职关系.md` | +| [`fund_daily`](#api-fund-daily) | 基金行情日线 | `GET` | `api/v1/market/data/fund/fund-daily` | `fund_code`, `trade_date`, `start_date`, `end_date`, `page`, `page_size` | `基金行情日线.md` | +| [`fund_fee`](#api-fund-fee) | 基金费率 | `GET` | `api/v1/market/data/fund/fund-fee` | `fund_code`, `charge_type`, `client_type`, `page`, `page_size` | `基金费率.md` | +| [`fund_asset_allocation`](#api-fund-asset-allocation) | 基金资产配置 | `GET` | `api/v1/market/data/fund/fund-asset-allocation` | `fund_code`, `report_date`, `publish_date`, `start_date`, `end_date`, `page`, `page_size` | `基金资产配置.md` | +| [`fund_risk_level`](#api-fund-risk-level) | 基金风险等级 | `GET` | `api/v1/market/data/fund/fund-risk-level` | `fund_code`, `history` | `基金风险等级.md` | +| [`fund_index_fund`](#api-fund-index-fund) | 指数跟踪基金 | `GET` | `api/v1/market/data/fund/index-fund` | `index_code`, `scope` | `指数跟踪基金.md` | ### 期货数据 @@ -2117,14 +2132,14 @@ Returns: - Path:`api/v1/market/data/stock-list/filter` - 参数:`board`, `listing_date_since`, `page`, `page_size` - 来源文档:`股票筛选.md` -- 原始接口:`stock_filter` +- 原始接口:`get_stock_filter` ```text 股票筛选. Endpoint: ``api/v1/market/data/stock-list/filter``. Method: ``GET``. -Documented endpoint: ``stock_filter``. +Documented endpoint: ``get_stock_filter``. Args: board: 板块/交易所筛选:`star` / `chi_next` / `bjse` / `xshg` / `xshe` / `main` (type: string; required: N). @@ -2152,14 +2167,14 @@ Returns: - Path:`api/v1/market/data/holder/stock-holder-ften` - 参数:`stock_code`, `is_last`, `page`, `page_size` - 来源文档:`十大流通股东.md` -- 原始接口:`stock_float_holders` +- 原始接口:`get_stock_holder_float_top10` ```text 十大流通股东. Endpoint: ``api/v1/market/data/holder/stock-holder-ften``. Method: ``GET``. -Documented endpoint: ``stock_float_holders``. +Documented endpoint: ``get_stock_holder_float_top10``. Args: stock_code: 标的代码,指定时返回该标的全部历史数据 (type: string; required: N). @@ -2326,14 +2341,14 @@ Returns: - Path:`api/v1/market/data/holder/stock-holder-ten` - 参数:`stock_code`, `is_last`, `page`, `page_size` - 来源文档:`十大股东.md` -- 原始接口:`stock_holders` +- 原始接口:`get_stock_holder_top10` ```text 十大股东. Endpoint: ``api/v1/market/data/holder/stock-holder-ten``. Method: ``GET``. -Documented endpoint: ``stock_holders``. +Documented endpoint: ``get_stock_holder_top10``. Args: stock_code: 标的代码,指定时返回该标的全部历史数据 (type: string; required: N). @@ -2361,14 +2376,14 @@ Returns: - Path:`api/v1/market/data/holder/stock-holder-nums` - 参数:`stock_code`, `is_last`, `page`, `page_size` - 来源文档:`股东人数.md` -- 原始接口:`stock_holders_number` +- 原始接口:`get_stock_holder_nums` ```text 股东人数. Endpoint: ``api/v1/market/data/holder/stock-holder-nums``. Method: ``GET``. -Documented endpoint: ``stock_holders_number``. +Documented endpoint: ``get_stock_holder_nums``. Args: stock_code: 标的代码,指定时返回该标的全部历史数据 (type: string; required: N). @@ -2967,14 +2982,14 @@ Returns: - Path:`api/v1/market/data/share/get-stock-share` - 参数:`stock_code`, `date` - 来源文档:`股本.md` -- 原始接口:`get_stock_share_handler` +- 原始接口:`get_stock_share` ```text 股本. Endpoint: ``api/v1/market/data/share/get-stock-share``. Method: ``GET``. -Documented endpoint: ``get_stock_share_handler``. +Documented endpoint: ``get_stock_share``. Args: stock_code: 股票代码 (type: string; required: Y). @@ -2997,14 +3012,14 @@ Returns: - Path:`api/v1/market/data/holder/stock-share-chg` - 参数:`stock_code`, `is_last`, `page`, `page_size` - 来源文档:`股东增减持.md` -- 原始接口:`stock_share_chg` +- 原始接口:`get_stock_share_chg` ```text 股东增减持. Endpoint: ``api/v1/market/data/holder/stock-share-chg``. Method: ``GET``. -Documented endpoint: ``stock_share_chg``. +Documented endpoint: ``get_stock_share_chg``. Args: stock_code: 标的代码,指定时返回该标的分页历史数据 (type: string; required: N). @@ -5086,6 +5101,231 @@ Returns: payloads when multi-page fetching is used with ``raw=True``. ``` +

fund_share

+ +- 接口名称:基金份额 +- HTTP:`GET` +- Path:`api/v1/market/data/fund/fund-share` +- 参数:`fund_code`, `stati_perd`, `start_date`, `end_date`, `page`, `page_size` +- 来源文档:`基金份额.md` +- 原始接口:`get_fund_share` + +```text +Endpoint: ``api/v1/market/data/fund/fund-share``. +Method: ``GET``. +Documented endpoint: ``get_fund_share``. +``` + +

fund_company

+ +- 接口名称:基金公司 +- HTTP:`GET` +- Path:`api/v1/market/data/fund/fund-company` +- 参数:`fund_company`, `page`, `page_size` +- 来源文档:`基金公司.md` +- 原始接口:`get_fund_company` + +```text +Endpoint: ``api/v1/market/data/fund/fund-company``. +Method: ``GET``. +Documented endpoint: ``get_fund_company``. +``` + +

fund_net_value_performance

+ +- 接口名称:基金净值收益表现 +- HTTP:`GET` +- Path:`api/v1/market/data/fund/fund-net-value-performance` +- 参数:`fund_code`, `stat_date`, `start_date`, `end_date`, `page`, `page_size` +- 来源文档:`基金净值收益表现.md` +- 原始接口:`get_fund_net_value_performance` + +```text +Endpoint: ``api/v1/market/data/fund/fund-net-value-performance``. +Method: ``GET``. +Documented endpoint: ``get_fund_net_value_performance``. +``` + +

fund_net_value

+ +- 接口名称:基金净值明细 +- HTTP:`GET` +- Path:`api/v1/market/data/fund/fund-net-value` +- 参数:`fund_code`, `nav_date`, `start_date`, `end_date`, `page`, `page_size` +- 来源文档:`基金净值明细.md` +- 原始接口:`get_fund_net_value` + +```text +Endpoint: ``api/v1/market/data/fund/fund-net-value``. +Method: ``GET``. +Documented endpoint: ``get_fund_net_value``. +``` + +

fund_classification

+ +- 接口名称:基金分类 +- HTTP:`GET` +- Path:`api/v1/market/data/fund/fund-classification` +- 参数:`fund_code`, `classify_std` +- 来源文档:`基金分类.md` +- 原始接口:`get_fund_classification` + +```text +Endpoint: ``api/v1/market/data/fund/fund-classification``. +Method: ``GET``. +Documented endpoint: ``get_fund_classification``. +``` + +

fund_list

+ +- 接口名称:基金列表 +- HTTP:`GET` +- Path:`api/v1/market/data/fund/fund-list` +- 参数:`fund_code`, `fund_type`, `page`, `page_size` +- 来源文档:`基金列表.md` +- 原始接口:`get_fund_list` + +```text +Endpoint: ``api/v1/market/data/fund/fund-list``. +Method: ``GET``. +Documented endpoint: ``get_fund_list``. +``` + +

fund_portfolio

+ +- 接口名称:基金持仓明细 +- HTTP:`GET` +- Path:`api/v1/market/data/fund/fund-portfolio` +- 参数:`fund_code`, `report_date`, `publish_date`, `start_date`, `end_date`, `page`, `page_size` +- 来源文档:`基金持仓明细.md` +- 原始接口:`get_fund_portfolio` + +```text +Endpoint: ``api/v1/market/data/fund/fund-portfolio``. +Method: ``GET``. +Documented endpoint: ``get_fund_portfolio``. +``` + +

fund_holder_structure

+ +- 接口名称:基金持有人结构 +- HTTP:`GET` +- Path:`api/v1/market/data/fund/fund-holder-structure` +- 参数:`fund_code`, `report_type`, `start_date`, `end_date` +- 来源文档:`基金持有人结构.md` +- 原始接口:`get_fund_holder_structure` + +```text +Endpoint: ``api/v1/market/data/fund/fund-holder-structure``. +Method: ``GET``. +Documented endpoint: ``get_fund_holder_structure``. +``` + +

fund_new_found

+ +- 接口名称:基金新发 +- HTTP:`GET` +- Path:`api/v1/market/data/fund/fund-new-found` +- 参数:`start_date`, `end_date`, `fund_type`, `page`, `page_size` +- 来源文档:`基金新发.md` +- 原始接口:`get_fund_new_found` + +```text +Endpoint: ``api/v1/market/data/fund/fund-new-found``. +Method: ``GET``. +Documented endpoint: ``get_fund_new_found``. +``` + +

fund_manager

+ +- 接口名称:基金经理任职关系 +- HTTP:`GET` +- Path:`api/v1/market/data/fund/fund-manager` +- 参数:`fund_code`, `fund_manager`, `is_inoffice`, `page`, `page_size` +- 来源文档:`基金经理任职关系.md` +- 原始接口:`get_fund_manager` + +```text +Endpoint: ``api/v1/market/data/fund/fund-manager``. +Method: ``GET``. +Documented endpoint: ``get_fund_manager``. +``` + +

fund_daily

+ +- 接口名称:基金行情日线 +- HTTP:`GET` +- Path:`api/v1/market/data/fund/fund-daily` +- 参数:`fund_code`, `trade_date`, `start_date`, `end_date`, `page`, `page_size` +- 来源文档:`基金行情日线.md` +- 原始接口:`get_fund_daily` + +```text +Endpoint: ``api/v1/market/data/fund/fund-daily``. +Method: ``GET``. +Documented endpoint: ``get_fund_daily``. +``` + +

fund_fee

+ +- 接口名称:基金费率 +- HTTP:`GET` +- Path:`api/v1/market/data/fund/fund-fee` +- 参数:`fund_code`, `charge_type`, `client_type`, `page`, `page_size` +- 来源文档:`基金费率.md` +- 原始接口:`get_fund_fee` + +```text +Endpoint: ``api/v1/market/data/fund/fund-fee``. +Method: ``GET``. +Documented endpoint: ``get_fund_fee``. +``` + +

fund_asset_allocation

+ +- 接口名称:基金资产配置 +- HTTP:`GET` +- Path:`api/v1/market/data/fund/fund-asset-allocation` +- 参数:`fund_code`, `report_date`, `publish_date`, `start_date`, `end_date`, `page`, `page_size` +- 来源文档:`基金资产配置.md` +- 原始接口:`get_fund_asset_allocation` + +```text +Endpoint: ``api/v1/market/data/fund/fund-asset-allocation``. +Method: ``GET``. +Documented endpoint: ``get_fund_asset_allocation``. +``` + +

fund_risk_level

+ +- 接口名称:基金风险等级 +- HTTP:`GET` +- Path:`api/v1/market/data/fund/fund-risk-level` +- 参数:`fund_code`, `history` +- 来源文档:`基金风险等级.md` +- 原始接口:`get_fund_risk_level` + +```text +Endpoint: ``api/v1/market/data/fund/fund-risk-level``. +Method: ``GET``. +Documented endpoint: ``get_fund_risk_level``. +``` + +

fund_index_fund

+ +- 接口名称:指数跟踪基金 +- HTTP:`GET` +- Path:`api/v1/market/data/fund/index-fund` +- 参数:`index_code`, `scope` +- 来源文档:`指数跟踪基金.md` +- 原始接口:`get_fund_index_fund` + +```text +Endpoint: ``api/v1/market/data/fund/index-fund``. +Method: ``GET``. +Documented endpoint: ``get_fund_index_fund``. +``` + ### 期货数据

china_futures_base_data

diff --git a/src/ftshare/apis/fund.py b/src/ftshare/apis/fund.py index 752b2e3..8e83cb1 100644 --- a/src/ftshare/apis/fund.py +++ b/src/ftshare/apis/fund.py @@ -257,3 +257,845 @@ def fund_support_symbols( as_dataframe=as_dataframe, **request_params, ) + + def fund_share( + self, + fund_code: Any | None = None, + stati_perd: Any | None = None, + start_date: Any | None = None, + end_date: Any | None = None, + page: int | None = None, + page_size: int | None = None, + limit: int | None = None, + all_pages: bool = False, + max_pages: int | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """基金份额. + + Endpoint: ``api/v1/market/data/fund/fund-share``. + Method: ``GET``. + Documented endpoint: ``get_fund_share``. + + Args: + fund_code: 基金代码 (type: string; required: Y). + stati_perd: 统计周期:日/季度/年度/截止时点/半年/全部,默认日 (type: string; required: N). + start_date: 开始日期 YYYYMMDD(按 trade_date 过滤) (type: int; required: N). + end_date: 结束日期 YYYYMMDD (type: int; required: N). + page: Page number, starting from 1. If omitted, the server default is used unless ``limit`` or ``all_pages`` is set. + page_size: Rows per page. The SDK validates this against the endpoint-specific maximum. + limit: Maximum number of rows to return. The SDK may fetch multiple pages to satisfy this limit. + all_pages: Fetch and combine pages until the server reports the last page. + max_pages: Optional safety cap for ``all_pages``. + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = { + 'fund_code': fund_code, + 'stati_perd': stati_perd, + 'start_date': start_date, + 'end_date': end_date, + } + request_params.update(kwargs) + path = ENDPOINTS['fund_share'].path + return self.get_paginated( + path, + page=page, + page_size=page_size, + limit=limit, + all_pages=all_pages, + max_pages=max_pages, + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def fund_company( + self, + fund_company: Any | None = None, + page: int | None = None, + page_size: int | None = None, + limit: int | None = None, + all_pages: bool = False, + max_pages: int | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """基金公司. + + Endpoint: ``api/v1/market/data/fund/fund-company``. + Method: ``GET``. + Documented endpoint: ``get_fund_company``. + + Args: + fund_company: 基金公司名称,精确匹配 (type: string; required: N). + page: Page number, starting from 1. If omitted, the server default is used unless ``limit`` or ``all_pages`` is set. + page_size: Rows per page. The SDK validates this against the endpoint-specific maximum. + limit: Maximum number of rows to return. The SDK may fetch multiple pages to satisfy this limit. + all_pages: Fetch and combine pages until the server reports the last page. + max_pages: Optional safety cap for ``all_pages``. + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = {'fund_company': fund_company} + request_params.update(kwargs) + path = ENDPOINTS['fund_company'].path + return self.get_paginated( + path, + page=page, + page_size=page_size, + limit=limit, + all_pages=all_pages, + max_pages=max_pages, + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def fund_net_value_performance( + self, + fund_code: Any | None = None, + stat_date: Any | None = None, + start_date: Any | None = None, + end_date: Any | None = None, + page: int | None = None, + page_size: int | None = None, + limit: int | None = None, + all_pages: bool = False, + max_pages: int | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """基金净值收益表现. + + Endpoint: ``api/v1/market/data/fund/fund-net-value-performance``. + Method: ``GET``. + Documented endpoint: ``get_fund_net_value_performance``. + + Args: + fund_code: 基金代码 (type: string; required: Y). + stat_date: 统计日期 YYYYMMDD(与 start/end 互斥) (type: int; required: N). + start_date: 统计开始日期(需与 end_date 同传) (type: int; required: N). + end_date: 统计结束日期 (type: int; required: N). + page: Page number, starting from 1. If omitted, the server default is used unless ``limit`` or ``all_pages`` is set. + page_size: Rows per page. The SDK validates this against the endpoint-specific maximum. + limit: Maximum number of rows to return. The SDK may fetch multiple pages to satisfy this limit. + all_pages: Fetch and combine pages until the server reports the last page. + max_pages: Optional safety cap for ``all_pages``. + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = { + 'fund_code': fund_code, + 'stat_date': stat_date, + 'start_date': start_date, + 'end_date': end_date, + } + request_params.update(kwargs) + path = ENDPOINTS['fund_net_value_performance'].path + return self.get_paginated( + path, + page=page, + page_size=page_size, + limit=limit, + all_pages=all_pages, + max_pages=max_pages, + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def fund_net_value( + self, + fund_code: Any | None = None, + nav_date: Any | None = None, + start_date: Any | None = None, + end_date: Any | None = None, + page: int | None = None, + page_size: int | None = None, + limit: int | None = None, + all_pages: bool = False, + max_pages: int | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """基金净值明细. + + Endpoint: ``api/v1/market/data/fund/fund-net-value``. + Method: ``GET``. + Documented endpoint: ``get_fund_net_value``. + + Args: + fund_code: 基金代码 (type: string; required: Y). + nav_date: 净值日期 YYYYMMDD(与 start/end 互斥) (type: int; required: N). + start_date: 净值开始日期 YYYYMMDD(需与 end_date 同传) (type: int; required: N). + end_date: 净值结束日期 YYYYMMDD (type: int; required: N). + page: Page number, starting from 1. If omitted, the server default is used unless ``limit`` or ``all_pages`` is set. + page_size: Rows per page. The SDK validates this against the endpoint-specific maximum. + limit: Maximum number of rows to return. The SDK may fetch multiple pages to satisfy this limit. + all_pages: Fetch and combine pages until the server reports the last page. + max_pages: Optional safety cap for ``all_pages``. + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = { + 'fund_code': fund_code, + 'nav_date': nav_date, + 'start_date': start_date, + 'end_date': end_date, + } + request_params.update(kwargs) + path = ENDPOINTS['fund_net_value'].path + return self.get_paginated( + path, + page=page, + page_size=page_size, + limit=limit, + all_pages=all_pages, + max_pages=max_pages, + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def fund_classification( + self, + fund_code: Any | None = None, + classify_std: Any | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """基金分类. + + Endpoint: ``api/v1/market/data/fund/fund-classification``. + Method: ``GET``. + Documented endpoint: ``get_fund_classification``. + + Args: + fund_code: 基金代码 (type: string; required: Y). + classify_std: 分类标准:证监会基金分类/晨星基金分类/银河证券分类2017版/Gangtise基金分类/Gangtise基金概念分类,缺省全部 (type: string; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``. + """ + request_params = {'fund_code': fund_code, 'classify_std': classify_std} + request_params.update(kwargs) + return self._call_endpoint( + 'fund_classification', + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def fund_list( + self, + fund_code: Any | None = None, + fund_type: Any | None = None, + page: int | None = None, + page_size: int | None = None, + limit: int | None = None, + all_pages: bool = False, + max_pages: int | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """基金列表. + + Endpoint: ``api/v1/market/data/fund/fund-list``. + Method: ``GET``. + Documented endpoint: ``get_fund_list``. + + Args: + fund_code: 基金代码 (type: string; required: N). + fund_type: 基金类型,精确匹配(股票型/混合型/债券型/货币型/保本型/其他型/REITs) (type: string; required: N). + page: Page number, starting from 1. If omitted, the server default is used unless ``limit`` or ``all_pages`` is set. + page_size: Rows per page. The SDK validates this against the endpoint-specific maximum. + limit: Maximum number of rows to return. The SDK may fetch multiple pages to satisfy this limit. + all_pages: Fetch and combine pages until the server reports the last page. + max_pages: Optional safety cap for ``all_pages``. + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = {'fund_code': fund_code, 'fund_type': fund_type} + request_params.update(kwargs) + path = ENDPOINTS['fund_list'].path + return self.get_paginated( + path, + page=page, + page_size=page_size, + limit=limit, + all_pages=all_pages, + max_pages=max_pages, + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def fund_portfolio( + self, + fund_code: Any | None = None, + report_date: Any | None = None, + publish_date: Any | None = None, + start_date: Any | None = None, + end_date: Any | None = None, + page: int | None = None, + page_size: int | None = None, + limit: int | None = None, + all_pages: bool = False, + max_pages: int | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """基金持仓明细. + + Endpoint: ``api/v1/market/data/fund/fund-portfolio``. + Method: ``GET``. + Documented endpoint: ``get_fund_portfolio``. + + Args: + fund_code: 基金代码 (type: string; required: Y). + report_date: 报告期 YYYYMMDD(与 start/end 互斥) (type: int; required: N). + publish_date: 发布日期 YYYYMMDD (type: int; required: N). + start_date: 报告期起始日期(需与 end_date 同传) (type: int; required: N). + end_date: 报告期结束日期 (type: int; required: N). + page: Page number, starting from 1. If omitted, the server default is used unless ``limit`` or ``all_pages`` is set. + page_size: Rows per page. The SDK validates this against the endpoint-specific maximum. + limit: Maximum number of rows to return. The SDK may fetch multiple pages to satisfy this limit. + all_pages: Fetch and combine pages until the server reports the last page. + max_pages: Optional safety cap for ``all_pages``. + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = { + 'fund_code': fund_code, + 'report_date': report_date, + 'publish_date': publish_date, + 'start_date': start_date, + 'end_date': end_date, + } + request_params.update(kwargs) + path = ENDPOINTS['fund_portfolio'].path + return self.get_paginated( + path, + page=page, + page_size=page_size, + limit=limit, + all_pages=all_pages, + max_pages=max_pages, + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def fund_holder_structure( + self, + fund_code: Any | None = None, + report_type: Any | None = None, + start_date: Any | None = None, + end_date: Any | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """基金持有人结构. + + Endpoint: ``api/v1/market/data/fund/fund-holder-structure``. + Method: ``GET``. + Documented endpoint: ``get_fund_holder_structure``. + + Args: + fund_code: 基金代码 (type: string; required: Y). + report_type: 报告类型:年度报告/中期报告/上市公告书/基金合同生效公告,缺省全部 (type: string; required: N). + start_date: 报告期起始日期 YYYYMMDD (type: int; required: N). + end_date: 报告期截止日期 YYYYMMDD (type: int; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``. + """ + request_params = { + 'fund_code': fund_code, + 'report_type': report_type, + 'start_date': start_date, + 'end_date': end_date, + } + request_params.update(kwargs) + return self._call_endpoint( + 'fund_holder_structure', + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def fund_new_found( + self, + start_date: Any | None = None, + end_date: Any | None = None, + fund_type: Any | None = None, + page: int | None = None, + page_size: int | None = None, + limit: int | None = None, + all_pages: bool = False, + max_pages: int | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """基金新发. + + Endpoint: ``api/v1/market/data/fund/fund-new-found``. + Method: ``GET``. + Documented endpoint: ``get_fund_new_found``. + + Args: + start_date: 成立日起始日期 YYYYMMDD(不传默认近 1 年) (type: int; required: N). + end_date: 成立日截止日期 YYYYMMDD(不传默认今天) (type: int; required: N). + fund_type: 基金类型过滤:混合型/债券型/股票型/货币型/其他型/保本型/REITs (type: string; required: N). + page: Page number, starting from 1. If omitted, the server default is used unless ``limit`` or ``all_pages`` is set. + page_size: Rows per page. The SDK validates this against the endpoint-specific maximum. + limit: Maximum number of rows to return. The SDK may fetch multiple pages to satisfy this limit. + all_pages: Fetch and combine pages until the server reports the last page. + max_pages: Optional safety cap for ``all_pages``. + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = { + 'start_date': start_date, + 'end_date': end_date, + 'fund_type': fund_type, + } + request_params.update(kwargs) + path = ENDPOINTS['fund_new_found'].path + return self.get_paginated( + path, + page=page, + page_size=page_size, + limit=limit, + all_pages=all_pages, + max_pages=max_pages, + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def fund_manager( + self, + fund_code: Any | None = None, + fund_manager: Any | None = None, + is_inoffice: Any | None = None, + page: int | None = None, + page_size: int | None = None, + limit: int | None = None, + all_pages: bool = False, + max_pages: int | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """基金经理任职关系. + + Endpoint: ``api/v1/market/data/fund/fund-manager``. + Method: ``GET``. + Documented endpoint: ``get_fund_manager``. + + Args: + fund_code: 基金代码(与 fund_manager 二选一) (type: string; required: N). + fund_manager: 基金经理姓名(与 fund_code 二选一) (type: string; required: N). + is_inoffice: 1 在任 / 0 离任 (type: string; required: N). + page: Page number, starting from 1. If omitted, the server default is used unless ``limit`` or ``all_pages`` is set. + page_size: Rows per page. The SDK validates this against the endpoint-specific maximum. + limit: Maximum number of rows to return. The SDK may fetch multiple pages to satisfy this limit. + all_pages: Fetch and combine pages until the server reports the last page. + max_pages: Optional safety cap for ``all_pages``. + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = { + 'fund_code': fund_code, + 'fund_manager': fund_manager, + 'is_inoffice': is_inoffice, + } + request_params.update(kwargs) + path = ENDPOINTS['fund_manager'].path + return self.get_paginated( + path, + page=page, + page_size=page_size, + limit=limit, + all_pages=all_pages, + max_pages=max_pages, + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def fund_daily( + self, + fund_code: Any | None = None, + trade_date: Any | None = None, + start_date: Any | None = None, + end_date: Any | None = None, + page: int | None = None, + page_size: int | None = None, + limit: int | None = None, + all_pages: bool = False, + max_pages: int | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """基金行情日线. + + Endpoint: ``api/v1/market/data/fund/fund-daily``. + Method: ``GET``. + Documented endpoint: ``get_fund_daily``. + + Args: + fund_code: 基金代码 (type: string; required: Y). + trade_date: 交易日期 YYYYMMDD(与 start/end 互斥) (type: string; required: N). + start_date: 起始日期 YYYYMMDD(需与 end_date 同传) (type: string; required: N). + end_date: 结束日期 YYYYMMDD (type: string; required: N). + page: Page number, starting from 1. If omitted, the server default is used unless ``limit`` or ``all_pages`` is set. + page_size: Rows per page. The SDK validates this against the endpoint-specific maximum. + limit: Maximum number of rows to return. The SDK may fetch multiple pages to satisfy this limit. + all_pages: Fetch and combine pages until the server reports the last page. + max_pages: Optional safety cap for ``all_pages``. + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = { + 'fund_code': fund_code, + 'trade_date': trade_date, + 'start_date': start_date, + 'end_date': end_date, + } + request_params.update(kwargs) + path = ENDPOINTS['fund_daily'].path + return self.get_paginated( + path, + page=page, + page_size=page_size, + limit=limit, + all_pages=all_pages, + max_pages=max_pages, + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def fund_fee( + self, + fund_code: Any | None = None, + charge_type: Any | None = None, + client_type: Any | None = None, + page: int | None = None, + page_size: int | None = None, + limit: int | None = None, + all_pages: bool = False, + max_pages: int | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """基金费率. + + Endpoint: ``api/v1/market/data/fund/fund-fee``. + Method: ``GET``. + Documented endpoint: ``get_fund_fee``. + + Args: + fund_code: 基金代码 (type: string; required: Y). + charge_type: 费率类型:日常申购费/日常赎回费/认购费/管理费/托管费/销售服务费 (type: string; required: N). + client_type: 客户类型:一般/机构/养老金/REITs (type: string; required: N). + page: Page number, starting from 1. If omitted, the server default is used unless ``limit`` or ``all_pages`` is set. + page_size: Rows per page. The SDK validates this against the endpoint-specific maximum. + limit: Maximum number of rows to return. The SDK may fetch multiple pages to satisfy this limit. + all_pages: Fetch and combine pages until the server reports the last page. + max_pages: Optional safety cap for ``all_pages``. + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = { + 'fund_code': fund_code, + 'charge_type': charge_type, + 'client_type': client_type, + } + request_params.update(kwargs) + path = ENDPOINTS['fund_fee'].path + return self.get_paginated( + path, + page=page, + page_size=page_size, + limit=limit, + all_pages=all_pages, + max_pages=max_pages, + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def fund_asset_allocation( + self, + fund_code: Any | None = None, + report_date: Any | None = None, + publish_date: Any | None = None, + start_date: Any | None = None, + end_date: Any | None = None, + page: int | None = None, + page_size: int | None = None, + limit: int | None = None, + all_pages: bool = False, + max_pages: int | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """基金资产配置. + + Endpoint: ``api/v1/market/data/fund/fund-asset-allocation``. + Method: ``GET``. + Documented endpoint: ``get_fund_asset_allocation``. + + Args: + fund_code: 基金代码 (type: string; required: Y). + report_date: 报告期 YYYYMMDD(与 start/end 互斥) (type: int; required: N). + publish_date: 发布日期 YYYYMMDD (type: int; required: N). + start_date: 报告期起始日期(需与 end_date 同传) (type: int; required: N). + end_date: 报告期结束日期 (type: int; required: N). + page: Page number, starting from 1. If omitted, the server default is used unless ``limit`` or ``all_pages`` is set. + page_size: Rows per page. The SDK validates this against the endpoint-specific maximum. + limit: Maximum number of rows to return. The SDK may fetch multiple pages to satisfy this limit. + all_pages: Fetch and combine pages until the server reports the last page. + max_pages: Optional safety cap for ``all_pages``. + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page + payloads when multi-page fetching is used with ``raw=True``. + """ + request_params = { + 'fund_code': fund_code, + 'report_date': report_date, + 'publish_date': publish_date, + 'start_date': start_date, + 'end_date': end_date, + } + request_params.update(kwargs) + path = ENDPOINTS['fund_asset_allocation'].path + return self.get_paginated( + path, + page=page, + page_size=page_size, + limit=limit, + all_pages=all_pages, + max_pages=max_pages, + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def fund_risk_level( + self, + fund_code: Any | None = None, + history: Any | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """基金风险等级. + + Endpoint: ``api/v1/market/data/fund/fund-risk-level``. + Method: ``GET``. + Documented endpoint: ``get_fund_risk_level``. + + Args: + fund_code: 基金代码 (type: string; required: Y). + history: true 返回全部变更历史,缺省/false 仅当前有效 (type: bool; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``. + """ + request_params = {'fund_code': fund_code, 'history': history} + request_params.update(kwargs) + return self._call_endpoint( + 'fund_risk_level', + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) + + def fund_index_fund( + self, + index_code: Any | None = None, + scope: Any | None = None, + *, + raw: bool = False, + fields: Sequence[str] | str | None = None, + as_dataframe: bool = True, + **kwargs: Any, + ) -> Any: + """指数跟踪基金. + + Endpoint: ``api/v1/market/data/fund/index-fund``. + Method: ``GET``. + Documented endpoint: ``get_fund_index_fund``. + + Args: + index_code: 指数代码,支持裸码或带后缀 (type: string; required: Y). + scope: `all` 全市场(默认)/ `etf` 仅场内 ETF (type: string; required: N). + raw: Return the decoded JSON payload without tabular extraction. + fields: Optional field list or comma-separated field string applied after extraction. + as_dataframe: Return a pandas ``DataFrame`` by default; set to ``False`` for Python rows. + **kwargs: Extra request parameters forwarded unchanged. Useful when the service adds parameters before the SDK is regenerated. + + Returns: + A pandas ``DataFrame`` by default, Python rows when + ``as_dataframe=False``, raw JSON when ``raw=True``. + """ + request_params = {'index_code': index_code, 'scope': scope} + request_params.update(kwargs) + return self._call_endpoint( + 'fund_index_fund', + raw=raw, + fields=fields, + as_dataframe=as_dataframe, + **request_params, + ) diff --git a/src/ftshare/apis/stock.py b/src/ftshare/apis/stock.py index b4245b5..3c20c86 100644 --- a/src/ftshare/apis/stock.py +++ b/src/ftshare/apis/stock.py @@ -668,7 +668,7 @@ def stock_float_holders( Endpoint: ``api/v1/market/data/holder/stock-holder-ften``. Method: ``GET``. - Documented endpoint: ``stock_float_holders``. + Documented endpoint: ``get_stock_holder_float_top10``. Args: stock_code: 标的代码,指定时返回该标的全部历史数据 (type: string; required: N). @@ -941,7 +941,7 @@ def stock_holders( Endpoint: ``api/v1/market/data/holder/stock-holder-ten``. Method: ``GET``. - Documented endpoint: ``stock_holders``. + Documented endpoint: ``get_stock_holder_top10``. Args: stock_code: 标的代码,指定时返回该标的全部历史数据 (type: string; required: N). @@ -996,7 +996,7 @@ def stock_holders_number( Endpoint: ``api/v1/market/data/holder/stock-holder-nums``. Method: ``GET``. - Documented endpoint: ``stock_holders_number``. + Documented endpoint: ``get_stock_holder_nums``. Args: stock_code: 标的代码,指定时返回该标的全部历史数据 (type: string; required: N). @@ -1051,7 +1051,7 @@ def stock_share_chg( Endpoint: ``api/v1/market/data/holder/stock-share-chg``. Method: ``GET``. - Documented endpoint: ``stock_share_chg``. + Documented endpoint: ``get_stock_share_chg``. Args: stock_code: 标的代码,指定时返回该标的分页历史数据 (type: string; required: N). @@ -3613,6 +3613,7 @@ def stock_comment_score_em( def stock_filter( self, + symbol: Any | None = None, board: Any | None = None, listing_date_since: Any | None = None, page: int | None = None, @@ -3630,9 +3631,10 @@ def stock_filter( Endpoint: ``api/v1/market/data/stock-list/filter``. Method: ``GET``. - Documented endpoint: ``stock_filter``. + Documented endpoint: ``get_stock_filter``. Args: + symbol: 单标的代码(如 `600519`、`600519.SH`、`600519.XSHG`);传入后忽略 board 与 listing_date_since (type: string; required: N). board: 板块/交易所筛选:`star` / `chi_next` / `bjse` / `xshg` / `xshe` / `main` (type: string; required: N). listing_date_since: 上市日期起点 YYYYMMDD,筛选此后上市的股票 (type: string; required: N). page: Page number, starting from 1. If omitted, the server default is used unless ``limit`` or ``all_pages`` is set. @@ -3650,7 +3652,7 @@ def stock_filter( ``as_dataframe=False``, raw JSON when ``raw=True``, or raw page payloads when multi-page fetching is used with ``raw=True``. """ - request_params = {'board': board, 'listing_date_since': listing_date_since} + request_params = {'symbol': symbol, 'board': board, 'listing_date_since': listing_date_since} request_params.update(kwargs) path = ENDPOINTS['stock_filter'].path return self.get_paginated( @@ -4460,7 +4462,7 @@ def stock_share( Endpoint: ``api/v1/market/data/share/get-stock-share``. Method: ``GET``. - Documented endpoint: ``get_stock_share_handler``. + Documented endpoint: ``get_stock_share``. Args: stock_code: 股票代码 (type: string; required: Y). diff --git a/src/ftshare/endpoints/fund.py b/src/ftshare/endpoints/fund.py index 79dcdc6..132e7e1 100644 --- a/src/ftshare/endpoints/fund.py +++ b/src/ftshare/endpoints/fund.py @@ -41,4 +41,109 @@ 'original_api': 'get_fund_support_symbols', 'params': ('page', 'page_size'), }, + 'fund_share': { + 'path': 'api/v1/market/data/fund/fund-share', + 'title': '基金份额', + 'doc_file': '基金份额.md', + 'original_api': 'get_fund_share', + 'params': ('fund_code', 'stati_perd', 'start_date', 'end_date', 'page', 'page_size'), + }, + 'fund_company': { + 'path': 'api/v1/market/data/fund/fund-company', + 'title': '基金公司', + 'doc_file': '基金公司.md', + 'original_api': 'get_fund_company', + 'params': ('fund_company', 'page', 'page_size'), + }, + 'fund_net_value_performance': { + 'path': 'api/v1/market/data/fund/fund-net-value-performance', + 'title': '基金净值收益表现', + 'doc_file': '基金净值收益表现.md', + 'original_api': 'get_fund_net_value_performance', + 'params': ('fund_code', 'stat_date', 'start_date', 'end_date', 'page', 'page_size'), + }, + 'fund_net_value': { + 'path': 'api/v1/market/data/fund/fund-net-value', + 'title': '基金净值明细', + 'doc_file': '基金净值明细.md', + 'original_api': 'get_fund_net_value', + 'params': ('fund_code', 'nav_date', 'start_date', 'end_date', 'page', 'page_size'), + }, + 'fund_classification': { + 'path': 'api/v1/market/data/fund/fund-classification', + 'title': '基金分类', + 'doc_file': '基金分类.md', + 'original_api': 'get_fund_classification', + 'params': ('fund_code', 'classify_std'), + }, + 'fund_list': { + 'path': 'api/v1/market/data/fund/fund-list', + 'title': '基金列表', + 'doc_file': '基金列表.md', + 'original_api': 'get_fund_list', + 'params': ('fund_code', 'fund_type', 'page', 'page_size'), + }, + 'fund_portfolio': { + 'path': 'api/v1/market/data/fund/fund-portfolio', + 'title': '基金持仓明细', + 'doc_file': '基金持仓明细.md', + 'original_api': 'get_fund_portfolio', + 'params': ('fund_code', 'report_date', 'publish_date', 'start_date', 'end_date', 'page', 'page_size'), + }, + 'fund_holder_structure': { + 'path': 'api/v1/market/data/fund/fund-holder-structure', + 'title': '基金持有人结构', + 'doc_file': '基金持有人结构.md', + 'original_api': 'get_fund_holder_structure', + 'params': ('fund_code', 'report_type', 'start_date', 'end_date'), + }, + 'fund_new_found': { + 'path': 'api/v1/market/data/fund/fund-new-found', + 'title': '基金新发', + 'doc_file': '基金新发.md', + 'original_api': 'get_fund_new_found', + 'params': ('start_date', 'end_date', 'fund_type', 'page', 'page_size'), + }, + 'fund_manager': { + 'path': 'api/v1/market/data/fund/fund-manager', + 'title': '基金经理任职关系', + 'doc_file': '基金经理任职关系.md', + 'original_api': 'get_fund_manager', + 'params': ('fund_code', 'fund_manager', 'is_inoffice', 'page', 'page_size'), + }, + 'fund_daily': { + 'path': 'api/v1/market/data/fund/fund-daily', + 'title': '基金行情日线', + 'doc_file': '基金行情日线.md', + 'original_api': 'get_fund_daily', + 'params': ('fund_code', 'trade_date', 'start_date', 'end_date', 'page', 'page_size'), + }, + 'fund_fee': { + 'path': 'api/v1/market/data/fund/fund-fee', + 'title': '基金费率', + 'doc_file': '基金费率.md', + 'original_api': 'get_fund_fee', + 'params': ('fund_code', 'charge_type', 'client_type', 'page', 'page_size'), + }, + 'fund_asset_allocation': { + 'path': 'api/v1/market/data/fund/fund-asset-allocation', + 'title': '基金资产配置', + 'doc_file': '基金资产配置.md', + 'original_api': 'get_fund_asset_allocation', + 'params': ('fund_code', 'report_date', 'publish_date', 'start_date', 'end_date', 'page', 'page_size'), + }, + 'fund_risk_level': { + 'path': 'api/v1/market/data/fund/fund-risk-level', + 'title': '基金风险等级', + 'doc_file': '基金风险等级.md', + 'original_api': 'get_fund_risk_level', + 'params': ('fund_code', 'history'), + }, + 'fund_index_fund': { + 'path': 'api/v1/market/data/fund/index-fund', + 'title': '指数跟踪基金', + 'doc_file': '指数跟踪基金.md', + 'original_api': 'get_fund_index_fund', + 'params': ('index_code', 'scope'), + }, }) diff --git a/src/ftshare/endpoints/stock.py b/src/ftshare/endpoints/stock.py index 31a3429..436ae6e 100644 --- a/src/ftshare/endpoints/stock.py +++ b/src/ftshare/endpoints/stock.py @@ -405,14 +405,14 @@ 'path': 'api/v1/market/data/stock-list/filter', 'title': '股票筛选', 'doc_file': '股票筛选.md', - 'original_api': 'stock_filter', - 'params': ('board', 'listing_date_since', 'page', 'page_size'), + 'original_api': 'get_stock_filter', + 'params': ('symbol', 'board', 'listing_date_since', 'page', 'page_size'), }, 'stock_float_holders': { 'path': 'api/v1/market/data/holder/stock-holder-ften', 'title': '十大流通股东', 'doc_file': '十大流通股东.md', - 'original_api': 'stock_float_holders', + 'original_api': 'get_stock_holder_float_top10', 'params': ('stock_code', 'is_last', 'page', 'page_size'), }, 'stock_ggcg_em': { @@ -447,14 +447,14 @@ 'path': 'api/v1/market/data/holder/stock-holder-ten', 'title': '十大股东', 'doc_file': '十大股东.md', - 'original_api': 'stock_holders', + 'original_api': 'get_stock_holder_top10', 'params': ('stock_code', 'is_last', 'page', 'page_size'), }, 'stock_holders_number': { 'path': 'api/v1/market/data/holder/stock-holder-nums', 'title': '股东人数', 'doc_file': '股东人数.md', - 'original_api': 'stock_holders_number', + 'original_api': 'get_stock_holder_nums', 'params': ('stock_code', 'is_last', 'page', 'page_size'), }, 'stock_institution_holdings': { @@ -581,14 +581,14 @@ 'path': 'api/v1/market/data/share/get-stock-share', 'title': '股本', 'doc_file': '股本.md', - 'original_api': 'get_stock_share_handler', + 'original_api': 'get_stock_share', 'params': ('stock_code', 'date'), }, 'stock_share_chg': { 'path': 'api/v1/market/data/holder/stock-share-chg', 'title': '股东增减持', 'doc_file': '股东增减持.md', - 'original_api': 'stock_share_chg', + 'original_api': 'get_stock_share_chg', 'params': ('stock_code', 'is_last', 'page', 'page_size'), }, 'stock_signal_latest_snapshot': { diff --git a/tests/test_client.py b/tests/test_client.py index 0e91daa..4e5b06d 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -797,3 +797,198 @@ def test_limit_event_timeline_3s_forwards_symbol_and_trade_date(): assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/limit-event-timeline-3s" assert session.calls[0]["params"] == {"symbol": "000504.XSHE", "trade_date": "20260713"} + + +def test_stock_filter_forwards_symbol_param(): + session = FakeSession([FakeResponse(payload={"items": [], "total_pages": 0, "total_items": 0})]) + client = FtshareClient(session=session) + + client.stock_filter(symbol="600519.SH", page=1, page_size=5, as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/stock-list/filter" + assert session.calls[0]["params"]["symbol"] == "600519.SH" + assert "board" not in session.calls[0]["params"] + assert "listing_date_since" not in session.calls[0]["params"] + + +def test_stock_float_holders_forwards_is_last_paging(): + session = FakeSession([FakeResponse(payload={"items": [], "total_pages": 0, "total_items": 0})]) + client = FtshareClient(session=session) + + client.stock_float_holders(is_last=True, page=1, page_size=5, as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/holder/stock-holder-ften" + assert session.calls[0]["params"]["is_last"] is True + + +def test_stock_share_chg_forwards_is_last_paging(): + session = FakeSession([FakeResponse(payload={"items": [], "total_pages": 0, "total_items": 0})]) + client = FtshareClient(session=session) + + client.stock_share_chg(is_last=True, page=1, page_size=5, as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/holder/stock-share-chg" + assert session.calls[0]["params"]["is_last"] is True + + +def test_fund_share_forwards_paginated_params(): + session = FakeSession([FakeResponse(payload={"items": [], "total_pages": 0, "total_items": 0})]) + client = FtshareClient(session=session) + + client.fund_share(fund_code="000001", stati_perd="日", start_date=20260101, end_date=20260717, + page=1, page_size=50, as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/fund-share" + assert session.calls[0]["params"] == { + "fund_code": "000001", + "stati_perd": "日", + "start_date": 20260101, + "end_date": 20260717, + "page": 1, + "page_size": 50, + } + + +def test_fund_company_paginated_filter(): + session = FakeSession([FakeResponse(payload={"items": [], "total_pages": 0, "total_items": 0})]) + client = FtshareClient(session=session) + + client.fund_company(fund_company="华夏基金", page=1, page_size=50, as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/fund-company" + assert session.calls[0]["params"]["fund_company"] == "华夏基金" + + +def test_fund_net_value_performance_interval_params(): + session = FakeSession([FakeResponse(payload={"items": [], "total_pages": 0, "total_items": 0})]) + client = FtshareClient(session=session) + + client.fund_net_value_performance(fund_code="000001", start_date=20260101, end_date=20260717, + page=1, page_size=50, as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/fund-net-value-performance" + assert session.calls[0]["params"]["start_date"] == 20260101 + + +def test_fund_net_value_paginated(): + session = FakeSession([FakeResponse(payload={"items": [], "total_pages": 0, "total_items": 0})]) + client = FtshareClient(session=session) + + client.fund_net_value(fund_code="000001", nav_date=20260717, page=1, page_size=50, as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/fund-net-value" + assert session.calls[0]["params"]["nav_date"] == 20260717 + + +def test_fund_classification_single_object(): + session = FakeSession([FakeResponse(payload={"fund_code": "000001", "fund_name": "华夏成长", + "classifications": {}})]) + client = FtshareClient(session=session) + + client.fund_classification(fund_code="000001", as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/fund-classification" + assert session.calls[0]["params"]["fund_code"] == "000001" + + +def test_fund_list_paginated_filter(): + session = FakeSession([FakeResponse(payload={"items": [], "total_pages": 0, "total_items": 0})]) + client = FtshareClient(session=session) + + client.fund_list(fund_type="股票型", page=1, page_size=50, as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/fund-list" + assert session.calls[0]["params"]["fund_type"] == "股票型" + + +def test_fund_portfolio_paginated(): + session = FakeSession([FakeResponse(payload={"items": [], "total_pages": 0, "total_items": 0})]) + client = FtshareClient(session=session) + + client.fund_portfolio(fund_code="000001", report_date=20260331, page=1, page_size=50, as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/fund-portfolio" + assert session.calls[0]["params"]["report_date"] == 20260331 + + +def test_fund_holder_structure_array_response(): + session = FakeSession([FakeResponse(payload=[])]) + client = FtshareClient(session=session) + + client.fund_holder_structure(fund_code="000001", as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/fund-holder-structure" + assert session.calls[0]["params"]["fund_code"] == "000001" + + +def test_fund_new_found_paginated(): + session = FakeSession([FakeResponse(payload={"items": [], "total_pages": 0, "total_items": 0})]) + client = FtshareClient(session=session) + + client.fund_new_found(start_date=20260101, end_date=20260717, fund_type="混合型", + page=1, page_size=50, as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/fund-new-found" + assert session.calls[0]["params"]["fund_type"] == "混合型" + + +def test_fund_manager_paginated(): + session = FakeSession([FakeResponse(payload={"items": [], "total_pages": 0, "total_items": 0})]) + client = FtshareClient(session=session) + + client.fund_manager(fund_code="000001", is_inoffice="1", page=1, page_size=50, as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/fund-manager" + assert session.calls[0]["params"]["is_inoffice"] == "1" + + +def test_fund_daily_paginated(): + session = FakeSession([FakeResponse(payload={"items": [], "total_pages": 0, "total_items": 0})]) + client = FtshareClient(session=session) + + client.fund_daily(fund_code="510300", trade_date="20260717", page=1, page_size=50, as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/fund-daily" + assert session.calls[0]["params"]["trade_date"] == "20260717" + + +def test_fund_fee_paginated_filter(): + session = FakeSession([FakeResponse(payload={"items": [], "total_pages": 0, "total_items": 0})]) + client = FtshareClient(session=session) + + client.fund_fee(fund_code="000001", charge_type="日常申购费", client_type="一般", + page=1, page_size=50, as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/fund-fee" + assert session.calls[0]["params"]["charge_type"] == "日常申购费" + + +def test_fund_asset_allocation_paginated(): + session = FakeSession([FakeResponse(payload={"items": [], "total_pages": 0, "total_items": 0})]) + client = FtshareClient(session=session) + + client.fund_asset_allocation(fund_code="000001", report_date=20260331, + page=1, page_size=50, as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/fund-asset-allocation" + assert session.calls[0]["params"]["report_date"] == 20260331 + + +def test_fund_risk_level_array_response(): + session = FakeSession([FakeResponse(payload=[])]) + client = FtshareClient(session=session) + + client.fund_risk_level(fund_code="000001", history=True, as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/fund-risk-level" + assert session.calls[0]["params"]["history"] is True + + +def test_fund_index_fund_array_response(): + session = FakeSession([FakeResponse(payload=[])]) + client = FtshareClient(session=session) + + client.fund_index_fund(index_code="000300", scope="etf", as_dataframe=False) + + assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/index-fund" + assert session.calls[0]["params"] == {"index_code": "000300", "scope": "etf"} From 9136a438f714275d8bfea6c6e0917c7fc84a81ea Mon Sep 17 00:00:00 2001 From: zhuhao Date: Sat, 18 Jul 2026 14:20:30 +0800 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20=E8=A7=84=E8=8C=83=20GET=20=E5=B8=83?= =?UTF-8?q?=E5=B0=94=E5=8F=82=E6=95=B0=E5=B9=B6=E8=A1=A5=E5=85=85=E5=85=A8?= =?UTF-8?q?=E9=87=8F=E6=8E=A5=E5=8F=A3=E5=A5=91=E7=BA=A6=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 GET 查询参数中的布尔值序列化为小写 true/false,同时保持 POST JSON 布尔类型不变;新增覆盖 197 个公开方法的接口契约测试, 验证请求方法、路径及完整参数转发。 --- src/ftshare/base.py | 6 +- tests/conftest.py | 32 +++++++ tests/endpoint_cases.py | 142 +++++++++++++++++++++++++++++ tests/test_client.py | 24 ++++- tests/test_endpoint_contracts.py | 150 +++++++++++++++++++++++++++++++ 5 files changed, 350 insertions(+), 4 deletions(-) create mode 100644 tests/conftest.py create mode 100644 tests/endpoint_cases.py create mode 100644 tests/test_endpoint_contracts.py diff --git a/src/ftshare/base.py b/src/ftshare/base.py index c22cb05..f9ddbda 100644 --- a/src/ftshare/base.py +++ b/src/ftshare/base.py @@ -147,9 +147,13 @@ def _request( headers=self.headers or None, ) else: + query_params = { + key: str(value).lower() if isinstance(value, bool) else value + for key, value in clean_params.items() + } response = self.session.get( url, - params=clean_params, + params=query_params, timeout=self.timeout, headers=self.headers or None, ) diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..1f27717 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,32 @@ +from __future__ import annotations + + +class FakeResponse: + def __init__(self, status_code=200, payload=None, text="{}", json_error=False): + self.status_code = status_code + self._payload = payload + self.text = text + self._json_error = json_error + + def json(self): + if self._json_error: + raise ValueError("not json") + return self._payload + + +class FakeSession: + def __init__(self, responses): + self.responses = list(responses) + self.calls = [] + + def get(self, url, params=None, timeout=None, headers=None): + self.calls.append( + {"method": "GET", "url": url, "params": params, "timeout": timeout, "headers": headers} + ) + return self.responses.pop(0) + + def post(self, url, json=None, timeout=None, headers=None): + self.calls.append( + {"method": "POST", "url": url, "json": json, "timeout": timeout, "headers": headers} + ) + return self.responses.pop(0) diff --git a/tests/endpoint_cases.py b/tests/endpoint_cases.py new file mode 100644 index 0000000..b31e2dc --- /dev/null +++ b/tests/endpoint_cases.py @@ -0,0 +1,142 @@ +from __future__ import annotations + +from typing import Any + + +SAMPLE_VALUES: dict[str, Any] = { + "adjust": "Forward", + "adjust_kind": "Forward", + "base_date": "2026-07-17", + "board": "all", + "board_code": "BK001", + "cal-type": "1Y", + "category": "经济", + "change_direction": "increase", + "charge_type": "日常申购费", + "classify_std": "证监会行业分类", + "client_type": "一般", + "compat": "v2", + "contract_code": "A2609.DCE", + "date": "20260717", + "days": 5, + "direction": "northbound", + "end": "20260717", + "end_date": "20260717", + "end_time": "15:00:00", + "exchange": "DCE", + "filter": "close > 10", + "fund_code": "000001", + "fund_company": "华夏基金", + "fund_manager": "张三", + "fund_type": "股票型", + "history": True, + "hk_code": "00700.HK", + "index_code": "000300", + "industry_code": "801010", + "inst_type": "基金", + "institution_code": "000001", + "institution_id": "1001", + "instrument_type": "stock", + "interval": "Day", + "interval_unit": "Day", + "interval_value": 1, + "invest_type": "机构", + "is_inoffice": "1", + "is_last": True, + "level": "1", + "limit": 5, + "listing_date_since": "20260101", + "market": "CN", + "market_code": "000300", + "market_id": "XSHG", + "member_name_abbr": "永安期货", + "n": 5, + "n_code": "000001.SZ", + "nav_date": 20260717, + "o_code": "000001.SH", + "offset": 0, + "order_by": "change_rate desc", + "page": 1, + "page_size": 5, + "period": "7d", + "publish_date": "20260717", + "quarter": 2, + "query": "人工智能", + "range": "Today", + "rank_group": "follow", + "refresh": False, + "report_date": 20260331, + "report_type": "annual", + "rept_type": "annual", + "request_id": "request-1", + "scope": "ChinaStock", + "secid": "1.600000", + "sector_code": "BK001", + "sector_type": "concept", + "signal_type": "new-high", + "since": "20260701", + "since_date": "20260701", + "since_ts_millis": 1784048400000, + "since_ts_ms": 1784048400000, + "span": "DAY1", + "start": "20260701", + "start_date": "20260701", + "start_time": "09:30:00", + "stat_date": "20260717", + "stati_perd": "日", + "stock_code": "000001.SZ", + "stock_name": "平安银行", + "symbol": "600000.XSHG", + "symbol_code": "110070.SH", + "symbol_id": "600000", + "symbols": ["600000.XSHG", "000001.XSHE"], + "time_range": "1Y", + "trade_code": "00700.HK", + "trade_date": "20260717", + "ts_code": "000001.SZ", + "ts_ms": 1784048400000, + "type": "ism-manufacturing", + "until": "20260717", + "until_date": "20260717", + "until_ts_millis": 1784307600000, + "until_ts_ms": 1784307600000, + "variant": "300001", + "variety_code": "A", + "year": 2024, +} + +SPECIAL_CALLS: dict[str, dict[str, Any]] = { + "search": {"query": "人工智能", "limit": 5}, + "stock_daec_stocks": { + "board": "all", + "page": 1, + "page_size": 5, + "filter": "close > 10", + "order_by": "change_rate desc", + }, + "stock_realtime_list": {"board": "chi-next", "page": 1, "page_size": 5}, + "stock_intraday_prices": { + "symbol": "600000.XSHG", + "range": "Today", + "days": None, + "ts_ms": None, + "compat": None, + "since": None, + "since_ts_ms": None, + }, + "stock_ohlcs": { + "symbol": "600000.XSHG", + "since": "20260701", + "until": "20260717", + "interval": "Day", + "adjust": "Forward", + "compat": None, + "span": None, + "limit": None, + "until_ts_ms": None, + }, +} + +WIRE_ALIASES: dict[str, dict[str, str]] = { + "search": {"query": "q"}, +} diff --git a/tests/test_client.py b/tests/test_client.py index 4e5b06d..5994e27 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -659,6 +659,24 @@ def test_as_dataframe_true_returns_dataframe(): assert df.iloc[0]["ts_code"] == "000001.SZ" +def test_get_query_booleans_are_lowercase_strings(): + session = FakeSession([FakeResponse(payload=[])]) + client = FtshareClient(session=session) + + client.get("api/v1/market/data/demo", enabled=True, disabled=False, as_dataframe=False) + + assert session.calls[0]["params"] == {"enabled": "true", "disabled": "false"} + + +def test_post_json_booleans_remain_booleans(): + session = FakeSession([FakeResponse(payload=[])]) + client = FtshareClient(session=session) + + client.post("api/v1/market/data/demo", enabled=True, disabled=False, as_dataframe=False) + + assert session.calls[0]["json"] == {"enabled": True, "disabled": False} + + def test_etf_candlesticks_posts_json_body_to_candlesticks_path(): session = FakeSession([FakeResponse(payload=[{"close": "4.5"}])]) client = FtshareClient(session=session) @@ -818,7 +836,7 @@ def test_stock_float_holders_forwards_is_last_paging(): client.stock_float_holders(is_last=True, page=1, page_size=5, as_dataframe=False) assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/holder/stock-holder-ften" - assert session.calls[0]["params"]["is_last"] is True + assert session.calls[0]["params"]["is_last"] == "true" def test_stock_share_chg_forwards_is_last_paging(): @@ -828,7 +846,7 @@ def test_stock_share_chg_forwards_is_last_paging(): client.stock_share_chg(is_last=True, page=1, page_size=5, as_dataframe=False) assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/holder/stock-share-chg" - assert session.calls[0]["params"]["is_last"] is True + assert session.calls[0]["params"]["is_last"] == "true" def test_fund_share_forwards_paginated_params(): @@ -981,7 +999,7 @@ def test_fund_risk_level_array_response(): client.fund_risk_level(fund_code="000001", history=True, as_dataframe=False) assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v1/market/data/fund/fund-risk-level" - assert session.calls[0]["params"]["history"] is True + assert session.calls[0]["params"]["history"] == "true" def test_fund_index_fund_array_response(): diff --git a/tests/test_endpoint_contracts.py b/tests/test_endpoint_contracts.py new file mode 100644 index 0000000..69a2d6a --- /dev/null +++ b/tests/test_endpoint_contracts.py @@ -0,0 +1,150 @@ +from __future__ import annotations + +import importlib.util +import inspect +from pathlib import Path +from typing import Any + +import pytest + +from ftshare.client import FtshareClient +from ftshare.endpoints import ENDPOINTS + +from conftest import FakeResponse, FakeSession +from endpoint_cases import SAMPLE_VALUES, SPECIAL_CALLS, WIRE_ALIASES + + +ROOT = Path(__file__).resolve().parents[2] +DOC_ROOT = ROOT / "ftshare-doc" / "api-doc" +AUDIT_SCRIPT = ROOT / ".claude" / "skills" / "ftshare-doc-to-sdk-skills" / "scripts" / "audit_sync.py" +SDK_ROOT = Path(__file__).resolve().parents[1] +SKILLS_ROOT = ROOT / "FTShare-skills" / "ftshare-market-data" + + +def _load_audit_module(): + spec = importlib.util.spec_from_file_location("ftshare_audit_sync", AUDIT_SCRIPT) + module = importlib.util.module_from_spec(spec) + assert spec.loader is not None + spec.loader.exec_module(module) + return module + + +AUDIT = _load_audit_module() + + +def _public_contracts() -> dict[str, dict[str, Any]]: + contracts: dict[str, dict[str, Any]] = {} + for doc in sorted(DOC_ROOT.rglob("*.md")): + relative = doc.relative_to(DOC_ROOT) + if doc.name == "接口异常排查清单.md" or "未发布" in relative.parts: + continue + report = AUDIT.build_report(SDK_ROOT, SKILLS_ROOT, doc, require_skill=False) + assert report["sdk"]["matches"], relative + for match in report["sdk"]["matches"]: + contracts[match["name"]] = {"document": report["document"], "endpoint": match} + return contracts + + +PUBLIC_CONTRACTS = _public_contracts() +CONTROL_PARAMS = {"page", "page_size"} + + +def _call_kwargs(name: str) -> dict[str, Any]: + if name in SPECIAL_CALLS: + return dict(SPECIAL_CALLS[name]) + endpoint = ENDPOINTS[name] + return { + param.replace("-", "_"): SAMPLE_VALUES[param] + for param in endpoint.params + } + + +def _wire_params(name: str, kwargs: dict[str, Any]) -> dict[str, Any]: + endpoint = ENDPOINTS[name] + result = {} + for param in endpoint.params: + python_name = param.replace("-", "_") + value = kwargs.get(python_name) + if value is None or param in endpoint.path_params: + continue + result[WIRE_ALIASES.get(name, {}).get(python_name, param)] = value + return result + + +def _response_payload(name: str) -> Any: + endpoint = ENDPOINTS[name] + if "page" in endpoint.params and "page_size" in endpoint.params: + return {"items": [], "total_pages": 0, "total_items": 0} + return [] + + +def test_all_published_documents_have_sdk_contracts(): + reports = AUDIT.audit_directory(SDK_ROOT, SKILLS_ROOT, DOC_ROOT) + assert reports["summary"]["public_documents"] == 184 + assert reports["summary"]["sdk_matches"] == 184 + assert reports["issues"] == [] + + +def test_contract_cases_cover_all_published_sdk_methods(): + assert len(PUBLIC_CONTRACTS) == 197 + assert set(PUBLIC_CONTRACTS) <= set(ENDPOINTS) + + +@pytest.mark.parametrize("method_name", sorted(PUBLIC_CONTRACTS)) +def test_endpoint_forwards_every_documented_parameter(method_name): + endpoint = ENDPOINTS[method_name] + method = getattr(FtshareClient, method_name) + signature = inspect.signature(method) + kwargs = _call_kwargs(method_name) + + for param in endpoint.params: + python_name = param.replace("-", "_") + if python_name not in signature.parameters: + assert any(p.kind == inspect.Parameter.VAR_KEYWORD for p in signature.parameters.values()) + assert python_name in kwargs + + session = FakeSession([FakeResponse(payload=_response_payload(method_name))]) + client = FtshareClient(session=session) + getattr(client, method_name)(as_dataframe=False, **kwargs) + + call = session.calls[0] + expected_path = endpoint.path + for path_param in endpoint.path_params: + expected_path = expected_path.replace("{" + path_param + "}", str(kwargs[path_param])) + assert call["url"] == client.base_url + expected_path + assert call["method"] == endpoint.method + + expected_wire = _wire_params(method_name, kwargs) + if endpoint.method == "POST": + assert call["json"] == expected_wire + assert "params" not in call + else: + expected_query = { + key: str(value).lower() if isinstance(value, bool) else value + for key, value in expected_wire.items() + } + assert call["params"] == expected_query + assert "json" not in call + + +@pytest.mark.parametrize("method_name", sorted(PUBLIC_CONTRACTS)) +def test_endpoint_case_covers_complete_metadata_parameter_set(method_name): + endpoint = ENDPOINTS[method_name] + kwargs = _call_kwargs(method_name) + expected_python_params = {param.replace("-", "_") for param in endpoint.params} + assert set(kwargs) == expected_python_params + + +def test_sample_values_cover_every_public_endpoint_parameter(): + public_params = { + param + for name in PUBLIC_CONTRACTS + for param in ENDPOINTS[name].params + } + special_params = { + param + for name in SPECIAL_CALLS + if name in PUBLIC_CONTRACTS + for param in ENDPOINTS[name].params + } + assert public_params - special_params <= set(SAMPLE_VALUES) From dc6920a10cd1b2ab1a9873fbf24e8a8777c4b831 Mon Sep 17 00:00:00 2001 From: zhuhao Date: Sat, 18 Jul 2026 14:29:45 +0800 Subject: [PATCH 4/4] =?UTF-8?q?fix=EF=BC=9Aci=20test=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_endpoint_contracts.py | 53 ++++++-------------------------- 1 file changed, 10 insertions(+), 43 deletions(-) diff --git a/tests/test_endpoint_contracts.py b/tests/test_endpoint_contracts.py index 69a2d6a..1093bcb 100644 --- a/tests/test_endpoint_contracts.py +++ b/tests/test_endpoint_contracts.py @@ -1,8 +1,6 @@ from __future__ import annotations -import importlib.util import inspect -from pathlib import Path from typing import Any import pytest @@ -14,38 +12,13 @@ from endpoint_cases import SAMPLE_VALUES, SPECIAL_CALLS, WIRE_ALIASES -ROOT = Path(__file__).resolve().parents[2] -DOC_ROOT = ROOT / "ftshare-doc" / "api-doc" -AUDIT_SCRIPT = ROOT / ".claude" / "skills" / "ftshare-doc-to-sdk-skills" / "scripts" / "audit_sync.py" -SDK_ROOT = Path(__file__).resolve().parents[1] -SKILLS_ROOT = ROOT / "FTShare-skills" / "ftshare-market-data" - - -def _load_audit_module(): - spec = importlib.util.spec_from_file_location("ftshare_audit_sync", AUDIT_SCRIPT) - module = importlib.util.module_from_spec(spec) - assert spec.loader is not None - spec.loader.exec_module(module) - return module - - -AUDIT = _load_audit_module() - - -def _public_contracts() -> dict[str, dict[str, Any]]: - contracts: dict[str, dict[str, Any]] = {} - for doc in sorted(DOC_ROOT.rglob("*.md")): - relative = doc.relative_to(DOC_ROOT) - if doc.name == "接口异常排查清单.md" or "未发布" in relative.parts: - continue - report = AUDIT.build_report(SDK_ROOT, SKILLS_ROOT, doc, require_skill=False) - assert report["sdk"]["matches"], relative - for match in report["sdk"]["matches"]: - contracts[match["name"]] = {"document": report["document"], "endpoint": match} - return contracts - - -PUBLIC_CONTRACTS = _public_contracts() +NON_PUBLISHED_ENDPOINTS = { + "stock_dividends_paginated", + "stock_intraday", + "stock_ohlcs", + "stock_related", +} +PUBLIC_CONTRACTS = set(ENDPOINTS) - NON_PUBLISHED_ENDPOINTS CONTROL_PARAMS = {"page", "page_size"} @@ -78,16 +51,10 @@ def _response_payload(name: str) -> Any: return [] -def test_all_published_documents_have_sdk_contracts(): - reports = AUDIT.audit_directory(SDK_ROOT, SKILLS_ROOT, DOC_ROOT) - assert reports["summary"]["public_documents"] == 184 - assert reports["summary"]["sdk_matches"] == 184 - assert reports["issues"] == [] - - -def test_contract_cases_cover_all_published_sdk_methods(): +def test_contract_cases_cover_all_public_sdk_methods(): assert len(PUBLIC_CONTRACTS) == 197 - assert set(PUBLIC_CONTRACTS) <= set(ENDPOINTS) + assert PUBLIC_CONTRACTS | NON_PUBLISHED_ENDPOINTS == set(ENDPOINTS) + assert not (PUBLIC_CONTRACTS & NON_PUBLISHED_ENDPOINTS) @pytest.mark.parametrize("method_name", sorted(PUBLIC_CONTRACTS))