jcdata 0.2.0__tar.gz → 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
jcdata-0.2.1/PKG-INFO ADDED
@@ -0,0 +1,198 @@
1
+ Metadata-Version: 2.4
2
+ Name: jcdata
3
+ Version: 0.2.1
4
+ Summary: Python client for JCDATA market data and factor APIs
5
+ Author: JiceQuant
6
+ License-Expression: LicenseRef-Proprietary
7
+ Project-URL: Homepage, https://jicequant.com/
8
+ Project-URL: Documentation, https://jicequant.com/
9
+ Project-URL: Repository, https://pypi.org/project/jcdata/
10
+ Keywords: finance,quant,market-data,china,a-share
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Financial and Insurance Industry
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Office/Business :: Financial :: Investment
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+ Requires-Dist: httpx>=0.24
26
+ Requires-Dist: pandas>=1.3
27
+ Requires-Dist: pyarrow>=14
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=7; extra == "dev"
30
+
31
+ # jcdata
32
+
33
+ `jcdata` 是 JCDATA 的 Python 客户端,用于获取市场数据、证券基础信息、因子、财务、ETF、期权、利率和宏观数据
34
+
35
+ ## 安装
36
+
37
+ ```bash
38
+ pip install jcdata
39
+ ```
40
+
41
+ ## 认证
42
+
43
+ 使用访问令牌登录。请将令牌保存在环境变量或密钥管理系统中,禁止写入源码、笔记本、日志或版本控制系统。
44
+
45
+ ```python
46
+ import jcdata
47
+
48
+ login_info = jcdata.login("YOUR_TOKEN")
49
+ if not login_info.get("user_name"):
50
+ raise PermissionError("令牌无效、已过期或无访问权限")
51
+
52
+ print(login_info["user_name"])
53
+ print(login_info["cell_quota_remaining"])
54
+ ```
55
+
56
+ 也可使用环境变量:
57
+
58
+ ```bash
59
+ # Linux / macOS
60
+ export JCDATA_TOKEN="YOUR_TOKEN"
61
+ ```
62
+
63
+ ```powershell
64
+ # Windows PowerShell
65
+ $env:JCDATA_TOKEN = "YOUR_TOKEN"
66
+ ```
67
+
68
+ ```python
69
+ jcdata.login()
70
+ ```
71
+
72
+ 令牌查找顺序为:`login(token=...)` 参数、`JCDATA_TOKEN` 环境变量、客户端配置。`login()` 返回用户名、接口使用量和剩余配额;认证未通过时这些字段为 `None`。
73
+
74
+ ## 基本使用
75
+
76
+ ```python
77
+ import jcdata
78
+
79
+ jcdata.login()
80
+
81
+ bars = jcdata.get_market_data(
82
+ "600000.SH",
83
+ "2025-01-02",
84
+ "2025-01-10",
85
+ fields=["date", "open", "high", "low", "close", "volume"],
86
+ )
87
+ frame = bars["600000.SH"]
88
+
89
+ if not frame.empty:
90
+ print(frame.tail())
91
+ ```
92
+
93
+ 多数按证券代码查询的接口返回 `dict[str, pandas.DataFrame]`:字典 key 为请求代码,DataFrame 中不依赖 `symbol` 列分组。没有匹配数据时也会保留对应的空 DataFrame,因此请显式处理 `frame.empty`。
94
+
95
+ 日期参数支持 `YYYY-MM-DD` 或 `YYYYMMDD`,例如 `2025-01-02` 或 `20250102`。
96
+
97
+ ## 常用接口
98
+
99
+ | 分类 | 接口 |
100
+ |---|---|
101
+ | 日 K | `get_market_data`、`iter_market_data`、`iter_market_data_batches` |
102
+ | 基础信息 | `get_instrument`、`get_adj_factor`、`get_settlement`、`get_future_contract` |
103
+ | 股票扩展 | `get_factors`、`get_valuation`、`get_market_value`、`get_finance`、`get_money_flow`、`get_margin`、`get_leader_board` |
104
+ | 期权 | `get_option_bars`、`get_option_greeks` |
105
+ | ETF | `get_etf_share`、`get_etf_tracking` |
106
+ | 日历与板块 | `get_trade_dates`、`get_all_sectors`、`get_stock_list_by_sector` |
107
+ | 利率与宏观 | `get_interest_rate`、`get_government_yield`、`get_macro_indicators` |
108
+
109
+ ## 批量行情
110
+
111
+ 直接传入代码列表即可查询多标的行情:
112
+
113
+ ```python
114
+ symbols = ["600000.SH", "000001.SZ", "510300.SH"]
115
+ bars = jcdata.get_market_data(symbols, "2025-01-02", "2025-01-10", fields=["date", "close"])
116
+
117
+ for symbol, frame in bars.items():
118
+ print(symbol, len(frame))
119
+ ```
120
+
121
+ 混合查询不同资产时,各 DataFrame 只返回该资产适用的字段。请按单个 DataFrame 的实际列名处理,不要假设所有资产具有相同字段。
122
+
123
+ ```python
124
+ mixed = jcdata.get_market_data(["600000.SH", "IF2501.CFE"], "2025-01-02", "2025-01-10")
125
+ print(mixed["600000.SH"].columns.tolist())
126
+ print(mixed["IF2501.CFE"].columns.tolist())
127
+ ```
128
+
129
+ ## 复权
130
+
131
+ `get_market_data()` 支持股票、ETF 和可转债复权:
132
+
133
+ ```python
134
+ adjusted = jcdata.get_market_data(
135
+ "600000.SH",
136
+ "2024-01-01",
137
+ "2025-01-31",
138
+ dividend_type="front",
139
+ fields=["date", "close"],
140
+ )
141
+ ```
142
+
143
+ 可用 `dividend_type`:`none`、`front`、`back`、`point`。使用 `point` 时必须同时传 `adjust_date`。指数不参与复权。
144
+
145
+ ## 大数据读取
146
+
147
+ 代码数量较多但希望按代码处理时,使用 `iter_market_data()`:
148
+
149
+ ```python
150
+ for chunk_symbols, frames in jcdata.iter_market_data(
151
+ symbols,
152
+ "2020-01-01",
153
+ "2025-01-01",
154
+ chunk_size=60,
155
+ fields=["date", "close", "volume"],
156
+ ):
157
+ for symbol in chunk_symbols:
158
+ process(frames[symbol])
159
+ ```
160
+
161
+ 超长历史数据使用 `iter_market_data_batches()`,并在循环内及时处理结果:
162
+
163
+ ```python
164
+ for present_symbols, frames in jcdata.iter_market_data_batches(
165
+ symbols,
166
+ "2015-01-01",
167
+ "2025-01-01",
168
+ fields=["date", "close"],
169
+ stream_batch_rows=65_536,
170
+ ):
171
+ for symbol in present_symbols:
172
+ frames[symbol].to_parquet(f"{symbol}.parquet", index=False)
173
+ ```
174
+
175
+ 同一代码可能跨多个批次出现。请不要将全部批次累积到内存中。
176
+
177
+ ## 错误处理
178
+
179
+ ```python
180
+ try:
181
+ jcdata.login()
182
+ bars = jcdata.get_market_data("600000.SH", "2025-01-02", "2025-01-10")
183
+ except jcdata.CellQuotaExceededError as exc:
184
+ print("配额已用尽,剩余:", exc.cell_quota_remaining)
185
+ except jcdata.InvalidParameterError as exc:
186
+ print("参数错误:", exc.param, exc.value)
187
+ except PermissionError as exc:
188
+ print("认证或授权失败:", exc)
189
+ ```
190
+
191
+ `CellQuotaExceededError` 是 `PermissionError` 的子类,因此应优先捕获。参数问题会引发 `InvalidParameterError`,可通过 `.param` 和 `.value` 定位。对于无效代码或正常无数据区间,按代码查询接口一般返回空 DataFrame,而非异常。
192
+
193
+ ## 更多说明
194
+
195
+ - 代码格式通常为 `代码.市场后缀`,例如 `600000.SH`、`000001.SZ`、`IF2501.CFE`。
196
+ - 使用 `get_asset_type_by_symbol()` 可识别常见代码的资产类型。
197
+ - 使用 `fields` 限定实际需要的列,可减少传输量和处理成本。
198
+ - 有访问频率或配额限制时,请避免无上限并发和紧密重试;应控制并发、缩小查询范围并保存任务进度。
jcdata-0.2.1/README.md ADDED
@@ -0,0 +1,168 @@
1
+ # jcdata
2
+
3
+ `jcdata` 是 JCDATA 的 Python 客户端,用于获取市场数据、证券基础信息、因子、财务、ETF、期权、利率和宏观数据
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ pip install jcdata
9
+ ```
10
+
11
+ ## 认证
12
+
13
+ 使用访问令牌登录。请将令牌保存在环境变量或密钥管理系统中,禁止写入源码、笔记本、日志或版本控制系统。
14
+
15
+ ```python
16
+ import jcdata
17
+
18
+ login_info = jcdata.login("YOUR_TOKEN")
19
+ if not login_info.get("user_name"):
20
+ raise PermissionError("令牌无效、已过期或无访问权限")
21
+
22
+ print(login_info["user_name"])
23
+ print(login_info["cell_quota_remaining"])
24
+ ```
25
+
26
+ 也可使用环境变量:
27
+
28
+ ```bash
29
+ # Linux / macOS
30
+ export JCDATA_TOKEN="YOUR_TOKEN"
31
+ ```
32
+
33
+ ```powershell
34
+ # Windows PowerShell
35
+ $env:JCDATA_TOKEN = "YOUR_TOKEN"
36
+ ```
37
+
38
+ ```python
39
+ jcdata.login()
40
+ ```
41
+
42
+ 令牌查找顺序为:`login(token=...)` 参数、`JCDATA_TOKEN` 环境变量、客户端配置。`login()` 返回用户名、接口使用量和剩余配额;认证未通过时这些字段为 `None`。
43
+
44
+ ## 基本使用
45
+
46
+ ```python
47
+ import jcdata
48
+
49
+ jcdata.login()
50
+
51
+ bars = jcdata.get_market_data(
52
+ "600000.SH",
53
+ "2025-01-02",
54
+ "2025-01-10",
55
+ fields=["date", "open", "high", "low", "close", "volume"],
56
+ )
57
+ frame = bars["600000.SH"]
58
+
59
+ if not frame.empty:
60
+ print(frame.tail())
61
+ ```
62
+
63
+ 多数按证券代码查询的接口返回 `dict[str, pandas.DataFrame]`:字典 key 为请求代码,DataFrame 中不依赖 `symbol` 列分组。没有匹配数据时也会保留对应的空 DataFrame,因此请显式处理 `frame.empty`。
64
+
65
+ 日期参数支持 `YYYY-MM-DD` 或 `YYYYMMDD`,例如 `2025-01-02` 或 `20250102`。
66
+
67
+ ## 常用接口
68
+
69
+ | 分类 | 接口 |
70
+ |---|---|
71
+ | 日 K | `get_market_data`、`iter_market_data`、`iter_market_data_batches` |
72
+ | 基础信息 | `get_instrument`、`get_adj_factor`、`get_settlement`、`get_future_contract` |
73
+ | 股票扩展 | `get_factors`、`get_valuation`、`get_market_value`、`get_finance`、`get_money_flow`、`get_margin`、`get_leader_board` |
74
+ | 期权 | `get_option_bars`、`get_option_greeks` |
75
+ | ETF | `get_etf_share`、`get_etf_tracking` |
76
+ | 日历与板块 | `get_trade_dates`、`get_all_sectors`、`get_stock_list_by_sector` |
77
+ | 利率与宏观 | `get_interest_rate`、`get_government_yield`、`get_macro_indicators` |
78
+
79
+ ## 批量行情
80
+
81
+ 直接传入代码列表即可查询多标的行情:
82
+
83
+ ```python
84
+ symbols = ["600000.SH", "000001.SZ", "510300.SH"]
85
+ bars = jcdata.get_market_data(symbols, "2025-01-02", "2025-01-10", fields=["date", "close"])
86
+
87
+ for symbol, frame in bars.items():
88
+ print(symbol, len(frame))
89
+ ```
90
+
91
+ 混合查询不同资产时,各 DataFrame 只返回该资产适用的字段。请按单个 DataFrame 的实际列名处理,不要假设所有资产具有相同字段。
92
+
93
+ ```python
94
+ mixed = jcdata.get_market_data(["600000.SH", "IF2501.CFE"], "2025-01-02", "2025-01-10")
95
+ print(mixed["600000.SH"].columns.tolist())
96
+ print(mixed["IF2501.CFE"].columns.tolist())
97
+ ```
98
+
99
+ ## 复权
100
+
101
+ `get_market_data()` 支持股票、ETF 和可转债复权:
102
+
103
+ ```python
104
+ adjusted = jcdata.get_market_data(
105
+ "600000.SH",
106
+ "2024-01-01",
107
+ "2025-01-31",
108
+ dividend_type="front",
109
+ fields=["date", "close"],
110
+ )
111
+ ```
112
+
113
+ 可用 `dividend_type`:`none`、`front`、`back`、`point`。使用 `point` 时必须同时传 `adjust_date`。指数不参与复权。
114
+
115
+ ## 大数据读取
116
+
117
+ 代码数量较多但希望按代码处理时,使用 `iter_market_data()`:
118
+
119
+ ```python
120
+ for chunk_symbols, frames in jcdata.iter_market_data(
121
+ symbols,
122
+ "2020-01-01",
123
+ "2025-01-01",
124
+ chunk_size=60,
125
+ fields=["date", "close", "volume"],
126
+ ):
127
+ for symbol in chunk_symbols:
128
+ process(frames[symbol])
129
+ ```
130
+
131
+ 超长历史数据使用 `iter_market_data_batches()`,并在循环内及时处理结果:
132
+
133
+ ```python
134
+ for present_symbols, frames in jcdata.iter_market_data_batches(
135
+ symbols,
136
+ "2015-01-01",
137
+ "2025-01-01",
138
+ fields=["date", "close"],
139
+ stream_batch_rows=65_536,
140
+ ):
141
+ for symbol in present_symbols:
142
+ frames[symbol].to_parquet(f"{symbol}.parquet", index=False)
143
+ ```
144
+
145
+ 同一代码可能跨多个批次出现。请不要将全部批次累积到内存中。
146
+
147
+ ## 错误处理
148
+
149
+ ```python
150
+ try:
151
+ jcdata.login()
152
+ bars = jcdata.get_market_data("600000.SH", "2025-01-02", "2025-01-10")
153
+ except jcdata.CellQuotaExceededError as exc:
154
+ print("配额已用尽,剩余:", exc.cell_quota_remaining)
155
+ except jcdata.InvalidParameterError as exc:
156
+ print("参数错误:", exc.param, exc.value)
157
+ except PermissionError as exc:
158
+ print("认证或授权失败:", exc)
159
+ ```
160
+
161
+ `CellQuotaExceededError` 是 `PermissionError` 的子类,因此应优先捕获。参数问题会引发 `InvalidParameterError`,可通过 `.param` 和 `.value` 定位。对于无效代码或正常无数据区间,按代码查询接口一般返回空 DataFrame,而非异常。
162
+
163
+ ## 更多说明
164
+
165
+ - 代码格式通常为 `代码.市场后缀`,例如 `600000.SH`、`000001.SZ`、`IF2501.CFE`。
166
+ - 使用 `get_asset_type_by_symbol()` 可识别常见代码的资产类型。
167
+ - 使用 `fields` 限定实际需要的列,可减少传输量和处理成本。
168
+ - 有访问频率或配额限制时,请避免无上限并发和紧密重试;应控制并发、缩小查询范围并保存任务进度。
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """
3
- JCDATA 客户端:连接数据服务后取历史行情与因子数据。
3
+ JCDATA Python 客户端:用于查询市场数据和相关数据集。
4
4
 
5
5
  使用前调用 ``jcdata.login("...")``(或设置环境变量 ``JCDATA_TOKEN``)::
6
6
 
@@ -15,10 +15,13 @@ from ._http import current_user, login, whoami
15
15
  from .errors import CellQuotaExceededError, ErrorCode, InvalidParameterError, RowQuotaExceededError
16
16
  from .data import (
17
17
  get_adj_factor,
18
+ get_asset_type_by_symbol,
18
19
  get_etf_share,
19
20
  get_etf_tracking,
20
21
  get_finance,
22
+ get_factors,
21
23
  get_future_contract,
24
+ get_government_yield,
22
25
  get_instrument,
23
26
  get_interest_rate,
24
27
  get_leader_board,
@@ -27,9 +30,10 @@ from .data import (
27
30
  iter_market_data,
28
31
  iter_market_data_batches,
29
32
  get_market_value,
33
+ get_macro_indicators,
30
34
  get_money_flow,
31
35
  get_option_bars,
32
- get_option_info,
36
+ get_option_greeks,
33
37
  get_settlement,
34
38
  get_all_sectors,
35
39
  get_stock_list_by_sector,
@@ -37,7 +41,7 @@ from .data import (
37
41
  get_valuation,
38
42
  )
39
43
 
40
- __version__ = "0.1.6"
44
+ __version__ = "0.2.1"
41
45
 
42
46
  __all__ = [
43
47
  "__version__",
@@ -49,6 +53,7 @@ __all__ = [
49
53
  "InvalidParameterError",
50
54
  "RowQuotaExceededError",
51
55
  "get_market_data",
56
+ "get_asset_type_by_symbol",
52
57
  "iter_market_data",
53
58
  "iter_market_data_batches",
54
59
  "get_instrument",
@@ -57,12 +62,15 @@ __all__ = [
57
62
  "get_future_contract",
58
63
  "get_valuation",
59
64
  "get_market_value",
65
+ "get_government_yield",
66
+ "get_macro_indicators",
60
67
  "get_finance",
68
+ "get_factors",
61
69
  "get_trade_dates",
62
70
  "get_all_sectors",
63
71
  "get_stock_list_by_sector",
64
72
  "get_option_bars",
65
- "get_option_info",
73
+ "get_option_greeks",
66
74
  "get_money_flow",
67
75
  "get_margin",
68
76
  "get_leader_board",
@@ -77,24 +77,28 @@ def _resolve_timeout(timeout_sec: float | None) -> float:
77
77
  return timeout_sec if timeout_sec is not None else config.TIMEOUT_SEC
78
78
 
79
79
 
80
+ def _login_result(body: dict[str, Any] | None = None) -> dict[str, Any]:
81
+ """构造 login 的稳定返回结构。"""
82
+ body = body or {}
83
+ return {
84
+ "user_name": body.get("user_name"),
85
+ "api_usage_week": body.get("api_usage_week"),
86
+ "api_usage_month": body.get("api_usage_month"),
87
+ "cell_quota_remaining": body.get("cell_quota_remaining"),
88
+ }
89
+
90
+
80
91
  def login(
81
92
  token: str | None = None,
82
93
  *,
83
94
  port: int | None = None,
84
95
  timeout_sec: float | None = None,
85
- ) -> None:
96
+ ) -> dict[str, Any]:
86
97
  """
87
- 连接数据服务并校验访问令牌。
88
-
89
- 参数:
90
- token: 访问令牌,优先级:参数 > 环境变量 JCDATA_TOKEN > config.TOKEN
91
- port: API 服务端口,优先级:参数 > 环境变量 JCDATA_PORT > config.PORT
92
- timeout_sec: 请求超时时间(秒),默认使用 config.TIMEOUT_SEC
98
+ 连接数据服务并校验访问令牌,返回当前用户和数据用量信息。
93
99
 
94
- 服务地址读取 config.BASE_URL;修改请编辑 jcdata/config.py。
95
-
96
- 示例:
97
- >>> jcdata.login("your_token")
100
+ 返回值固定含有 ``user_name``、``api_usage_week``、``api_usage_month``、
101
+ ``cell_quota_remaining`` 四个键。令牌未通过认证时,各值均为 ``None``。
98
102
  """
99
103
  global _client, _user_name, _authenticated
100
104
 
@@ -102,21 +106,27 @@ def login(
102
106
  key = _resolve_token(token)
103
107
  resolved_port = _resolve_port(port)
104
108
  to = _resolve_timeout(timeout_sec)
105
-
106
- headers = {
107
- "Authorization": f"Bearer {key}",
108
- "X-Api-Key": key,
109
- }
109
+ headers = {"Authorization": f"Bearer {key}", "X-Api-Key": key}
110
110
 
111
111
  if _client is not None:
112
112
  _client.close()
113
113
 
114
114
  final_url = _build_base_url(url, resolved_port)
115
115
  _client = httpx.Client(base_url=final_url, timeout=to, headers=headers)
116
-
117
- _user_name, _authenticated = _whoami_request()
118
- if not _authenticated:
119
- raise PermissionError("令牌校验未通过,请检查访问令牌")
116
+ response = _client.get("/api/v1/auth/whoami")
117
+ if response.status_code in (401, 403):
118
+ _user_name = None
119
+ _authenticated = False
120
+ return _login_result()
121
+ response.raise_for_status()
122
+ body = response.json()
123
+ if not isinstance(body, dict) or not body.get("user_name"):
124
+ _user_name = None
125
+ _authenticated = False
126
+ return _login_result()
127
+ _user_name = str(body["user_name"])
128
+ _authenticated = True
129
+ return _login_result(body)
120
130
 
121
131
 
122
132
  def whoami() -> str | None:
@@ -141,7 +151,8 @@ def _whoami_request() -> tuple[str | None, bool]:
141
151
  raise PermissionError("令牌无效或已过期")
142
152
  r.raise_for_status()
143
153
  body = r.json()
144
- return body.get("user_name"), bool(body.get("authenticated"))
154
+ user_name = body.get("user_name")
155
+ return user_name, bool(user_name)
145
156
 
146
157
 
147
158
  def _client_or_raise() -> httpx.Client:
@@ -177,9 +188,14 @@ def _raise_for_detail(status_code: int, detail: dict | str | None) -> None:
177
188
  param=detail.get("param"),
178
189
  value=detail.get("value"),
179
190
  )
180
- if status_code == 400:
191
+ if status_code in (400, 422):
181
192
  if isinstance(detail, dict):
182
- raise InvalidParameterError(str(detail.get("message") or "请求参数不合法"))
193
+ raise InvalidParameterError(
194
+ str(detail.get("message") or "请求参数不合法"),
195
+ code=str(detail.get("code") or ErrorCode.INVALID_PARAMETER),
196
+ param=detail.get("param"),
197
+ value=detail.get("value"),
198
+ )
183
199
  raise InvalidParameterError(str(detail) if detail else "请求参数不合法")
184
200
  if status_code == 401:
185
201
  raise PermissionError("未授权,请先 jcdata.login()")
@@ -208,7 +224,7 @@ def _retry_after_seconds(r: httpx.Response, detail: dict | str | None) -> float:
208
224
 
209
225
  def _raise_http_error(r: httpx.Response) -> None:
210
226
  detail = _parse_error_detail(r)
211
- if r.status_code in (400, 401, 403, 429):
227
+ if r.status_code in (400, 401, 403, 422, 429):
212
228
  _raise_for_detail(r.status_code, detail)
213
229
  r.raise_for_status()
214
230
 
@@ -368,7 +384,7 @@ def _post_query(
368
384
 
369
385
 
370
386
  def iter_stream_bars(params: dict[str, Any]) -> Iterator[dict[str, pd.DataFrame]]:
371
- """以 HTTP 流逐段读取 Zstd Arrow 日 K,不缓冲完整响应体。"""
387
+ """逐批读取日 K 数据,不缓冲完整响应体。"""
372
388
  from ._arrow import ARROW_ZSTD_MEDIA_TYPE, iter_zstd_arrow_by_symbol
373
389
 
374
390
  client = _client_or_raise()
jcdata-0.2.1/config.py ADDED
@@ -0,0 +1,23 @@
1
+ # -*- coding: utf-8 -*-
2
+ """jcdata 客户端默认配置。
3
+
4
+ 生产环境请通过环境变量或 ``jcdata.login(token=...)`` 提供访问令牌。
5
+ 不要将访问令牌写入源码、配置文件或版本控制系统。
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ # 服务地址。一般无需修改;私有部署可按本单位要求覆盖。
11
+ BASE_URL = "https://api.jicequant.com"
12
+ PORT = None
13
+
14
+ # 单次请求超时(秒)。
15
+ TIMEOUT_SEC = 3600.0
16
+
17
+ # 不在发行包中保存令牌。此变量仅保留配置兼容性;优先使用
18
+ # login(token=...) 或环境变量 JCDATA_TOKEN。
19
+ TOKEN = ""
20
+
21
+ # 多代码查询的客户端行为配置。
22
+ USE_POST_BULK = True
23
+ POST_MIN_SYMBOLS = 2