ashareapi-pi 0.2.5 → 0.2.7

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.
@@ -1,204 +1,204 @@
1
- # 官方 SDK(Python `pip install ashareapi` · Node.js `npm install ashareapi`)
2
-
3
- **什么时候用 SDK 而不是直接打 HTTP**:
4
- - ✅ **要写代码**(Python 脚本 / notebook / 回测 · Node 服务 / Next.js / 脚本)→ 用 SDK(省掉重试、异常分类、字段解析)
5
- - ✅ Python 要成 **pandas DataFrame**(直接算 / 画图)→ 用 Python SDK
6
- - ✅ Node 要 **TypeScript 类型**(编辑器补全 32 个方法与参数)→ 用 Node SDK
7
- - ❌ 只是**取一个数看一眼** → 直接 `curl` / `fetch` 更快
8
- - ❌ 用 **Go / Java / C# 等**(暂无官方 SDK)→ 直接调 HTTP(见 `endpoints.md`)
9
-
10
- ---
11
-
12
- ## 一、安装
13
-
14
- **Python**(要求 3.9+;强依赖只有 `requests`,pandas 可选):
15
-
16
- ```bash
17
- pip install ashareapi # 基础:返回 list[dict]
18
- pip install "ashareapi[pandas]" # 加 DataFrame 支持(推荐)
19
- ```
20
-
21
- **Node.js / TypeScript**(要求 Node ≥ 18;**零运行时依赖**,用原生 `fetch`):
22
-
23
- ```bash
24
- npm install ashareapi
25
- ```
26
-
27
- > ⚠️ Node SDK **只在服务端用**(Node / Next.js 服务端 / 云函数)—— 浏览器里会暴露你的 API Key,它刻意不提供浏览器构建。
28
-
29
- ## 二、快速开始
30
-
31
- **Python**:
32
-
33
- ```python
34
- from ashareapi import AShareAPI
35
-
36
- cli = AShareAPI() # 免费端点无需 Key
37
- df = cli.quote("sh600667") # 实时行情 → DataFrame
38
- print(df[["date", "last", "turnover"]])
39
-
40
- print(cli.kline("600667.SH", count=5)) # 代码格式随便写(自动归一化)
41
- print(cli.hot(limit=10))
42
- print(cli.changedist()) # 涨跌分布(市场广度)
43
- ```
44
-
45
- **Node.js / TypeScript**(ESM 与 CommonJS 都支持):
46
-
47
- ```ts
48
- import { AShareAPI } from "ashareapi"; // CJS: const { AShareAPI } = require("ashareapi")
49
-
50
- const cli = new AShareAPI(); // 免费端点无需 Key
51
- const bars = await cli.quote("sh600667"); // → 对象数组
52
- console.log(bars[0]); // { date, open, last, high, low, volume, amount, turnover }
53
-
54
- console.log(await cli.kline("600667.SH", "day", 5));
55
- console.log(await cli.hot(10));
56
- console.log(await cli.changedist());
57
- ```
58
-
59
- **付费端点**:
60
-
61
- ```python
62
- # Python
63
- cli = AShareAPI("ct-你的Key") # 或环境变量 ASHARE_API_KEY
64
- print(cli.fund("sh600667")) # 资金流 + 龙虎榜 + 大宗 + 两融
65
- print(cli.finance("sh600667")) # 三大报表
66
- print(cli.lhb("institution")) # 龙虎榜机构榜
67
- print(cli.screen(preset="low_pe", orderby="ROETTM", limit=10))
68
- print(cli.industry_chain(mode="stock", code="sh600667"))
69
- ```
70
-
71
- ```ts
72
- // Node.js
73
- const cli = new AShareAPI({ apiKey: "ct-你的Key" }); // 或 process.env.ASHARE_API_KEY
74
- console.log(await cli.fund("sh600667"));
75
- console.log(await cli.finance("sh600667"));
76
- console.log(await cli.lhb("institution"));
77
- console.log(await cli.screen("", "low_pe", 10, "ROETTM")); // expr, preset, limit, orderby
78
- console.log(await cli.industryChain("stock", "", "sh600667"));
79
- ```
80
-
81
- **环境变量**(推荐,别把 Key 写死在代码里):
82
-
83
- ```bash
84
- export ASHARE_API_KEY=ct-你的Key # Linux/macOS
85
- set ASHARE_API_KEY=ct-你的Key # Windows cmd
86
- ```
87
-
88
- ## 三、代码格式:三种写法都认
89
-
90
- 两个 SDK 内部都会把它们统一成 `sh600667`:
91
-
92
- | 你写的 | 结果 |
93
- |---|---|
94
- | `sh600667` | `sh600667` |
95
- | `600667.SH` | `sh600667` |
96
- | `600667` | `sh600667`(按首位推断:5/6→沪 · 0/3→深 · 4/8→北)|
97
-
98
- → **从别处迁过来的代码基本不用改**。
99
-
100
- ## 四、32 个方法(与 HTTP 端点 1:1)
101
-
102
- | 端点 | Python | Node.js |
103
- |---|---|---|
104
- | `/v1/quote` | `quote(code)` | `quote(code)` |
105
- | `/v1/kline` | `kline(code, period, count)` | `kline(code, period, count)` |
106
- | `/v1/hot` | `hot(limit)` | `hot(limit)` |
107
- | `/v1/market-overview` | `market_overview(type)` | `marketOverview(type)` · 别名 `market_overview` |
108
- | `/v1/changedist` | `changedist()` | `changedist()` |
109
- | `/v1/health` · `/v1/challenge` · `/v1/usage` | `health()` `challenge()` `usage()` | 同 |
110
- | `/v1/fund` | `fund(code)` | `fund(code)` |
111
- | `/v1/lhb` | `lhb(type, date)` | `lhb(type, date)` |
112
- | `/v1/margin-trade` | `margin_trade(code, date)` | `marginTrade(code, date)` · 别名 `margin_trade` |
113
- | `/v1/block-trade` | `block_trade(code, date)` | `blockTrade(code, date)` · 别名 `block_trade` |
114
- | `/v1/finance` | `finance(code, num)` | `finance(code, num)` |
115
- | `/v1/dividend` · `/v1/shareholder` | `dividend(code, years)` `shareholder(code)` | 同 |
116
- | `/v1/technical` · `/v1/chip` · `/v1/profile` · `/v1/search` | `technical(code)` `chip(code)` `profile(code)` `search(q)` | 同 |
117
- | **`/v1/orderbook`**|`orderbook(code)` | 同(五档盘口·**盘中**·量单位=手)|
118
- | **`/v1/snapshot`**|`snapshot(code)` | 同(全字段画像·**仅 A 股**·付费)|
119
- | `/v1/events` · `/v1/calendar` | `events(code)` `calendar(date, limit)` | 同 |
120
- | `/v1/sector` | `sector()` | `sector()` |
121
- | `/v1/sector-valuation` | `sector_valuation(code)` | `sectorValuation(code)` · 别名 `sector_valuation` |
122
- | `/v1/industry-chain` | `industry_chain(mode, topic, code)` | `industryChain(mode, topic, code)` · 别名 `industry_chain` |
123
- | `/v1/bond` · `/v1/etf` · `/v1/ipo` | `bond(code)` `etf(code)` `ipo(days)` | 同 |
124
- | `/v1/screen` | `screen(expr, preset, limit, orderby, desc, market)` | 同(位置参数)|
125
- | `/v1/macro` | `macro(region, names)` | `macro(region, names)` |
126
- | `/v1/dehydrated` | `dehydrated(mode, symbol, limit)` | `dehydrated(mode, symbol, limit)` |
127
-
128
- > **方法是否与线上一致?** 两个 SDK 都有**覆盖守护测试**:拉 `/openapi.json` 比对方法名,端点增减即测试红灯。
129
-
130
- ## 五、返回形态(两者不同,注意)
131
-
132
- ⚠️ **端点返回的不总是"一张表"** —— `data` 有 **4 种形状**(对象数组 / 表列表 / 多段结构 / Markdown 文本,见 `endpoints.md`)。
133
- SDK **只把「对象数组」转成 DataFrame**,其余**原样返回**(不强行套成 DataFrame):
134
-
135
- | 返回形状 | Python | Node.js |
136
- |---|---|---|
137
- | 对象数组(多数端点)| `pandas.DataFrame`(装了 pandas)/ `list[dict]` | **对象数组 `Row[]`** |
138
- | 表列表(`finance`)| **`list[list[dict]]` 原样返回**(不套 DataFrame)| `TableList` = `Row[][]` |
139
- | 多段结构(`shareholder` · `calendar`)| **`dict` 原样返回** | `SectionedResult` = `{tables, data}` |
140
- | 完整信封 | `raw=True` | `new AShareAPI({ raw: true })` |
141
- | 同步性 | **同步** | **全部返回 Promise**(要 `await`)|
142
-
143
- **字段语义与单位**(手/元/百分数)见 `fields.md` —— 两个 SDK **都不会**帮你换算单位。
144
-
145
- ## 六、异常(5 类,各自告诉你做什么)
146
-
147
- **Python**:
148
-
149
- ```python
150
- from ashareapi import (AShareAPI, AShareError, AuthError, RateLimitError,
151
- UpstreamError, EmptyResultError, APIError)
152
-
153
- try:
154
- df = cli.fund("sh600667")
155
- except AuthError as e: # 401/403 → 付费端点缺 Key / IP 维度限制
156
- print(e)
157
- except RateLimitError as e: # 429 → 降频 · 解 PoW 提额 · 升级档位
158
- print(e)
159
- except UpstreamError as e: # ok:false → 上游失败(已换源、不扣次数)→ 重试一次
160
- print(e)
161
- except EmptyResultError as e: # 当前无数据(如当天无大宗交易)→ 不计费,换条件
162
- print(e)
163
- except APIError as e: # 网络 / 5xx 重试耗尽
164
- print(e)
165
- ```
166
-
167
- **Node.js**(同名 5 类,`instanceof` 判定):
168
-
169
- ```ts
170
- import { AShareAPI, AuthError, RateLimitError, UpstreamError, EmptyResultError } from "ashareapi";
171
-
172
- try {
173
- const rows = await cli.fund("sh600667");
174
- } catch (e) {
175
- if (e instanceof AuthError) console.log(e.message); // 401/403
176
- else if (e instanceof RateLimitError) console.log(e.message); // 429
177
- else if (e instanceof UpstreamError) console.log(e.message); // ok:false → 重试一次
178
- else if (e instanceof EmptyResultError) console.log(e.message);// 当前无数据 → 不计费
179
- else throw e;
180
- }
181
- ```
182
-
183
- 全部继承自 `AShareError`(Python 要一把抓就 `except AShareError`)。
184
-
185
- **`EmptyResultError` 是 SDK 相对裸 HTTP 的独有改进**:把"**没有数据**"和"**取数失败**"分开,避免把"今天没大宗交易"当故障反复重试(细节见 `errors.md`)。
186
-
187
- ## 七、SDK vs 直接 HTTP vs 其他数据源
188
-
189
- | | 官方 SDK | 自己 requests / fetch | 其他开源库 |
190
- |---|---|---|---|
191
- | 上手 | **装完即用** | 自己封装重试/异常 | 装完即用 |
192
- | 返回 | **DataFrame**(Python)/ **对象数组**(Node)| 自己解析 | DataFrame |
193
- | 免费试用 | **5 端点免 Key** | 同样免 Key | 视来源 |
194
- | 错误处理 | **5 类异常**(含"无数据≠失败")| 自己判断 | 自己判断 |
195
- | 维护 | **我们维护**(多源自动切换)| 上游改了你改 | 上游改版常需跟进 |
196
- | 依赖 | Python: `requests`(pandas 可选)/ Node: **零依赖** | 同 | 视库 |
197
-
198
- ## 八、边界(诚实)
199
-
200
- - **K 线只有日/周/月**,**没有分钟级**(`period` 仅 `day`/`week`/`month`)
201
- - **新闻/公告全文**不在 API 范围(有 `dehydrated` 研报摘要、`events` 事件标签)
202
- - **不含投资建议** —— SDK 只负责取数
203
- - **Node SDK 不要在浏览器里用**(会暴露 Key)
204
- - 版本记录与更新:https://ashareapi.com/changelog
1
+ # 官方 SDK(Python `pip install ashareapi` · Node.js `npm install ashareapi`)
2
+
3
+ **什么时候用 SDK 而不是直接打 HTTP**:
4
+ - ✅ **要写代码**(Python 脚本 / notebook / 回测 · Node 服务 / Next.js / 脚本)→ 用 SDK(省掉重试、异常分类、字段解析)
5
+ - ✅ Python 要成 **pandas DataFrame**(直接算 / 画图)→ 用 Python SDK
6
+ - ✅ Node 要 **TypeScript 类型**(编辑器补全 33 个方法与参数)→ 用 Node SDK
7
+ - ❌ 只是**取一个数看一眼** → 直接 `curl` / `fetch` 更快
8
+ - ❌ 用 **Go / Java / C# 等**(暂无官方 SDK)→ 直接调 HTTP(见 `endpoints.md`)
9
+
10
+ ---
11
+
12
+ ## 一、安装
13
+
14
+ **Python**(要求 3.9+;强依赖只有 `requests`,pandas 可选):
15
+
16
+ ```bash
17
+ pip install ashareapi # 基础:返回 list[dict]
18
+ pip install "ashareapi[pandas]" # 加 DataFrame 支持(推荐)
19
+ ```
20
+
21
+ **Node.js / TypeScript**(要求 Node ≥ 18;**零运行时依赖**,用原生 `fetch`):
22
+
23
+ ```bash
24
+ npm install ashareapi
25
+ ```
26
+
27
+ > ⚠️ Node SDK **只在服务端用**(Node / Next.js 服务端 / 云函数)—— 浏览器里会暴露你的 API Key,它刻意不提供浏览器构建。
28
+
29
+ ## 二、快速开始
30
+
31
+ **Python**:
32
+
33
+ ```python
34
+ from ashareapi import AShareAPI
35
+
36
+ cli = AShareAPI() # 免费端点无需 Key
37
+ df = cli.quote("sh600667") # 实时行情 → DataFrame
38
+ print(df[["date", "last", "turnover"]])
39
+
40
+ print(cli.kline("600667.SH", count=5)) # 代码格式随便写(自动归一化)
41
+ print(cli.hot(limit=10))
42
+ print(cli.changedist()) # 涨跌分布(市场广度)
43
+ ```
44
+
45
+ **Node.js / TypeScript**(ESM 与 CommonJS 都支持):
46
+
47
+ ```ts
48
+ import { AShareAPI } from "ashareapi"; // CJS: const { AShareAPI } = require("ashareapi")
49
+
50
+ const cli = new AShareAPI(); // 免费端点无需 Key
51
+ const bars = await cli.quote("sh600667"); // → 对象数组
52
+ console.log(bars[0]); // { date, open, last, high, low, volume, amount, turnover }
53
+
54
+ console.log(await cli.kline("600667.SH", "day", 5));
55
+ console.log(await cli.hot(10));
56
+ console.log(await cli.changedist());
57
+ ```
58
+
59
+ **付费端点**:
60
+
61
+ ```python
62
+ # Python
63
+ cli = AShareAPI("ct-你的Key") # 或环境变量 ASHARE_API_KEY
64
+ print(cli.fund("sh600667")) # 资金流 + 龙虎榜 + 大宗 + 两融
65
+ print(cli.finance("sh600667")) # 三大报表
66
+ print(cli.lhb("institution")) # 龙虎榜机构榜
67
+ print(cli.screen(preset="low_pe", orderby="ROETTM", limit=10))
68
+ print(cli.industry_chain(mode="stock", code="sh600667"))
69
+ ```
70
+
71
+ ```ts
72
+ // Node.js
73
+ const cli = new AShareAPI({ apiKey: "ct-你的Key" }); // 或 process.env.ASHARE_API_KEY
74
+ console.log(await cli.fund("sh600667"));
75
+ console.log(await cli.finance("sh600667"));
76
+ console.log(await cli.lhb("institution"));
77
+ console.log(await cli.screen("", "low_pe", 10, "ROETTM")); // expr, preset, limit, orderby
78
+ console.log(await cli.industryChain("stock", "", "sh600667"));
79
+ ```
80
+
81
+ **环境变量**(推荐,别把 Key 写死在代码里):
82
+
83
+ ```bash
84
+ export ASHARE_API_KEY=ct-你的Key # Linux/macOS
85
+ set ASHARE_API_KEY=ct-你的Key # Windows cmd
86
+ ```
87
+
88
+ ## 三、代码格式:三种写法都认
89
+
90
+ 两个 SDK 内部都会把它们统一成 `sh600667`:
91
+
92
+ | 你写的 | 结果 |
93
+ |---|---|
94
+ | `sh600667` | `sh600667` |
95
+ | `600667.SH` | `sh600667` |
96
+ | `600667` | `sh600667`(按首位推断:5/6→沪 · 0/3→深 · 4/8→北)|
97
+
98
+ → **从别处迁过来的代码基本不用改**。
99
+
100
+ ## 四、33 个方法(与 HTTP 端点 1:1)
101
+
102
+ | 端点 | Python | Node.js |
103
+ |---|---|---|
104
+ | `/v1/quote` | `quote(code)` | `quote(code)` |
105
+ | `/v1/kline` | `kline(code, period, count)` | `kline(code, period, count)` |
106
+ | `/v1/hot` | `hot(limit)` | `hot(limit)` |
107
+ | `/v1/market-overview` | `market_overview(type)` | `marketOverview(type)` · 别名 `market_overview` |
108
+ | `/v1/changedist` | `changedist()` | `changedist()` |
109
+ | `/v1/health` · `/v1/challenge` · `/v1/usage` | `health()` `challenge()` `usage()` | 同 |
110
+ | `/v1/fund` | `fund(code)` | `fund(code)` |
111
+ | `/v1/lhb` | `lhb(type, date)` | `lhb(type, date)` |
112
+ | `/v1/margin-trade` | `margin_trade(code, date)` | `marginTrade(code, date)` · 别名 `margin_trade` |
113
+ | `/v1/block-trade` | `block_trade(code, date)` | `blockTrade(code, date)` · 别名 `block_trade` |
114
+ | `/v1/finance` | `finance(code, num)` | `finance(code, num)` |
115
+ | `/v1/dividend` · `/v1/shareholder` | `dividend(code, years)` `shareholder(code)` | 同 |
116
+ | `/v1/technical` · `/v1/chip` · `/v1/profile` · `/v1/search` | `technical(code)` `chip(code)` `profile(code)` `search(q)` | 同 |
117
+ | **`/v1/orderbook`**|`orderbook(code)` | 同(五档盘口·**盘中**·量单位=手)|
118
+ | **`/v1/snapshot`**|`snapshot(code)` | 同(全字段画像·**仅 A 股**·付费)|
119
+ | `/v1/events` · `/v1/calendar` | `events(code)` `calendar(date, limit)` | 同 |
120
+ | `/v1/sector` | `sector()` | `sector()` |
121
+ | `/v1/sector-valuation` | `sector_valuation(code)` | `sectorValuation(code)` · 别名 `sector_valuation` |
122
+ | `/v1/industry-chain` | `industry_chain(mode, topic, code)` | `industryChain(mode, topic, code)` · 别名 `industry_chain` |
123
+ | `/v1/bond` · `/v1/etf` · `/v1/ipo` | `bond(code)` `etf(code)` `ipo(days)` | 同 |
124
+ | `/v1/screen` | `screen(expr, preset, limit, orderby, desc, market)` | 同(位置参数)|
125
+ | `/v1/macro` | `macro(region, names)` | `macro(region, names)` |
126
+ | `/v1/dehydrated` | `dehydrated(mode, symbol, limit)` | `dehydrated(mode, symbol, limit)` |
127
+
128
+ > **方法是否与线上一致?** 两个 SDK 都有**覆盖守护测试**:拉 `/openapi.json` 比对方法名,端点增减即测试红灯。
129
+
130
+ ## 五、返回形态(两者不同,注意)
131
+
132
+ ⚠️ **端点返回的不总是"一张表"** —— `data` 有 **4 种形状**(对象数组 / 表列表 / 多段结构 / Markdown 文本,见 `endpoints.md`)。
133
+ SDK **只把「对象数组」转成 DataFrame**,其余**原样返回**(不强行套成 DataFrame):
134
+
135
+ | 返回形状 | Python | Node.js |
136
+ |---|---|---|
137
+ | 对象数组(多数端点)| `pandas.DataFrame`(装了 pandas)/ `list[dict]` | **对象数组 `Row[]`** |
138
+ | 表列表(`finance`)| **`list[list[dict]]` 原样返回**(不套 DataFrame)| `TableList` = `Row[][]` |
139
+ | 多段结构(`shareholder` · `calendar`)| **`dict` 原样返回** | `SectionedResult` = `{tables, data}` |
140
+ | 完整信封 | `raw=True` | `new AShareAPI({ raw: true })` |
141
+ | 同步性 | **同步** | **全部返回 Promise**(要 `await`)|
142
+
143
+ **字段语义与单位**(手/元/百分数)见 `fields.md` —— 两个 SDK **都不会**帮你换算单位。
144
+
145
+ ## 六、异常(5 类,各自告诉你做什么)
146
+
147
+ **Python**:
148
+
149
+ ```python
150
+ from ashareapi import (AShareAPI, AShareError, AuthError, RateLimitError,
151
+ UpstreamError, EmptyResultError, APIError)
152
+
153
+ try:
154
+ df = cli.fund("sh600667")
155
+ except AuthError as e: # 401/403 → 付费端点缺 Key / IP 维度限制
156
+ print(e)
157
+ except RateLimitError as e: # 429 → 降频 · 解 PoW 提额(只提次数)· 升级档位
158
+ print(e)
159
+ except UpstreamError as e: # ok:false → 上游失败(已换源、不扣次数)→ 重试一次
160
+ print(e)
161
+ except EmptyResultError as e: # 当前无数据(如当天无大宗交易)→ 不计费,换条件
162
+ print(e)
163
+ except APIError as e: # 网络 / 5xx 重试耗尽
164
+ print(e)
165
+ ```
166
+
167
+ **Node.js**(同名 5 类,`instanceof` 判定):
168
+
169
+ ```ts
170
+ import { AShareAPI, AuthError, RateLimitError, UpstreamError, EmptyResultError } from "ashareapi";
171
+
172
+ try {
173
+ const rows = await cli.fund("sh600667");
174
+ } catch (e) {
175
+ if (e instanceof AuthError) console.log(e.message); // 401/403
176
+ else if (e instanceof RateLimitError) console.log(e.message); // 429
177
+ else if (e instanceof UpstreamError) console.log(e.message); // ok:false → 重试一次
178
+ else if (e instanceof EmptyResultError) console.log(e.message);// 当前无数据 → 不计费
179
+ else throw e;
180
+ }
181
+ ```
182
+
183
+ 全部继承自 `AShareError`(Python 要一把抓就 `except AShareError`)。
184
+
185
+ **`EmptyResultError` 是 SDK 相对裸 HTTP 的独有改进**:把"**没有数据**"和"**取数失败**"分开,避免把"今天没大宗交易"当故障反复重试(细节见 `errors.md`)。
186
+
187
+ ## 七、SDK vs 直接 HTTP vs 其他数据源
188
+
189
+ | | 官方 SDK | 自己 requests / fetch | 其他开源库 |
190
+ |---|---|---|---|
191
+ | 上手 | **装完即用** | 自己封装重试/异常 | 装完即用 |
192
+ | 返回 | **DataFrame**(Python)/ **对象数组**(Node)| 自己解析 | DataFrame |
193
+ | 免费试用 | **5 端点免 Key** | 同样免 Key | 视来源 |
194
+ | 错误处理 | **5 类异常**(含"无数据≠失败")| 自己判断 | 自己判断 |
195
+ | 维护 | **我们维护**(多源自动切换)| 上游改了你改 | 上游改版常需跟进 |
196
+ | 依赖 | Python: `requests`(pandas 可选)/ Node: **零依赖** | 同 | 视库 |
197
+
198
+ ## 八、边界(诚实)
199
+
200
+ - **K 线只有日/周/月**,**没有分钟级**(`period` 仅 `day`/`week`/`month`)
201
+ - **新闻/公告全文**不在 API 范围(有 `dehydrated` 研报摘要、`events` 事件标签)
202
+ - **不含投资建议** —— SDK 只负责取数
203
+ - **Node SDK 不要在浏览器里用**(会暴露 Key)
204
+ - 版本记录与更新:https://ashareapi.com/changelog