From 7c7c54e83ef4bbc58f4a0fd6e1dd76d80dfcfd9e Mon Sep 17 00:00:00 2001 From: zhuhao Date: Thu, 15 Oct 2026 09:23:35 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix=EF=BC=9A=E5=8F=AF=E8=BD=AC=E5=80=BA?= =?UTF-8?q?=E5=88=86=E9=92=9F=20K=20=E7=BA=BF=E8=B5=B7=E6=AD=A2=E8=B7=A8?= =?UTF-8?q?=E5=BA=A6=E4=B8=8A=E9=99=90=E6=94=B9=E4=B8=BA=2030=20=E4=B8=AA?= =?UTF-8?q?=E8=87=AA=E7=84=B6=E6=97=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 同步 ftshare-doc 修改:convertible_bond_minute_candlesticks 的 since/until 跨度由 3 个自然日改为 30 个北京时间自然日(含起止日期、 非交易日计入),同步 bond.py 文档串与 API_REFERENCE。 --- docs/API_REFERENCE.md | 2 +- src/ftshare/apis/bond.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index 0de8594..aaa6a07 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -5501,7 +5501,7 @@ Args: symbols: 1~20 个可转债代码;支持重复参数、逗号分隔或 JSON 字符串数组(与 symbol 二选一) (type: string[]; required: N). interval_value: 分钟周期:仅支持 1、5、15,默认 1 (type: enum; required: N). since_ts_millis: 起始时间戳,单位毫秒;单只、批量都必须提供 (type: int(ms); required: Y). - until_ts_millis: 结束时间戳,单位毫秒;不得早于 since,且单次跨度不超过 3 个自然日 (type: int(ms); required: Y). + until_ts_millis: 结束时间戳,单位毫秒;不得早于 since,且单次跨度不超过 30 个北京时间自然日(包含起止日期,非交易日也计入) (type: int(ms); required: Y). limit: 每只标的聚合后最多返回条数,范围 1~1000;省略返回窗口内全部记录 (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. diff --git a/src/ftshare/apis/bond.py b/src/ftshare/apis/bond.py index 315d31e..09cb687 100644 --- a/src/ftshare/apis/bond.py +++ b/src/ftshare/apis/bond.py @@ -131,7 +131,7 @@ def convertible_bond_minute_candlesticks( symbols: 1~20 个可转债代码;支持重复参数、逗号分隔或 JSON 字符串数组(与 symbol 二选一) (type: string[]; required: N). interval_value: 分钟周期:仅支持 1、5、15,默认 1 (type: enum; required: N). since_ts_millis: 起始时间戳,单位毫秒;单只、批量都必须提供 (type: int(ms); required: Y). - until_ts_millis: 结束时间戳,单位毫秒;不得早于 since,且单次跨度不超过 3 个自然日 (type: int(ms); required: Y). + until_ts_millis: 结束时间戳,单位毫秒;不得早于 since,且单次跨度不超过 30 个北京时间自然日(包含起止日期,非交易日也计入) (type: int(ms); required: Y). limit: 每只标的聚合后最多返回条数,范围 1~1000;省略返回窗口内全部记录 (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. From 0f47c8a240bfc3eae8414163ed1dbd926744cd83 Mon Sep 17 00:00:00 2001 From: zhuhao Date: Mon, 19 Oct 2026 18:36:24 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix=EF=BC=9A=E5=AE=9E=E6=97=B6K=E7=BA=BF=20?= =?UTF-8?q?symbols=20=E6=94=B9=E7=94=A8=E9=80=97=E5=8F=B7=E5=88=86?= =?UTF-8?q?=E9=9A=94=EF=BC=8C=E9=BE=99=E8=99=8E=E6=A6=9C=E5=88=86=E9=A1=B5?= =?UTF-8?q?=E4=B8=8A=E9=99=90=E6=94=B9=E4=B8=BA=20500?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- docs/API_REFERENCE.md | 18 +++++++++--------- src/ftshare/apis/bond.py | 10 +++++----- src/ftshare/apis/etf.py | 6 +++--- src/ftshare/apis/index.py | 6 +++--- src/ftshare/apis/stock.py | 10 ++++++---- src/ftshare/endpoints/stock.py | 2 ++ src/ftshare/params.py | 7 +++---- tests/test_client.py | 14 +++++++++++--- 8 files changed, 42 insertions(+), 31 deletions(-) diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index aaa6a07..dfa4a55 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -971,7 +971,7 @@ Documented endpoint: ``get_eastmoney_stock_flow``. Args: symbol: 股票代码,如 600522 (type: string; required: N). - trade_date: 交易日 YYYYMMDD;与 start_date/end_date 互斥 (type: string; required: N). + trade_date: 交易日 YYYYMMDD;可与 start_date/end_date 按 AND 条件组合过滤 (type: string; required: N). start_date: 区间起始日 YYYYMMDD;需与 end_date 同时提供 (type: string; required: N). end_date: 区间结束日 YYYYMMDD;需与 start_date 同时提供 (type: string; required: N). page: Page number, starting from 1. If omitted, the server default is used unless ``limit`` or ``all_pages`` is set. @@ -2920,7 +2920,7 @@ Returns: - HTTP:`GET` - Path:`api/v4/market/data/stock-realtime-day-kline` - 参数:`symbols` -- 说明:`symbols` 支持 list/tuple(SDK 自动序列化为 JSON 字符串数组)或 JSON 字符串。 +- 说明:`symbols` 支持 list/tuple(SDK 自动序列化为逗号分隔字符串)或已是逗号分隔/JSON 字符串的代码列表。 - 来源文档:`股票实时日K线.md` - 原始接口:`stock_realtime_day_kline` @@ -2968,7 +2968,7 @@ Returns: - HTTP:`GET` - Path:`api/v4/market/data/stock-realtime-minute-kline` - 参数:`symbols` -- 说明:`symbols` 支持 list/tuple(SDK 自动序列化为 JSON 字符串数组)或 JSON 字符串。 +- 说明:`symbols` 支持 list/tuple(SDK 自动序列化为逗号分隔字符串)或已是逗号分隔/JSON 字符串的代码列表。 - 来源文档:`股票实时分钟K线.md` - 原始接口:`stock_realtime_minute_kline` @@ -3799,7 +3799,7 @@ Returns: - HTTP:`GET` - Path:`api/v4/market/data/index-realtime-day-kline` - 参数:`symbols` -- 说明:`symbols` 支持 list/tuple(SDK 自动序列化为 JSON 字符串数组)或 JSON 字符串。 +- 说明:`symbols` 支持 list/tuple(SDK 自动序列化为逗号分隔字符串)或已是逗号分隔/JSON 字符串的代码列表。 - 来源文档:`指数实时日K线.md` - 原始接口:`index_realtime_day_kline` @@ -3813,7 +3813,7 @@ Returns: - HTTP:`GET` - Path:`api/v4/market/data/index-realtime-minute-kline` - 参数:`symbols` -- 说明:`symbols` 支持 list/tuple(SDK 自动序列化为 JSON 字符串数组)或 JSON 字符串。 +- 说明:`symbols` 支持 list/tuple(SDK 自动序列化为逗号分隔字符串)或已是逗号分隔/JSON 字符串的代码列表。 - 来源文档:`指数实时分钟K线.md` - 原始接口:`index_realtime_minute_kline` @@ -4233,7 +4233,7 @@ Returns: - HTTP:`GET` - Path:`api/v4/market/data/etf-realtime-day-kline` - 参数:`symbols` -- 说明:`symbols` 支持 list/tuple(SDK 自动序列化为 JSON 字符串数组)或 JSON 字符串。 +- 说明:`symbols` 支持 list/tuple(SDK 自动序列化为逗号分隔字符串)或已是逗号分隔/JSON 字符串的代码列表。 - 来源文档:`ETF实时日K线.md` - 原始接口:`etf_realtime_day_kline` @@ -4247,7 +4247,7 @@ ETF实时日K线. - HTTP:`GET` - Path:`api/v4/market/data/etf-realtime-minute-kline` - 参数:`symbols` -- 说明:`symbols` 支持 list/tuple(SDK 自动序列化为 JSON 字符串数组)或 JSON 字符串。 +- 说明:`symbols` 支持 list/tuple(SDK 自动序列化为逗号分隔字符串)或已是逗号分隔/JSON 字符串的代码列表。 - 来源文档:`ETF实时分钟K线.md` - 原始接口:`etf_realtime_minute_kline` @@ -5531,7 +5531,7 @@ Method: ``GET``. Documented endpoint: ``convertible_bond_realtime_day_kline``. Args: - symbols: 1~20 个可转债代码的 JSON 字符串数组,如 ``["113042.SH","123107.SZ"]``;单只也必须传单元素数组 (type: string; required: Y). + symbols: 1~20 个可转债代码的逗号分隔列表,如 ``113042.SH,123107.SZ``;也兼容 JSON 字符串数组格式;支持带交易所后缀和可推断市场的六码裸代码 (type: string; required: Y). 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. @@ -5559,7 +5559,7 @@ Method: ``GET``. Documented endpoint: ``convertible_bond_realtime_minute_kline``. Args: - symbols: 1~20 个可转债代码的 JSON 字符串数组,如 ``["113042.SH","123107.SZ"]``;单只也必须传单元素数组 (type: string; required: Y). + symbols: 1~20 个可转债代码的逗号分隔列表,如 ``113042.SH,123107.SZ``;也兼容 JSON 字符串数组格式;支持带交易所后缀和可推断市场的六码裸代码 (type: string; required: Y). 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/apis/bond.py b/src/ftshare/apis/bond.py index 09cb687..d42dbfd 100644 --- a/src/ftshare/apis/bond.py +++ b/src/ftshare/apis/bond.py @@ -6,7 +6,7 @@ from typing import Any from ..endpoints import ENDPOINTS -from ..params import symbols_to_json_string +from ..params import symbols_to_csv_string class BondApiMixin: @@ -161,7 +161,7 @@ def convertible_bond_realtime_day_kline(self, symbols: Any | None = None, *, raw Documented endpoint: ``convertible_bond_realtime_day_kline``. Args: - symbols: 1~20 个可转债代码的 JSON 字符串数组,如 ``["113042.SH","123107.SZ"]``;单只也必须传单元素数组 (type: string; required: Y). + symbols: 1~20 个可转债代码的逗号分隔列表,如 ``113042.SH,123107.SZ``;也兼容 JSON 字符串数组格式;支持带交易所后缀和可推断市场的六码裸代码 (type: string; required: Y). 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. @@ -171,7 +171,7 @@ def convertible_bond_realtime_day_kline(self, symbols: Any | None = None, *, raw A pandas ``DataFrame`` by default, Python rows when ``as_dataframe=False``, or raw JSON when ``raw=True``. """ - params = {'symbols': symbols_to_json_string(symbols)} + params = {'symbols': symbols_to_csv_string(symbols)} params.update(kwargs) return self._call_endpoint('convertible_bond_realtime_day_kline', raw=raw, fields=fields, as_dataframe=as_dataframe, **params) @@ -183,7 +183,7 @@ def convertible_bond_realtime_minute_kline(self, symbols: Any | None = None, *, Documented endpoint: ``convertible_bond_realtime_minute_kline``. Args: - symbols: 1~20 个可转债代码的 JSON 字符串数组,如 ``["113042.SH","123107.SZ"]``;单只也必须传单元素数组 (type: string; required: Y). + symbols: 1~20 个可转债代码的逗号分隔列表,如 ``113042.SH,123107.SZ``;也兼容 JSON 字符串数组格式;支持带交易所后缀和可推断市场的六码裸代码 (type: string; required: Y). 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. @@ -193,7 +193,7 @@ def convertible_bond_realtime_minute_kline(self, symbols: Any | None = None, *, A pandas ``DataFrame`` by default, Python rows when ``as_dataframe=False``, or raw JSON when ``raw=True``. """ - params = {'symbols': symbols_to_json_string(symbols)} + params = {'symbols': symbols_to_csv_string(symbols)} params.update(kwargs) return self._call_endpoint('convertible_bond_realtime_minute_kline', raw=raw, fields=fields, as_dataframe=as_dataframe, **params) diff --git a/src/ftshare/apis/etf.py b/src/ftshare/apis/etf.py index dd22c57..6046681 100644 --- a/src/ftshare/apis/etf.py +++ b/src/ftshare/apis/etf.py @@ -7,7 +7,7 @@ from typing import Any from ..endpoints import ENDPOINTS -from ..params import symbols_to_json_string +from ..params import symbols_to_csv_string class EtfApiMixin: @@ -330,14 +330,14 @@ def etf_minutes(self, symbol: Any | None = None, interval_value: Any | None = No def etf_realtime_minute_kline(self, symbols: Any | None = None, *, raw: bool = False, fields: Sequence[str] | str | None = None, as_dataframe: bool = True, **kwargs: Any) -> Any: """ETF实时分钟K线.""" - params = {'symbols': symbols_to_json_string(symbols)} + params = {'symbols': symbols_to_csv_string(symbols)} params.update(kwargs) return self._call_endpoint('etf_realtime_minute_kline', raw=raw, fields=fields, as_dataframe=as_dataframe, **params) def etf_realtime_day_kline(self, symbols: Any | None = None, *, raw: bool = False, fields: Sequence[str] | str | None = None, as_dataframe: bool = True, **kwargs: Any) -> Any: """ETF实时日K线.""" - params = {'symbols': symbols_to_json_string(symbols)} + params = {'symbols': symbols_to_csv_string(symbols)} params.update(kwargs) return self._call_endpoint('etf_realtime_day_kline', raw=raw, fields=fields, as_dataframe=as_dataframe, **params) diff --git a/src/ftshare/apis/index.py b/src/ftshare/apis/index.py index e505131..05664fb 100644 --- a/src/ftshare/apis/index.py +++ b/src/ftshare/apis/index.py @@ -6,7 +6,7 @@ from typing import Any from ..endpoints import ENDPOINTS -from ..params import symbols_to_json_string +from ..params import symbols_to_csv_string class IndexApiMixin: @@ -469,14 +469,14 @@ def index_minutes(self, symbol: Any | None = None, interval_value: Any | None = def index_realtime_minute_kline(self, symbols: Any | None = None, *, raw: bool = False, fields: Sequence[str] | str | None = None, as_dataframe: bool = True, **kwargs: Any) -> Any: """指数实时分钟K线.""" - params = {'symbols': symbols_to_json_string(symbols)} + params = {'symbols': symbols_to_csv_string(symbols)} params.update(kwargs) return self._call_endpoint('index_realtime_minute_kline', raw=raw, fields=fields, as_dataframe=as_dataframe, **params) def index_realtime_day_kline(self, symbols: Any | None = None, *, raw: bool = False, fields: Sequence[str] | str | None = None, as_dataframe: bool = True, **kwargs: Any) -> Any: """指数实时日K线.""" - params = {'symbols': symbols_to_json_string(symbols)} + params = {'symbols': symbols_to_csv_string(symbols)} params.update(kwargs) return self._call_endpoint('index_realtime_day_kline', raw=raw, fields=fields, as_dataframe=as_dataframe, **params) diff --git a/src/ftshare/apis/stock.py b/src/ftshare/apis/stock.py index 5d1d079..7c89cce 100644 --- a/src/ftshare/apis/stock.py +++ b/src/ftshare/apis/stock.py @@ -6,7 +6,7 @@ from typing import Any from ..endpoints import ENDPOINTS -from ..params import symbols_to_json_string +from ..params import symbols_to_csv_string def _present_params(params: dict[str, Any]) -> list[str]: @@ -1554,7 +1554,7 @@ def eastmoney_stock_flow( Args: symbol: 股票代码,如 600522 (type: string; required: N). - trade_date: 交易日 YYYYMMDD;与 start_date/end_date 互斥 (type: string; required: N). + trade_date: 交易日 YYYYMMDD;可与 start_date/end_date 按 AND 条件组合过滤 (type: string; required: N). start_date: 区间起始日 YYYYMMDD;需与 end_date 同时提供 (type: string; required: N). end_date: 区间结束日 YYYYMMDD;需与 start_date 同时提供 (type: string; required: N). page: Page number, starting from 1. If omitted, the server default is used unless ``limit`` or ``all_pages`` is set. @@ -2367,6 +2367,7 @@ def abnormal_trading_details( limit=limit, all_pages=all_pages, max_pages=max_pages, + max_page_size=500, raw=raw, fields=fields, as_dataframe=as_dataframe, @@ -2415,6 +2416,7 @@ def abnormal_trading_overview( limit=limit, all_pages=all_pages, max_pages=max_pages, + max_page_size=500, raw=raw, fields=fields, as_dataframe=as_dataframe, @@ -4735,14 +4737,14 @@ def ths_industry_constituents(self, industry_code: Any | None = None, industry_n def stock_realtime_minute_kline(self, symbols: Any | None = None, *, raw: bool = False, fields: Sequence[str] | str | None = None, as_dataframe: bool = True, **kwargs: Any) -> Any: """股票实时分钟K线.""" - params = {'symbols': symbols_to_json_string(symbols)} + params = {'symbols': symbols_to_csv_string(symbols)} params.update(kwargs) return self._call_endpoint('stock_realtime_minute_kline', raw=raw, fields=fields, as_dataframe=as_dataframe, **params) def stock_realtime_day_kline(self, symbols: Any | None = None, *, raw: bool = False, fields: Sequence[str] | str | None = None, as_dataframe: bool = True, **kwargs: Any) -> Any: """股票实时日K线.""" - params = {'symbols': symbols_to_json_string(symbols)} + params = {'symbols': symbols_to_csv_string(symbols)} params.update(kwargs) return self._call_endpoint('stock_realtime_day_kline', raw=raw, fields=fields, as_dataframe=as_dataframe, **params) diff --git a/src/ftshare/endpoints/stock.py b/src/ftshare/endpoints/stock.py index e185bb9..0644bf4 100644 --- a/src/ftshare/endpoints/stock.py +++ b/src/ftshare/endpoints/stock.py @@ -12,6 +12,7 @@ 'doc_file': '龙虎榜明细.md', 'original_api': 'abnormal_trading_details', 'params': ('date', 'page', 'page_size'), + 'max_page_size': 500, }, 'abnormal_trading_overview': { 'path': 'api/v1/market/data/abnormal-trading-overview', @@ -19,6 +20,7 @@ 'doc_file': '龙虎榜总览.md', 'original_api': 'abnormal_trading_overview', 'params': ('date', 'page', 'page_size'), + 'max_page_size': 500, }, 'auction_results': { 'path': 'api/v2/market/data/auction-results', diff --git a/src/ftshare/params.py b/src/ftshare/params.py index 49e64da..6473fdb 100644 --- a/src/ftshare/params.py +++ b/src/ftshare/params.py @@ -2,12 +2,11 @@ from __future__ import annotations -import json from typing import Any -def symbols_to_json_string(symbols: Any) -> Any: - """Serialize list/tuple/set symbols into the JSON string realtime kline endpoints require.""" +def symbols_to_csv_string(symbols: Any) -> Any: + """Serialize list/tuple/set symbols into the comma-separated string the realtime kline endpoints document.""" if isinstance(symbols, (list, tuple, set)): - return json.dumps(list(symbols)) + return ",".join(str(symbol) for symbol in symbols) return symbols diff --git a/tests/test_client.py b/tests/test_client.py index 49966d3..4e74d65 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -764,7 +764,7 @@ def test_etf_share_and_net_value_reject_page_size_above_200(): client.etf_net_value(etf_code="510300", page_size=201) -def test_realtime_kline_methods_serialize_symbols_list_to_json(): +def test_realtime_kline_methods_serialize_symbols_list_to_csv(): realtime_payload = {"code": 200, "message": "success", "data": [{"symbol": "600519.SH", "items": [], "total": 0}]} methods = [ "stock_realtime_day_kline", @@ -781,7 +781,7 @@ def test_realtime_kline_methods_serialize_symbols_list_to_json(): getattr(client, method_name)(symbols=["600519.SH", "000001.SZ"], as_dataframe=False) - assert session.calls[0]["params"] == {"symbols": '["600519.SH", "000001.SZ"]'} + assert session.calls[0]["params"] == {"symbols": "600519.SH,000001.SZ"} session = FakeSession([FakeResponse(payload=realtime_payload)]) client = FtshareClient(session=session) @@ -791,6 +791,14 @@ def test_realtime_kline_methods_serialize_symbols_list_to_json(): assert session.calls[0]["params"] == {"symbols": '["600519.SH"]'} +def test_abnormal_trading_methods_accept_documented_500_row_page_size(): + client = FtshareClient(session=FakeSession([])) + + for method_name in ("abnormal_trading_details", "abnormal_trading_overview"): + with pytest.raises(ValueError, match="page_size must be between 1 and 500"): + getattr(client, method_name)(page_size=501) + + def test_futures_kline_batch_and_realtime_day_kline_forward_symbols_list(): session = FakeSession([FakeResponse(payload=[])]) client = FtshareClient(session=session) @@ -1377,7 +1385,7 @@ def test_convertible_bond_kline_family_forwards_documented_parameters(): getattr(client, method_name)(symbols=["113042.SH", "123107.SZ"], as_dataframe=False) - assert session.calls[0]["params"] == {"symbols": '["113042.SH", "123107.SZ"]'} + assert session.calls[0]["params"] == {"symbols": "113042.SH,123107.SZ"} def test_stock_intraday_forwards_range_days_and_ts_ms(): From 4f7f12f6cbb2a791843754a64b9ec9228bed0f69 Mon Sep 17 00:00:00 2001 From: zhuhao Date: Mon, 19 Oct 2026 20:30:33 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix=EF=BC=9A=E6=89=B9=E9=87=8FK=E7=BA=BF=20?= =?UTF-8?q?symbols=20=E6=94=B9=E7=94=A8=E9=80=97=E5=8F=B7=E5=88=86?= =?UTF-8?q?=E9=9A=94=EF=BC=8C=E7=A7=BB=E9=99=A4=E4=B8=8D=E5=AD=98=E5=9C=A8?= =?UTF-8?q?=E7=9A=84=20futures=5Fminutes=5Fbatch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- docs/API_REFERENCE.md | 19 ++++------- src/ftshare/apis/bond.py | 8 ++--- src/ftshare/apis/etf.py | 4 +-- src/ftshare/apis/futures.py | 23 +++++-------- src/ftshare/apis/index.py | 4 +-- src/ftshare/apis/stock.py | 4 +-- src/ftshare/endpoints/futures.py | 7 ---- tests/endpoint_cases.py | 2 -- tests/test_client.py | 56 ++++++++++++++++++-------------- tests/test_integration_market.py | 1 - 10 files changed, 57 insertions(+), 71 deletions(-) diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index dfa4a55..9fb0186 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -251,7 +251,6 @@ ### 期货数据 | [`eastmoney_futures_strange`](#api-eastmoney-futures-strange) | 东方财富期货龙虎榜 | `GET` | `api/v1/market/data/eastmoney-futures-strange` | `exchange`, `variety`, `contract`, `trade_date` | `东方财富期货龙虎榜.md` | -| [`futures_minutes_batch`](#api-futures-minutes-batch) | 批量期货历史分钟行情 | `GET` | `api/v2/market/data/futures_minutes/batch` | `symbols`, `interval`, `start`, `end`, `limit` | `批量期货历史分钟行情.md` | | [`member_build_process`](#api-member-build-process) | 会员建仓过程 | `GET` | `api/v2/market/data/member-build-process` | `exchange`, `member_name`, `instrument_id`, `start_date`, `end_date`, `contract_multiplier`, `page`, `page_size` | `会员建仓过程.md` | | [`member_position_ranking`](#api-member-position-ranking) | 会员持仓排名 | `GET` | `api/v2/market/data/member-position-ranking` | `exchange`, `instrument_id`, `trade_date`, `direction`, `page`, `page_size` | `会员持仓排名.md` | @@ -5172,7 +5171,7 @@ Method: ``GET``. Documented endpoint: ``futures_kline_batch``. Args: - symbols: 1~20 个期货合约代码;支持重复参数、逗号分隔或列表 (type: string[]; required: Y). + symbols: 1~20 个期货合约代码;使用逗号分隔,兼容重复参数 (type: string; required: Y). interval: K 线周期,默认 ``daily`` (type: string; required: N). start: 起始时间戳,单位毫秒 (type: integer; required: N). end: 结束时间戳,单位毫秒,不能单独传 (type: integer; required: N). @@ -5205,7 +5204,7 @@ Documented endpoint: ``futures_minutes``. Args: symbol: 单个期货合约代码,带交易所短后缀;与 ``symbols`` 二选一 (type: string; required: N). - symbols: 1~20 个期货合约代码;支持重复参数、逗号分隔或列表;与 ``symbol`` 二选一 (type: string[]; required: N). + symbols: 1~20 个期货合约代码;使用逗号分隔,兼容重复参数;与 ``symbol`` 二选一 (type: string; required: N). interval: 分钟周期,默认 ``1min`` (type: string; required: N). start: 起始时间戳,单位毫秒;必填 (type: integer; required: Y). end: 结束时间戳,单位毫秒;必填,不能单独传 (type: integer; required: Y). @@ -5237,7 +5236,7 @@ Method: ``GET``. Documented endpoint: ``futures_minutes_realtime``. Args: - symbols: 期货合约代码列表,1~20 个 (type: array; required: Y). + symbols: 逗号分隔的期货合约代码列表,1~20 个 (type: string; required: Y). 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. @@ -5302,7 +5301,7 @@ Method: ``GET``. Documented endpoint: ``futures_realtime_day_kline``. Args: - symbols: 1~20 个期货合约代码;支持重复参数、逗号分隔或列表 (type: string[]; required: Y). + symbols: 1~20 个期货合约代码;使用逗号分隔,兼容重复参数 (type: string; required: Y). 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. @@ -5463,7 +5462,7 @@ Method: ``GET``. Documented endpoint: ``convertible_bond_candlesticks_batch``. Args: - symbols: 可转债代码列表,1~20 个;支持重复参数、逗号分隔或 JSON 字符串数组 (type: string[]; required: Y). + symbols: 1~20 个可转债代码;使用逗号分隔,兼容重复参数和 JSON 字符串数组 (type: string; required: Y). interval_unit: 周期单位:Day/Week/Month/Year,大小写不敏感 (type: enum; required: Y). adjust_kind: 复权:None(默认,不复权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). since_ts_millis: 起始时间戳,单位毫秒;不得晚于 until,且与 until 相差不超过 12 个自然月 (type: int(ms); required: Y). @@ -5498,7 +5497,7 @@ Documented endpoint: ``convertible_bond_minute_candlesticks``. Args: symbol: 单只可转债代码(与 symbols 二选一,不能同时传) (type: string; required: N). - symbols: 1~20 个可转债代码;支持重复参数、逗号分隔或 JSON 字符串数组(与 symbol 二选一) (type: string[]; required: N). + symbols: 1~20 个可转债代码;使用逗号分隔,兼容重复参数和 JSON 字符串数组(与 symbol 二选一) (type: string; required: N). interval_value: 分钟周期:仅支持 1、5、15,默认 1 (type: enum; required: N). since_ts_millis: 起始时间戳,单位毫秒;单只、批量都必须提供 (type: int(ms); required: Y). until_ts_millis: 结束时间戳,单位毫秒;不得早于 since,且单次跨度不超过 30 个北京时间自然日(包含起止日期,非交易日也计入) (type: int(ms); required: Y). @@ -6722,12 +6721,6 @@ Returns: - 参数:`exchange, variety, contract, trade_date` - 来源文档:`东方财富期货龙虎榜.md` -

futures_minutes_batch

- -- Path:`api/v2/market/data/futures_minutes/batch` -- 参数:`symbols, interval, start, end, limit` -- 来源文档:`批量期货历史分钟行情.md` -

member_build_process

- Path:`api/v2/market/data/member-build-process` diff --git a/src/ftshare/apis/bond.py b/src/ftshare/apis/bond.py index d42dbfd..0fce6db 100644 --- a/src/ftshare/apis/bond.py +++ b/src/ftshare/apis/bond.py @@ -80,7 +80,7 @@ def convertible_bond_candlesticks_batch( Documented endpoint: ``convertible_bond_candlesticks_batch``. Args: - symbols: 可转债代码列表,1~20 个;支持重复参数、逗号分隔或 JSON 字符串数组 (type: string[]; required: Y). + symbols: 1~20 个可转债代码;使用逗号分隔,兼容重复参数和 JSON 字符串数组 (type: string; required: Y). interval_unit: 周期单位:Day/Week/Month/Year,大小写不敏感 (type: enum; required: Y). adjust_kind: 复权:None(默认,不复权)/Forward(前复权)/Backward(后复权) (type: enum; required: N). since_ts_millis: 起始时间戳,单位毫秒;不得晚于 until,且与 until 相差不超过 12 个自然月 (type: int(ms); required: Y). @@ -96,7 +96,7 @@ def convertible_bond_candlesticks_batch( ``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, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} + request_params = {'symbols': symbols_to_csv_string(symbols), 'interval_unit': interval_unit, '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', @@ -128,7 +128,7 @@ def convertible_bond_minute_candlesticks( Args: symbol: 单只可转债代码(与 symbols 二选一,不能同时传) (type: string; required: N). - symbols: 1~20 个可转债代码;支持重复参数、逗号分隔或 JSON 字符串数组(与 symbol 二选一) (type: string[]; required: N). + symbols: 1~20 个可转债代码;使用逗号分隔,兼容重复参数和 JSON 字符串数组(与 symbol 二选一) (type: string; required: N). interval_value: 分钟周期:仅支持 1、5、15,默认 1 (type: enum; required: N). since_ts_millis: 起始时间戳,单位毫秒;单只、批量都必须提供 (type: int(ms); required: Y). until_ts_millis: 结束时间戳,单位毫秒;不得早于 since,且单次跨度不超过 30 个北京时间自然日(包含起止日期,非交易日也计入) (type: int(ms); required: Y). @@ -143,7 +143,7 @@ def convertible_bond_minute_candlesticks( ``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, 'symbols': symbols, 'interval_value': interval_value, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} + request_params = {'symbol': symbol, 'symbols': symbols_to_csv_string(symbols), 'interval_value': interval_value, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} request_params.update(kwargs) return self._call_endpoint( 'convertible_bond_minute_candlesticks', diff --git a/src/ftshare/apis/etf.py b/src/ftshare/apis/etf.py index 6046681..de3cfe8 100644 --- a/src/ftshare/apis/etf.py +++ b/src/ftshare/apis/etf.py @@ -343,7 +343,7 @@ def etf_realtime_day_kline(self, symbols: Any | None = None, *, raw: bool = Fals def etf_minutes_batch(self, symbols: 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: """批量ETF历史分钟行情.""" - params = {'symbols': symbols, 'interval_value': interval_value, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} + params = {'symbols': symbols_to_csv_string(symbols), 'interval_value': interval_value, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} params.update(kwargs) return self._call_endpoint('etf_minutes_batch', raw=raw, fields=fields, as_dataframe=as_dataframe, **params) @@ -429,7 +429,7 @@ def etf_announcements_download( def etf_candlesticks_batch(self, symbols: Any | None = None, interval_unit: 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线.""" - params = {'symbols': symbols, 'interval_unit': interval_unit, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} + params = {'symbols': symbols_to_csv_string(symbols), 'interval_unit': interval_unit, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} params.update(kwargs) return self._call_endpoint('etf_candlesticks_batch', raw=raw, fields=fields, as_dataframe=as_dataframe, **params) diff --git a/src/ftshare/apis/futures.py b/src/ftshare/apis/futures.py index e53a074..a059bb9 100644 --- a/src/ftshare/apis/futures.py +++ b/src/ftshare/apis/futures.py @@ -6,6 +6,7 @@ from typing import Any from ..endpoints import ENDPOINTS +from ..params import symbols_to_csv_string class FuturesApiMixin: @@ -317,7 +318,7 @@ def futures_minutes( Args: symbol: 单个期货合约代码,带交易所短后缀;与 ``symbols`` 二选一 (type: string; required: N). - symbols: 1~20 个期货合约代码;支持重复参数、逗号分隔或列表;与 ``symbol`` 二选一 (type: string[]; required: N). + symbols: 1~20 个期货合约代码;使用逗号分隔,兼容重复参数;与 ``symbol`` 二选一 (type: string; required: N). interval: 分钟周期,默认 ``1min`` (type: string; required: N). start: 起始时间戳,单位毫秒;必填 (type: integer; required: Y). end: 结束时间戳,单位毫秒;必填,不能单独传 (type: integer; required: Y). @@ -333,7 +334,7 @@ def futures_minutes( """ request_params = { 'symbol': symbol, - 'symbols': symbols, + 'symbols': symbols_to_csv_string(symbols), 'interval': interval, 'start': start, 'end': end, @@ -418,7 +419,7 @@ def futures_kline_batch( Documented endpoint: ``futures_kline_batch``. Args: - symbols: 1~20 个期货合约代码;支持重复参数、逗号分隔或列表 (type: string[]; required: Y). + symbols: 1~20 个期货合约代码;使用逗号分隔,兼容重复参数 (type: string; required: Y). interval: K 线周期,默认 ``daily`` (type: string; required: N). start: 起始时间戳,单位毫秒 (type: integer; required: N). end: 结束时间戳,单位毫秒,不能单独传 (type: integer; required: N). @@ -433,7 +434,7 @@ def futures_kline_batch( ``as_dataframe=False``, or raw JSON when ``raw=True``. """ request_params = { - 'symbols': symbols, + 'symbols': symbols_to_csv_string(symbols), 'interval': interval, 'start': start, 'end': end, @@ -464,7 +465,7 @@ def futures_minutes_realtime( Documented endpoint: ``futures_minutes_realtime``. Args: - symbols: 期货合约代码列表,1~20 个 (type: array; required: Y). + symbols: 逗号分隔的期货合约代码列表,1~20 个 (type: string; required: Y). 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. @@ -474,7 +475,7 @@ def futures_minutes_realtime( A pandas ``DataFrame`` by default, Python rows when ``as_dataframe=False``, or raw JSON when ``raw=True``. """ - request_params = {'symbols': symbols} + request_params = {'symbols': symbols_to_csv_string(symbols)} request_params.update(kwargs) return self._call_endpoint( 'futures_minutes_realtime', @@ -500,7 +501,7 @@ def futures_realtime_day_kline( Documented endpoint: ``futures_realtime_day_kline``. Args: - symbols: 1~20 个期货合约代码;支持重复参数、逗号分隔或列表 (type: string[]; required: Y). + symbols: 1~20 个期货合约代码;使用逗号分隔,兼容重复参数 (type: string; required: Y). 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. @@ -510,7 +511,7 @@ def futures_realtime_day_kline( A pandas ``DataFrame`` by default, Python rows when ``as_dataframe=False``, or raw JSON when ``raw=True``. """ - request_params = {'symbols': symbols} + request_params = {'symbols': symbols_to_csv_string(symbols)} request_params.update(kwargs) return self._call_endpoint( 'futures_realtime_day_kline', @@ -847,9 +848,3 @@ def member_position_ranking(self, exchange: Any | None = None, instrument_id: An params = {'exchange': exchange, 'instrument_id': instrument_id, 'trade_date': trade_date, 'direction': direction} params.update(kwargs) return self.get_paginated(ENDPOINTS['member_position_ranking'].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, **params) - - def futures_minutes_batch(self, symbols: Any | None = None, interval: Any | None = None, start: Any | None = None, end: Any | None = None, limit: Any | None = None, *, raw: bool = False, fields: Sequence[str] | str | None = None, as_dataframe: bool = True, **kwargs: Any) -> Any: - """批量期货历史分钟行情.""" - params = {'symbols': symbols, 'interval': interval, 'start': start, 'end': end, 'limit': limit} - params.update(kwargs) - return self._call_endpoint('futures_minutes_batch', raw=raw, fields=fields, as_dataframe=as_dataframe, **params) diff --git a/src/ftshare/apis/index.py b/src/ftshare/apis/index.py index 05664fb..c8840f1 100644 --- a/src/ftshare/apis/index.py +++ b/src/ftshare/apis/index.py @@ -488,12 +488,12 @@ def sw_index_history_minutes(self, index_code: Any | None = None, start_date: An def index_minutes_batch(self, symbols: Any | None = None, interval_value: 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: """批量指数历史分钟行情.""" - params = {'symbols': symbols, 'interval_value': interval_value, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} + params = {'symbols': symbols_to_csv_string(symbols), 'interval_value': interval_value, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} params.update(kwargs) return self._call_endpoint('index_minutes_batch', raw=raw, fields=fields, as_dataframe=as_dataframe, **params) def index_candlesticks_batch(self, symbols: Any | None = None, interval_unit: 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线.""" - params = {'symbols': symbols, 'interval_unit': interval_unit, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} + params = {'symbols': symbols_to_csv_string(symbols), 'interval_unit': interval_unit, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} params.update(kwargs) return self._call_endpoint('index_candlesticks_batch', raw=raw, fields=fields, as_dataframe=as_dataframe, **params) diff --git a/src/ftshare/apis/stock.py b/src/ftshare/apis/stock.py index 7c89cce..bbfeba9 100644 --- a/src/ftshare/apis/stock.py +++ b/src/ftshare/apis/stock.py @@ -4793,13 +4793,13 @@ def ths_all_board_kline(self, start_date: Any | None = None, end_date: Any | Non def stock_candlesticks_batch(self, symbols: Any | None = None, interval_unit: 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线.""" - params = {'symbols': symbols, 'interval_unit': interval_unit, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} + params = {'symbols': symbols_to_csv_string(symbols), 'interval_unit': interval_unit, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} params.update(kwargs) return self._call_endpoint('stock_candlesticks_batch', raw=raw, fields=fields, as_dataframe=as_dataframe, **params) def stock_minutes_batch(self, symbols: 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: """批量股票历史分钟行情.""" - params = {'symbols': symbols, 'interval_value': interval_value, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} + params = {'symbols': symbols_to_csv_string(symbols), 'interval_value': interval_value, 'adjust_kind': adjust_kind, 'since_ts_millis': since_ts_millis, 'until_ts_millis': until_ts_millis, 'limit': limit} params.update(kwargs) return self._call_endpoint('stock_minutes_batch', raw=raw, fields=fields, as_dataframe=as_dataframe, **params) diff --git a/src/ftshare/endpoints/futures.py b/src/ftshare/endpoints/futures.py index 02d3437..a851964 100644 --- a/src/ftshare/endpoints/futures.py +++ b/src/ftshare/endpoints/futures.py @@ -146,12 +146,5 @@ 'original_api': 'member_position_ranking', 'params': ('exchange', 'instrument_id', 'trade_date', 'direction', 'page', 'page_size'), }, - 'futures_minutes_batch': { - 'path': 'api/v2/market/data/futures_minutes/batch', - 'title': '批量期货历史分钟行情', - 'doc_file': '批量期货历史分钟行情.md', - 'original_api': 'futures_minutes_batch', - 'params': ('symbols', 'interval', 'start', 'end', 'limit'), - }, }) diff --git a/tests/endpoint_cases.py b/tests/endpoint_cases.py index cf14a3a..a07777c 100644 --- a/tests/endpoint_cases.py +++ b/tests/endpoint_cases.py @@ -254,7 +254,6 @@ "eastmoney_futures_strange": {"exchange": "DCE", "variety": "A", "contract": "A2609", "trade_date": "20260820"}, "member_build_process": {"exchange": "DCE", "member_name": "永安期货", "instrument_id": "A2609", "start_date": "20260818", "end_date": "20260820", "contract_multiplier": 10, "page": 1, "page_size": 5}, "member_position_ranking": {"exchange": "DCE", "instrument_id": "A2609", "trade_date": "20260820", "direction": "long", "page": 1, "page_size": 5}, - "futures_minutes_batch": {"symbols": "A2609.DCE", "interval": "1min", "start": 1784048400000, "end": 1784050200000, "limit": 5}, "hsi_daily_weight": {"trade_date": 20260820, "start_date": None, "end_date": None, "index_slug": "HSI", "stock_code": None, "page": 1, "page_size": 5}, "stk_ah_comparison": {"hk_code": "00700.HK", "ts_code": None, "trade_date": 20260820, "start_date": None, "end_date": None, "page": 1, "page_size": 5}, "sw_index_history_minutes": {"index_code": "801001", "start_date": "20260818", "end_date": "20260820", "page": 1, "page_size": 5}, @@ -306,7 +305,6 @@ def _millis(day: str, time: str = "00:00:00") -> int: "futures_kline": {"symbol": "A2609.DCE", "interval": "daily", "start": _millis("2026-05-01"), "end": _millis("2026-07-17", "15:00:00"), "limit": 5}, "futures_kline_batch": {"symbols": "A2609.DCE", "interval": "daily", "start": _millis("2026-05-01"), "end": _millis("2026-07-17", "15:00:00"), "limit": 5}, "futures_minutes": {"symbol": "A2609.DCE", "symbols": None, "interval": "1min", "start": _millis("2026-07-17", "09:30:00"), "end": _millis("2026-07-17", "10:00:00"), "limit": 5}, - "futures_minutes_batch": {"symbols": "A2609.DCE", "interval": "1min", "start": _millis("2026-07-17", "09:30:00"), "end": _millis("2026-07-17", "10:00:00"), "limit": 5}, "futures_minutes_realtime": {"symbols": "A2609.DCE"}, "futures_realtime_day_kline": {"symbols": "A2609.DCE"}, "futures_nanhua_index_kline": {"code": "AG_NH", "trade_date": None, "start_date": None, "end_date": None, "page": 1, "page_size": 5}, diff --git a/tests/test_client.py b/tests/test_client.py index 4e74d65..0954637 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -350,7 +350,6 @@ def test_requested_endpoint_api_versions(): "eastmoney_futures_strange": "api/v1/market/data/eastmoney-futures-strange", "member_build_process": "api/v2/market/data/member-build-process", "member_position_ranking": "api/v2/market/data/member-position-ranking", - "futures_minutes_batch": "api/v2/market/data/futures_minutes/batch", "hsi_daily_weight": "api/v1/market/data/hk/hsi-daily-weight", "stk_ah_comparison": "api/v1/market/data/hk/stk-ah-comparison", "sw_index_history_minutes": "api/v1/market/data/sw-index/history-minutes", @@ -382,12 +381,13 @@ def test_requested_endpoint_api_versions(): assert {name: ENDPOINTS[name].path for name in expected_paths} == expected_paths -def test_new_batch_endpoints_forward_symbols_and_documented_parameters(): +def test_new_batch_endpoints_forward_symbols_as_comma_separated_string(): cases = [ ( "stock_candlesticks_batch", + ["600519.SH", "000001.SZ"], + "600519.SH,000001.SZ", { - "symbols": '["600519.SH"]', "interval_unit": "day", "adjust_kind": "forward", "since_ts_millis": 1784048400000, @@ -397,8 +397,9 @@ def test_new_batch_endpoints_forward_symbols_and_documented_parameters(): ), ( "etf_candlesticks_batch", + ["510300.SH", "159915.SZ"], + "510300.SH,159915.SZ", { - "symbols": '["510300.SH"]', "interval_unit": "day", "adjust_kind": "forward", "since_ts_millis": 1784048400000, @@ -408,8 +409,9 @@ def test_new_batch_endpoints_forward_symbols_and_documented_parameters(): ), ( "index_candlesticks_batch", + ["000300.SH", "000905.SH"], + "000300.SH,000905.SH", { - "symbols": '["000300.SH"]', "interval_unit": "day", "adjust_kind": "forward", "since_ts_millis": 1784048400000, @@ -419,8 +421,9 @@ def test_new_batch_endpoints_forward_symbols_and_documented_parameters(): ), ( "stock_minutes_batch", + ["600519.SH", "000001.SZ"], + "600519.SH,000001.SZ", { - "symbols": '["600519.SH"]', "interval_value": 1, "adjust_kind": "none", "since_ts_millis": 1784048400000, @@ -430,8 +433,9 @@ def test_new_batch_endpoints_forward_symbols_and_documented_parameters(): ), ( "etf_minutes_batch", + ["510300.SH", "159915.SZ"], + "510300.SH,159915.SZ", { - "symbols": '["510300.SH"]', "interval_value": 1, "adjust_kind": "none", "since_ts_millis": 1784048400000, @@ -441,8 +445,9 @@ def test_new_batch_endpoints_forward_symbols_and_documented_parameters(): ), ( "index_minutes_batch", + ["000300.SH", "000905.SH"], + "000300.SH,000905.SH", { - "symbols": '["000300.SH"]', "interval_value": 1, "since_ts_millis": 1784048400000, "until_ts_millis": 1784050200000, @@ -450,25 +455,28 @@ def test_new_batch_endpoints_forward_symbols_and_documented_parameters(): }, ), ( - "futures_minutes_batch", - { - "symbols": '["A2609.DCE"]', - "interval": "1min", - "start": 1784048400000, - "end": 1784050200000, - "limit": 5, - }, + "futures_minutes_realtime", + ["A2609.DCE", "CU2609.SHF"], + "A2609.DCE,CU2609.SHF", + {}, ), ] - for method_name, kwargs in cases: + for method_name, symbols, expected_symbols, kwargs in cases: session = FakeSession([FakeResponse(payload=[])]) client = FtshareClient(session=session) - getattr(client, method_name)(as_dataframe=False, **kwargs) + getattr(client, method_name)(symbols=symbols, as_dataframe=False, **kwargs) assert session.calls[0]["url"] == "https://market.ft.tech/gateway/" + ENDPOINTS[method_name].path - assert session.calls[0]["params"] == kwargs + assert session.calls[0]["params"] == {"symbols": expected_symbols, **kwargs} + + session = FakeSession([FakeResponse(payload=[])]) + client = FtshareClient(session=session) + + client.stock_candlesticks_batch(symbols='["600519.SH"]', interval_unit="day", since_ts_millis=1784048400000, until_ts_millis=1784050200000, as_dataframe=False) + + assert session.calls[0]["params"]["symbols"] == '["600519.SH"]' def test_eastmoney_etf_flow_allows_page_size_up_to_1000(): @@ -814,7 +822,7 @@ def test_futures_kline_batch_and_realtime_day_kline_forward_symbols_list(): assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v2/market/data/futures/kline/batch" assert session.calls[0]["params"] == { - "symbols": ["A2611.DCE", "M2611.DCE"], + "symbols": "A2611.DCE,M2611.DCE", "interval": "daily", "start": 1790784000000, "end": 1791647999000, @@ -827,7 +835,7 @@ def test_futures_kline_batch_and_realtime_day_kline_forward_symbols_list(): client.futures_realtime_day_kline(symbols=["A2611.DCE", "CU2611.SHF"], as_dataframe=False) assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v4/market/data/futures-realtime-day-kline" - assert session.calls[0]["params"] == {"symbols": ["A2611.DCE", "CU2611.SHF"]} + assert session.calls[0]["params"] == {"symbols": "A2611.DCE,CU2611.SHF"} def test_futures_minutes_forwards_symbols_for_batch_queries(): @@ -845,7 +853,7 @@ def test_futures_minutes_forwards_symbols_for_batch_queries(): assert session.calls[0]["url"] == "https://market.ft.tech/gateway/api/v2/market/data/futures_minutes" assert session.calls[0]["params"] == { - "symbols": ["A2611.DCE", "CU2611.SHF"], + "symbols": "A2611.DCE,CU2611.SHF", "interval": "5min", "start": 1791475200000, "end": 1791647999000, @@ -1344,7 +1352,7 @@ def test_convertible_bond_kline_family_forwards_documented_parameters(): "convertible_bond_candlesticks_batch", "api/v2/market/data/convertible-bond-candlesticks/batch", kline, - {"symbols": ["113042.SH", "123107.SZ"], "interval_unit": "Day", "since_ts_millis": 1786291200000, "until_ts_millis": 1786377599999, "limit": 1}, + {"symbols": "113042.SH,123107.SZ", "interval_unit": "Day", "since_ts_millis": 1786291200000, "until_ts_millis": 1786377599999, "limit": 1}, ), ( "convertible_bond_minute_candlesticks", @@ -1374,7 +1382,7 @@ def test_convertible_bond_kline_family_forwards_documented_parameters(): ) assert session.calls[0]["params"] == { - "symbols": ["113042.SH", "123107.SZ"], + "symbols": "113042.SH,123107.SZ", "since_ts_millis": 1786291200000, "until_ts_millis": 1786377599999, } diff --git a/tests/test_integration_market.py b/tests/test_integration_market.py index 2945fbd..17d022a 100644 --- a/tests/test_integration_market.py +++ b/tests/test_integration_market.py @@ -20,7 +20,6 @@ # server moves. KNOWN_SERVER_ISSUES: dict[str, str] = { "ashare_news_sentiment_factors": "HTTP 502 下游服务请求失败 for every parameter combination", - "futures_minutes_batch": "HTTP 404 请求的资源不存在 — route absent on the test server", }