tokease 1.13.2__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.
- tokease-1.13.2/MANIFEST.in +2 -0
- tokease-1.13.2/PKG-INFO +94 -0
- tokease-1.13.2/README.md +71 -0
- tokease-1.13.2/pyproject.toml +43 -0
- tokease-1.13.2/setup.cfg +4 -0
- tokease-1.13.2/src/tokease/__init__.py +31 -0
- tokease-1.13.2/src/tokease/_pkg_version.txt +1 -0
- tokease-1.13.2/src/tokease/catalog.py +393 -0
- tokease-1.13.2/src/tokease/client.py +434 -0
- tokease-1.13.2/src/tokease/errors.py +34 -0
- tokease-1.13.2/src/tokease/version.py +48 -0
- tokease-1.13.2/src/tokease.egg-info/PKG-INFO +94 -0
- tokease-1.13.2/src/tokease.egg-info/SOURCES.txt +17 -0
- tokease-1.13.2/src/tokease.egg-info/dependency_links.txt +1 -0
- tokease-1.13.2/src/tokease.egg-info/requires.txt +3 -0
- tokease-1.13.2/src/tokease.egg-info/top_level.txt +1 -0
- tokease-1.13.2/tests/test_catalog.py +71 -0
- tokease-1.13.2/tests/test_client.py +155 -0
- tokease-1.13.2/tokease_build.py +64 -0
tokease-1.13.2/PKG-INFO
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tokease
|
|
3
|
+
Version: 1.13.2
|
|
4
|
+
Summary: 词易算力指数平台 Python SDK:查看接口参数并查询行情数据
|
|
5
|
+
Author: WhaleIndex
|
|
6
|
+
Project-URL: Homepage, https://whale.tokease.cn/
|
|
7
|
+
Project-URL: Documentation, https://whale.tokease.cn/handbook/
|
|
8
|
+
Project-URL: Repository, https://github.com/fyinfor/WhaleIndex
|
|
9
|
+
Project-URL: Changelog, https://github.com/fyinfor/WhaleIndex/releases
|
|
10
|
+
Keywords: tokease,whaleindex,index,api
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Provides-Extra: pandas
|
|
22
|
+
Requires-Dist: pandas>=2; extra == "pandas"
|
|
23
|
+
|
|
24
|
+
# tokease
|
|
25
|
+
|
|
26
|
+
词易算力指数平台的 Python SDK。不发请求也能查看每个接口的输入参数和输出字段;配置 API Key 后可以查询 `index_basic`、`index_daily`、`index_quote`、`trade_cal`,以及无需 Key 的公开行情接口。
|
|
27
|
+
|
|
28
|
+
## 安装
|
|
29
|
+
|
|
30
|
+
发布到 PyPI 之后:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install tokease
|
|
34
|
+
pip install "tokease[pandas]"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
在仓库里开发:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install -e python/tokease
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 查看接口参数
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import tokease
|
|
47
|
+
|
|
48
|
+
tokease.apis()
|
|
49
|
+
tokease.apis("query")
|
|
50
|
+
tokease.api_params("index_daily")
|
|
51
|
+
tokease.api_fields("index_daily")
|
|
52
|
+
tokease.describe("index_quote")
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`api_params` 返回的名称与 `POST /api/v1/query` 的参数白名单一致。未知参数会在本地直接拒绝,不会发给服务端。
|
|
56
|
+
|
|
57
|
+
## 查询数据
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import tokease
|
|
61
|
+
|
|
62
|
+
client = tokease.Client(api_key="tokease_xxxxxxxxxxxx_xxxxxxxx")
|
|
63
|
+
frame = client.index_daily(
|
|
64
|
+
index_code="Server_Index",
|
|
65
|
+
start_date="20260801",
|
|
66
|
+
end_date="20260831",
|
|
67
|
+
fields=["trade_date", "index_code", "index_value", "change_rate"],
|
|
68
|
+
).to_dataframe()
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
API Key 也可以通过环境变量 `TOKEASE_API_KEY` 传入。服务地址是 `pyproject.toml` 里的 `Homepage`,当前为 `https://whale.tokease.cn`。
|
|
72
|
+
|
|
73
|
+
默认会按 `has_more` 自动翻页。只要单页时传入 `paginate=False`。
|
|
74
|
+
|
|
75
|
+
公开接口不需要 API Key:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
client = tokease.Client()
|
|
79
|
+
client.public_indices()
|
|
80
|
+
client.public_index_latest("Server_Index")
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 发布到 PyPI
|
|
84
|
+
|
|
85
|
+
版本号始终等于仓库根目录 `package.json` 的 `version`,不要在 Python 包里另写一份。PyPI 上每个版本只能上传一次。
|
|
86
|
+
|
|
87
|
+
发布使用 PyPI API Token,不使用 GitHub 受信发布。在 PyPI 账号设置里创建令牌,范围选 **Entire account**,再写入本仓库的 Actions secret `PYPI_API_TOKEN`。之后推送与系统版本一致的标签即可发布。本地 `.githooks/pre-push` 会先核对,版本不一致时标签推不上去:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
git tag v1.13.1
|
|
91
|
+
git push origin v1.13.1
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
也可以在 GitHub Actions 里手动运行 **Publish tokease**,选择 `pypi` 或 `testpypi`。TestPyPI 需要在 test.pypi.org 另建一个 API Token,并换成对应的 secret。
|
tokease-1.13.2/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# tokease
|
|
2
|
+
|
|
3
|
+
词易算力指数平台的 Python SDK。不发请求也能查看每个接口的输入参数和输出字段;配置 API Key 后可以查询 `index_basic`、`index_daily`、`index_quote`、`trade_cal`,以及无需 Key 的公开行情接口。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
发布到 PyPI 之后:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install tokease
|
|
11
|
+
pip install "tokease[pandas]"
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
在仓库里开发:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install -e python/tokease
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 查看接口参数
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import tokease
|
|
24
|
+
|
|
25
|
+
tokease.apis()
|
|
26
|
+
tokease.apis("query")
|
|
27
|
+
tokease.api_params("index_daily")
|
|
28
|
+
tokease.api_fields("index_daily")
|
|
29
|
+
tokease.describe("index_quote")
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`api_params` 返回的名称与 `POST /api/v1/query` 的参数白名单一致。未知参数会在本地直接拒绝,不会发给服务端。
|
|
33
|
+
|
|
34
|
+
## 查询数据
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
import tokease
|
|
38
|
+
|
|
39
|
+
client = tokease.Client(api_key="tokease_xxxxxxxxxxxx_xxxxxxxx")
|
|
40
|
+
frame = client.index_daily(
|
|
41
|
+
index_code="Server_Index",
|
|
42
|
+
start_date="20260801",
|
|
43
|
+
end_date="20260831",
|
|
44
|
+
fields=["trade_date", "index_code", "index_value", "change_rate"],
|
|
45
|
+
).to_dataframe()
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
API Key 也可以通过环境变量 `TOKEASE_API_KEY` 传入。服务地址是 `pyproject.toml` 里的 `Homepage`,当前为 `https://whale.tokease.cn`。
|
|
49
|
+
|
|
50
|
+
默认会按 `has_more` 自动翻页。只要单页时传入 `paginate=False`。
|
|
51
|
+
|
|
52
|
+
公开接口不需要 API Key:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
client = tokease.Client()
|
|
56
|
+
client.public_indices()
|
|
57
|
+
client.public_index_latest("Server_Index")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## 发布到 PyPI
|
|
61
|
+
|
|
62
|
+
版本号始终等于仓库根目录 `package.json` 的 `version`,不要在 Python 包里另写一份。PyPI 上每个版本只能上传一次。
|
|
63
|
+
|
|
64
|
+
发布使用 PyPI API Token,不使用 GitHub 受信发布。在 PyPI 账号设置里创建令牌,范围选 **Entire account**,再写入本仓库的 Actions secret `PYPI_API_TOKEN`。之后推送与系统版本一致的标签即可发布。本地 `.githooks/pre-push` 会先核对,版本不一致时标签推不上去:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git tag v1.13.1
|
|
68
|
+
git push origin v1.13.1
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
也可以在 GitHub Actions 里手动运行 **Publish tokease**,选择 `pypi` 或 `testpypi`。TestPyPI 需要在 test.pypi.org 另建一个 API Token,并换成对应的 secret。
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "tokease_build"
|
|
4
|
+
backend-path = ["."]
|
|
5
|
+
|
|
6
|
+
[project]
|
|
7
|
+
name = "tokease"
|
|
8
|
+
dynamic = ["version"]
|
|
9
|
+
description = "词易算力指数平台 Python SDK:查看接口参数并查询行情数据"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [{ name = "WhaleIndex" }]
|
|
13
|
+
keywords = ["tokease", "whaleindex", "index", "api"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Topic :: Office/Business :: Financial",
|
|
23
|
+
]
|
|
24
|
+
dependencies = []
|
|
25
|
+
|
|
26
|
+
[project.optional-dependencies]
|
|
27
|
+
pandas = ["pandas>=2"]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Homepage = "https://whale.tokease.cn/"
|
|
31
|
+
Documentation = "https://whale.tokease.cn/handbook/"
|
|
32
|
+
Repository = "https://github.com/fyinfor/WhaleIndex"
|
|
33
|
+
Changelog = "https://github.com/fyinfor/WhaleIndex/releases"
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.dynamic]
|
|
36
|
+
version = { attr = "tokease.version.__version__" }
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.packages.find]
|
|
39
|
+
where = ["src"]
|
|
40
|
+
include = ["tokease*"]
|
|
41
|
+
|
|
42
|
+
[tool.setuptools.package-data]
|
|
43
|
+
tokease = ["_pkg_version.txt"]
|
tokease-1.13.2/setup.cfg
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""词易算力指数平台 Python SDK。"""
|
|
2
|
+
|
|
3
|
+
from tokease.catalog import (
|
|
4
|
+
APISpec,
|
|
5
|
+
Field,
|
|
6
|
+
Param,
|
|
7
|
+
api_fields,
|
|
8
|
+
api_params,
|
|
9
|
+
apis,
|
|
10
|
+
describe,
|
|
11
|
+
get_api,
|
|
12
|
+
)
|
|
13
|
+
from tokease.client import Client, QueryResult
|
|
14
|
+
from tokease.errors import TokeaseAPIError, TokeaseError
|
|
15
|
+
from tokease.version import __version__
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"__version__",
|
|
19
|
+
"APISpec",
|
|
20
|
+
"Client",
|
|
21
|
+
"Field",
|
|
22
|
+
"Param",
|
|
23
|
+
"QueryResult",
|
|
24
|
+
"TokeaseAPIError",
|
|
25
|
+
"TokeaseError",
|
|
26
|
+
"api_fields",
|
|
27
|
+
"api_params",
|
|
28
|
+
"apis",
|
|
29
|
+
"describe",
|
|
30
|
+
"get_api",
|
|
31
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.13.2
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
"""算力指数平台接口参数目录。
|
|
2
|
+
|
|
3
|
+
参数名、字段名与服务端白名单一致,见 ``POST /api/v1/query`` 与公开行情接口。
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from dataclasses import asdict, dataclass
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from tokease.errors import TokeaseError
|
|
12
|
+
|
|
13
|
+
QUERY_PATH = "/api/v1/query"
|
|
14
|
+
DEFAULT_LIMIT = 1000
|
|
15
|
+
MAX_LIMIT = 5000
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(frozen=True)
|
|
19
|
+
class Param:
|
|
20
|
+
"""单个输入参数。"""
|
|
21
|
+
|
|
22
|
+
name: str
|
|
23
|
+
type: str
|
|
24
|
+
required: bool
|
|
25
|
+
description: str
|
|
26
|
+
location: str = "params"
|
|
27
|
+
|
|
28
|
+
def as_dict(self) -> dict[str, Any]:
|
|
29
|
+
return asdict(self)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass(frozen=True)
|
|
33
|
+
class Field:
|
|
34
|
+
"""单个输出字段。"""
|
|
35
|
+
|
|
36
|
+
name: str
|
|
37
|
+
type: str
|
|
38
|
+
description: str
|
|
39
|
+
|
|
40
|
+
def as_dict(self) -> dict[str, Any]:
|
|
41
|
+
return asdict(self)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass(frozen=True)
|
|
45
|
+
class APISpec:
|
|
46
|
+
"""一个数据集或公开接口的完整说明。"""
|
|
47
|
+
|
|
48
|
+
name: str
|
|
49
|
+
kind: str
|
|
50
|
+
summary: str
|
|
51
|
+
method: str
|
|
52
|
+
path: str
|
|
53
|
+
params: tuple[Param, ...]
|
|
54
|
+
fields: tuple[Field, ...]
|
|
55
|
+
scope: str | None = None
|
|
56
|
+
timeliness: str = "none"
|
|
57
|
+
default_fields: tuple[str, ...] = ()
|
|
58
|
+
sort: tuple[str, ...] = ()
|
|
59
|
+
# 不能同时出现的参数组。例如 trade_date 不能和 start_date/end_date 一起用。
|
|
60
|
+
exclusive: tuple[tuple[str, ...], ...] = ()
|
|
61
|
+
|
|
62
|
+
def as_dict(self) -> dict[str, Any]:
|
|
63
|
+
return {
|
|
64
|
+
"name": self.name,
|
|
65
|
+
"kind": self.kind,
|
|
66
|
+
"summary": self.summary,
|
|
67
|
+
"method": self.method,
|
|
68
|
+
"path": self.path,
|
|
69
|
+
"scope": self.scope,
|
|
70
|
+
"timeliness": self.timeliness,
|
|
71
|
+
"params": [item.as_dict() for item in self.params],
|
|
72
|
+
"fields": [item.as_dict() for item in self.fields],
|
|
73
|
+
"default_fields": list(self.default_fields),
|
|
74
|
+
"sort": list(self.sort),
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _param(name: str, description: str, *, required: bool = False, type: str = "str", location: str = "params") -> Param:
|
|
79
|
+
return Param(name=name, type=type, required=required, description=description, location=location)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _field(name: str, type: str, description: str) -> Field:
|
|
83
|
+
return Field(name=name, type=type, description=description)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
_DATE = "日期,YYYYMMDD 或 YYYY-MM-DD,含边界"
|
|
87
|
+
|
|
88
|
+
_APIS: dict[str, APISpec] = {
|
|
89
|
+
"index_basic": APISpec(
|
|
90
|
+
name="index_basic",
|
|
91
|
+
kind="query",
|
|
92
|
+
summary="指数基本信息",
|
|
93
|
+
method="POST",
|
|
94
|
+
path=QUERY_PATH,
|
|
95
|
+
scope="index:read",
|
|
96
|
+
timeliness="none",
|
|
97
|
+
params=(_param("index_code", "指数代码,精确匹配,如 Server_Index"),),
|
|
98
|
+
fields=(
|
|
99
|
+
_field("index_code", "str", "唯一指数代码,例如 Server_Index"),
|
|
100
|
+
_field("index_name", "str", "指数中文名称"),
|
|
101
|
+
_field("description", "str", "指数说明;未填写时为空字符串"),
|
|
102
|
+
_field("base_date", "str|null", "基准日期,YYYYMMDD"),
|
|
103
|
+
_field("base_value", "decimal", "基准点位"),
|
|
104
|
+
_field("visibility", "str", "公开范围:private / index_only / aggregate / member"),
|
|
105
|
+
_field("enabled", "bool", "是否启用"),
|
|
106
|
+
),
|
|
107
|
+
default_fields=("index_code", "index_name", "description", "base_date", "base_value", "visibility", "enabled"),
|
|
108
|
+
sort=("sort_no", "index_code"),
|
|
109
|
+
),
|
|
110
|
+
"index_daily": APISpec(
|
|
111
|
+
name="index_daily",
|
|
112
|
+
kind="query",
|
|
113
|
+
summary="指数日线(点位 / 加权价格)",
|
|
114
|
+
method="POST",
|
|
115
|
+
path=QUERY_PATH,
|
|
116
|
+
scope="index:read",
|
|
117
|
+
timeliness="member",
|
|
118
|
+
params=(
|
|
119
|
+
_param("index_code", "指数代码,如 Server_Index"),
|
|
120
|
+
_param("trade_date", "交易日期,不能与 start_date/end_date 同用"),
|
|
121
|
+
_param("start_date", f"开始{_DATE}"),
|
|
122
|
+
_param("end_date", f"结束{_DATE}"),
|
|
123
|
+
),
|
|
124
|
+
fields=(
|
|
125
|
+
_field("trade_date", "str", "交易日期,YYYYMMDD"),
|
|
126
|
+
_field("index_code", "str", "指数代码"),
|
|
127
|
+
_field("weighted_price", "decimal", "整体加权价格 Σ(price × weight)"),
|
|
128
|
+
_field("index_value", "decimal", "当日指数点位"),
|
|
129
|
+
_field("previous_price", "decimal|null", "上一可计算报价日的整体价格"),
|
|
130
|
+
_field("previous_index", "decimal|null", "上一可计算报价日的指数点位"),
|
|
131
|
+
_field("change_rate", "decimal", "涨跌比例,0.0123 表示 1.23%"),
|
|
132
|
+
_field("calculated_at", "str", "计算时间,RFC 3339"),
|
|
133
|
+
),
|
|
134
|
+
default_fields=(
|
|
135
|
+
"trade_date",
|
|
136
|
+
"index_code",
|
|
137
|
+
"weighted_price",
|
|
138
|
+
"index_value",
|
|
139
|
+
"previous_price",
|
|
140
|
+
"previous_index",
|
|
141
|
+
"change_rate",
|
|
142
|
+
"calculated_at",
|
|
143
|
+
),
|
|
144
|
+
sort=("trade_date", "index_code"),
|
|
145
|
+
exclusive=(("trade_date",), ("start_date", "end_date")),
|
|
146
|
+
),
|
|
147
|
+
"index_quote": APISpec(
|
|
148
|
+
name="index_quote",
|
|
149
|
+
kind="query",
|
|
150
|
+
summary="规格报价明细",
|
|
151
|
+
method="POST",
|
|
152
|
+
path=QUERY_PATH,
|
|
153
|
+
scope="quote:read",
|
|
154
|
+
timeliness="member",
|
|
155
|
+
params=(
|
|
156
|
+
_param("index_code", "指数代码,如 Server_Index"),
|
|
157
|
+
_param("trade_date", "报价日期,不能与 start_date/end_date 同用"),
|
|
158
|
+
_param("start_date", f"开始{_DATE}"),
|
|
159
|
+
_param("end_date", f"结束{_DATE}"),
|
|
160
|
+
_param("specification", "规格名称,精确匹配,如 B300"),
|
|
161
|
+
),
|
|
162
|
+
fields=(
|
|
163
|
+
_field("trade_date", "str", "报价日期,YYYYMMDD"),
|
|
164
|
+
_field("index_code", "str", "指数代码"),
|
|
165
|
+
_field("specification", "str", "规格名称"),
|
|
166
|
+
_field("weight", "decimal", "权重,同日同指数合计为 1"),
|
|
167
|
+
_field("price", "decimal", "规格报价"),
|
|
168
|
+
),
|
|
169
|
+
default_fields=("trade_date", "index_code", "specification", "weight", "price"),
|
|
170
|
+
sort=("trade_date", "index_code", "specification"),
|
|
171
|
+
exclusive=(("trade_date",), ("start_date", "end_date")),
|
|
172
|
+
),
|
|
173
|
+
"trade_cal": APISpec(
|
|
174
|
+
name="trade_cal",
|
|
175
|
+
kind="query",
|
|
176
|
+
summary="交易日历",
|
|
177
|
+
method="POST",
|
|
178
|
+
path=QUERY_PATH,
|
|
179
|
+
scope="calendar:read",
|
|
180
|
+
timeliness="none",
|
|
181
|
+
params=(
|
|
182
|
+
_param("trade_date", "日期,不能与 start_date/end_date 同用"),
|
|
183
|
+
_param("start_date", f"开始{_DATE}"),
|
|
184
|
+
_param("end_date", f"结束{_DATE}"),
|
|
185
|
+
),
|
|
186
|
+
fields=(
|
|
187
|
+
_field("trade_date", "str", "日期,YYYYMMDD"),
|
|
188
|
+
_field("is_workday", "bool", "是否为指数工作日"),
|
|
189
|
+
_field("remark", "str", "节假日或特殊说明"),
|
|
190
|
+
),
|
|
191
|
+
default_fields=("trade_date", "is_workday", "remark"),
|
|
192
|
+
sort=("trade_date",),
|
|
193
|
+
exclusive=(("trade_date",), ("start_date", "end_date")),
|
|
194
|
+
),
|
|
195
|
+
"public_config": APISpec(
|
|
196
|
+
name="public_config",
|
|
197
|
+
kind="public",
|
|
198
|
+
summary="公开系统配置",
|
|
199
|
+
method="GET",
|
|
200
|
+
path="/api/v1/public/config",
|
|
201
|
+
params=(),
|
|
202
|
+
fields=(
|
|
203
|
+
_field("registration_enabled", "bool", "是否开放自助注册"),
|
|
204
|
+
_field("site_url", "str", "网站卡片链接"),
|
|
205
|
+
_field("site_name", "str", "网站卡片名称"),
|
|
206
|
+
_field("sms_login_enabled", "bool", "是否开放手机验证码登录"),
|
|
207
|
+
_field("sms_registration_enabled", "bool", "注册时是否要求短信验证"),
|
|
208
|
+
_field("sms_password_reset_enabled", "bool", "是否开放短信找回密码"),
|
|
209
|
+
_field("sms_international_enabled", "bool", "是否允许国际号码"),
|
|
210
|
+
_field("sms_code_length", "int", "验证码位数"),
|
|
211
|
+
_field("sms_resend_seconds", "int", "注册等场景的验证码发送间隔(秒)"),
|
|
212
|
+
_field("sms_login_resend_seconds", "int", "登录场景的验证码发送间隔(秒)"),
|
|
213
|
+
),
|
|
214
|
+
default_fields=(
|
|
215
|
+
"registration_enabled",
|
|
216
|
+
"site_url",
|
|
217
|
+
"site_name",
|
|
218
|
+
"sms_login_enabled",
|
|
219
|
+
"sms_registration_enabled",
|
|
220
|
+
"sms_password_reset_enabled",
|
|
221
|
+
"sms_international_enabled",
|
|
222
|
+
"sms_code_length",
|
|
223
|
+
"sms_resend_seconds",
|
|
224
|
+
"sms_login_resend_seconds",
|
|
225
|
+
),
|
|
226
|
+
),
|
|
227
|
+
"public_indices": APISpec(
|
|
228
|
+
name="public_indices",
|
|
229
|
+
kind="public",
|
|
230
|
+
summary="公开指数列表及最新点位",
|
|
231
|
+
method="GET",
|
|
232
|
+
path="/api/v1/public/indices",
|
|
233
|
+
timeliness="member",
|
|
234
|
+
params=(),
|
|
235
|
+
fields=(
|
|
236
|
+
_field("index_code", "str", "指数代码"),
|
|
237
|
+
_field("index_name", "str", "指数名称"),
|
|
238
|
+
_field("description", "str", "指数说明"),
|
|
239
|
+
_field("base_date", "str", "基准日期"),
|
|
240
|
+
_field("base_value", "str", "基准点位"),
|
|
241
|
+
_field("visibility", "str", "公开范围"),
|
|
242
|
+
_field("sort_no", "int", "展示顺序"),
|
|
243
|
+
_field("enabled", "bool", "是否启用"),
|
|
244
|
+
_field("latest", "object|null", "最新日数据;aggregate 指数才含 weighted_price"),
|
|
245
|
+
),
|
|
246
|
+
default_fields=(
|
|
247
|
+
"index_code",
|
|
248
|
+
"index_name",
|
|
249
|
+
"description",
|
|
250
|
+
"base_date",
|
|
251
|
+
"base_value",
|
|
252
|
+
"visibility",
|
|
253
|
+
"sort_no",
|
|
254
|
+
"enabled",
|
|
255
|
+
"latest",
|
|
256
|
+
),
|
|
257
|
+
),
|
|
258
|
+
"public_index_daily": APISpec(
|
|
259
|
+
name="public_index_daily",
|
|
260
|
+
kind="public",
|
|
261
|
+
summary="公开指数日线序列",
|
|
262
|
+
method="GET",
|
|
263
|
+
path="/api/v1/public/index-daily/{index_code}",
|
|
264
|
+
timeliness="member",
|
|
265
|
+
params=(
|
|
266
|
+
_param("index_code", "指数代码", required=True, location="path"),
|
|
267
|
+
_param("start_date", f"开始{_DATE}", location="query"),
|
|
268
|
+
_param("end_date", f"结束{_DATE}", location="query"),
|
|
269
|
+
),
|
|
270
|
+
fields=(
|
|
271
|
+
_field("trade_date", "str", "交易日期,YYYY-MM-DD"),
|
|
272
|
+
_field("index_code", "str", "指数代码"),
|
|
273
|
+
_field("weighted_price", "decimal|null", "整体加权价格,仅 aggregate 指数返回"),
|
|
274
|
+
_field("index_value", "decimal", "当日指数点位"),
|
|
275
|
+
_field("change_rate", "decimal", "涨跌比例"),
|
|
276
|
+
_field("calculated_at", "str", "计算时间,RFC 3339"),
|
|
277
|
+
),
|
|
278
|
+
default_fields=("trade_date", "index_code", "weighted_price", "index_value", "change_rate", "calculated_at"),
|
|
279
|
+
),
|
|
280
|
+
"public_index_quotes": APISpec(
|
|
281
|
+
name="public_index_quotes",
|
|
282
|
+
kind="public",
|
|
283
|
+
summary="公开规格报价序列,仅 aggregate 指数",
|
|
284
|
+
method="GET",
|
|
285
|
+
path="/api/v1/public/index-quotes/{index_code}",
|
|
286
|
+
timeliness="member",
|
|
287
|
+
params=(
|
|
288
|
+
_param("index_code", "指数代码", required=True, location="path"),
|
|
289
|
+
_param("start_date", f"开始{_DATE}", location="query"),
|
|
290
|
+
_param("end_date", f"结束{_DATE}", location="query"),
|
|
291
|
+
),
|
|
292
|
+
fields=(
|
|
293
|
+
_field("trade_date", "str", "交易日期,YYYY-MM-DD"),
|
|
294
|
+
_field("index_code", "str", "指数代码"),
|
|
295
|
+
_field("specification", "str", "规格名称"),
|
|
296
|
+
_field("weight", "decimal", "权重"),
|
|
297
|
+
_field("price", "decimal", "报价"),
|
|
298
|
+
_field("weighted_price", "decimal", "price × weight"),
|
|
299
|
+
),
|
|
300
|
+
default_fields=("trade_date", "index_code", "specification", "weight", "price", "weighted_price"),
|
|
301
|
+
),
|
|
302
|
+
"public_index_latest": APISpec(
|
|
303
|
+
name="public_index_latest",
|
|
304
|
+
kind="public",
|
|
305
|
+
summary="公开指数最新点位",
|
|
306
|
+
method="GET",
|
|
307
|
+
path="/api/v1/public/index-daily/{index_code}/latest",
|
|
308
|
+
timeliness="member",
|
|
309
|
+
params=(_param("index_code", "指数代码", required=True, location="path"),),
|
|
310
|
+
fields=(
|
|
311
|
+
_field("trade_date", "str", "交易日期,YYYY-MM-DD"),
|
|
312
|
+
_field("index_code", "str", "指数代码"),
|
|
313
|
+
_field("weighted_price", "decimal|null", "整体加权价格,仅 aggregate 指数返回"),
|
|
314
|
+
_field("index_value", "decimal", "当日指数点位"),
|
|
315
|
+
_field("change_rate", "decimal", "涨跌比例"),
|
|
316
|
+
_field("calculated_at", "str", "计算时间,RFC 3339"),
|
|
317
|
+
),
|
|
318
|
+
default_fields=("trade_date", "index_code", "weighted_price", "index_value", "change_rate", "calculated_at"),
|
|
319
|
+
),
|
|
320
|
+
"public_membership": APISpec(
|
|
321
|
+
name="public_membership",
|
|
322
|
+
kind="public",
|
|
323
|
+
summary="当前会话的会员权益",
|
|
324
|
+
method="GET",
|
|
325
|
+
path="/api/v1/public/membership",
|
|
326
|
+
params=(),
|
|
327
|
+
fields=(
|
|
328
|
+
_field("active", "bool", "是否有效会员"),
|
|
329
|
+
_field("tier", "str", "等级代码"),
|
|
330
|
+
_field("expires_at", "str|null", "到期时间"),
|
|
331
|
+
_field("latest", "bool", "当前身份是否可查看最新已发布数据"),
|
|
332
|
+
_field("delay_days", "int", "免费用户延迟交易日数"),
|
|
333
|
+
_field("cutoff", "str|null", "当前可见的数据截止日"),
|
|
334
|
+
_field("first_eligible", "bool", "是否仍享有首月优惠资格"),
|
|
335
|
+
_field("free_benefits", "object", "免费用户权益"),
|
|
336
|
+
_field("benefits", "object", "当前身份的实际权益"),
|
|
337
|
+
_field("tiers", "array", "全部会员等级及其权益"),
|
|
338
|
+
_field("plans", "array", "上架套餐"),
|
|
339
|
+
_field("payment_enabled", "bool", "在线支付开关"),
|
|
340
|
+
_field("methods", "array", "可用支付方式"),
|
|
341
|
+
),
|
|
342
|
+
default_fields=(
|
|
343
|
+
"active",
|
|
344
|
+
"tier",
|
|
345
|
+
"expires_at",
|
|
346
|
+
"latest",
|
|
347
|
+
"delay_days",
|
|
348
|
+
"cutoff",
|
|
349
|
+
"first_eligible",
|
|
350
|
+
"free_benefits",
|
|
351
|
+
"benefits",
|
|
352
|
+
"tiers",
|
|
353
|
+
"plans",
|
|
354
|
+
"payment_enabled",
|
|
355
|
+
"methods",
|
|
356
|
+
),
|
|
357
|
+
),
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def apis(kind: str | None = None) -> list[str]:
|
|
362
|
+
"""返回接口名称。``kind`` 可取 ``query`` 或 ``public``。"""
|
|
363
|
+
if kind is None:
|
|
364
|
+
return list(_APIS)
|
|
365
|
+
if kind not in {"query", "public"}:
|
|
366
|
+
raise TokeaseError("kind 只能是 query 或 public")
|
|
367
|
+
return [name for name, spec in _APIS.items() if spec.kind == kind]
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def get_api(api_name: str) -> APISpec:
|
|
371
|
+
"""返回指定接口的完整说明。"""
|
|
372
|
+
try:
|
|
373
|
+
return _APIS[api_name]
|
|
374
|
+
except KeyError as exc:
|
|
375
|
+
known = ", ".join(_APIS)
|
|
376
|
+
raise TokeaseError(f"未知接口 {api_name!r},可选:{known}") from exc
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def api_params(api_name: str) -> tuple[Param, ...]:
|
|
380
|
+
"""返回指定接口的输入参数。"""
|
|
381
|
+
return get_api(api_name).params
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def api_fields(api_name: str) -> tuple[Field, ...]:
|
|
385
|
+
"""返回指定接口的输出字段。"""
|
|
386
|
+
return get_api(api_name).fields
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def describe(api_name: str | None = None) -> dict[str, Any] | list[dict[str, Any]]:
|
|
390
|
+
"""返回一个或全部接口的参数、字段与权限说明。"""
|
|
391
|
+
if api_name is None:
|
|
392
|
+
return [spec.as_dict() for spec in _APIS.values()]
|
|
393
|
+
return get_api(api_name).as_dict()
|