stock-sdk 1.0.0

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.
package/origin.md ADDED
@@ -0,0 +1,480 @@
1
+ # qt.gtimg.cn 腾讯财经接口非官方说明文档
2
+
3
+ > 重要说明:`qt.gtimg.cn` 并没有公开官方 API 文档,本文档内容均来自社区和抓包逆向整理,仅供参考和学习使用,随时可能调整或下线,使用前请自行验证。
4
+
5
+ ---
6
+
7
+ ## 1. 基本约定
8
+
9
+ - **Host**:`http://qt.gtimg.cn`
10
+ - **HTTP 方法**:`GET`
11
+ - **基础格式**:
12
+
13
+ ```text
14
+ http://qt.gtimg.cn/q=<参数串>
15
+ ```
16
+
17
+ - **多标的查询**:多个代码用英文逗号 `,` 拼接,例如:
18
+
19
+ ```text
20
+ http://qt.gtimg.cn/q=sh600000,sz000001,hk00001
21
+ ```
22
+
23
+ - **返回格式**:若成功,一般为若干行 **JS 变量赋值**,例如:
24
+
25
+ ```text
26
+ v_sz000858="51~五 粮 液~000858~27.78~27.60~...~";
27
+ v_sh600000="1~浦发银行~600000~7.06~7.03~...~";
28
+ ```
29
+
30
+ - 变量名:`v_` + 查询参数(如 `sz000858` / `s_sz000858` / `ff_sz000858` 等)。
31
+ - 字段分隔符:`~`。
32
+ - 行分隔:`;`(英文分号)。
33
+
34
+ - **编码**:响应内容通常为 GBK/GB2312,需要先按 GBK/GB2312 解码,再转 UTF-8,否则中文字段会乱码。
35
+
36
+ ---
37
+
38
+ ## 2. 市场与代码前缀
39
+
40
+ 常见市场前缀约定(用于 `<market+code>` 部分):
41
+
42
+ | 市场 / 类型 | 示例前缀 | 示例代码 | 说明 |
43
+ |----------------|----------------|--------------------|----------------------------------------|
44
+ | 上证 A 股/指数 | `sh` | `sh600000` | 浦发银行 |
45
+ | 深证 A 股/指数 | `sz` | `sz000858` | 五粮液 |
46
+ | 北交所 | `bj` | `bj899050` | 北证 50 指数(示例) |
47
+ | 港股 | `hk` / `r_hk` | `hk00001` / `r_hk09988` | 普通 / 扩展行情(港股) |
48
+ | 美股 | `us` / `s_us` | `usBABA` / `s_usBABA` | 全量 / 简要行情(美股) |
49
+ | 公募基金 | `jj` | `jj000001` | 华夏成长混合等开放式基金 |
50
+
51
+ ---
52
+
53
+ ## 3. 接口总览
54
+
55
+ ### 3.1 A 股 / 指数 / 港股 / 美股 实时行情(全量字段)
56
+
57
+ **用途**:获取单只或多只股票、指数的详细实时行情(含盘口、逐笔、成交额、市值等大量字段)。
58
+
59
+ **参数格式**:
60
+
61
+ ```text
62
+ q=<market><code>
63
+ ```
64
+
65
+ **示例**:
66
+
67
+ - 上证个股:
68
+
69
+ ```text
70
+ http://qt.gtimg.cn/q=sh600000
71
+ ```
72
+
73
+ - 深证个股:
74
+
75
+ ```text
76
+ http://qt.gtimg.cn/q=sz000858
77
+ ```
78
+
79
+ - 多标的:
80
+
81
+ ```text
82
+ http://qt.gtimg.cn/q=sh600000,sz000001,sz000858
83
+ ```
84
+
85
+ **典型字段(A 股)说明**
86
+
87
+ 返回示例:
88
+
89
+ ```text
90
+ v_sz000858="51~五 粮 液~000858~27.78~27.60~270295~142514~127781~27.77~220~27.78~144~27.76~244~27.79~146~27.75~261~27.80~74~27.74~244~27.81~41~27.73~190~27.82~127~27.72~232~27.83~96~~2025/11/26 15:00:03~27.78~0.18~0.65~27.91~27.25~27.78/270295/748632327~270295~74863~0.63~16.59~~27.91~27.25~~~1.57~27.91~2025-11-26~0.63~16.59~~~1.57~~";
91
+ ```
92
+
93
+ 按 `~` 分割后,下标从 0 开始,典型字段含义(仅节选,实际字段更多):
94
+
95
+ | 下标 | 含义 |
96
+ |------|------------------------------------|
97
+ | 0 | 市场标识(如 51) |
98
+ | 1 | 名称 |
99
+ | 2 | 股票代码 |
100
+ | 3 | 当前价格 |
101
+ | 4 | 昨收 |
102
+ | 5 | 今开 |
103
+ | 6 | 成交量(手) |
104
+ | 7 | 外盘(手) |
105
+ | 8 | 内盘(手) |
106
+ | 9–18 | 买一~买五价及对应数量 |
107
+ | 19–28| 卖一~卖五价及对应数量 |
108
+ | 29 | 最近逐笔成交串 |
109
+ | 30 | 时间戳(交易日期+时间) |
110
+ | 31 | 涨跌额 |
111
+ | 32 | 涨跌幅(%) |
112
+ | 33 | 当日最高 |
113
+ | 34 | 当日最低 |
114
+ | 35 | “价格/成交量/成交额” 综合字段 |
115
+ | 36 | 成交量(手) |
116
+ | 37 | 成交额(万) |
117
+ | 38 | 换手率 |
118
+ | 39 | 市盈率 |
119
+ | 44 | 流通市值 |
120
+ | 45 | 总市值 |
121
+ | 46 | 市净率 |
122
+ | 47 | 涨停价 |
123
+ | 48 | 跌停价 |
124
+
125
+ > 注意:不同标的(A 股 / 港股 / 美股 / 指数等)字段数量和定义会有差异,使用前建议对照实际返回串自行确认。
126
+
127
+ **支持标的类型(常见)**:
128
+
129
+ - A 股个股,如:`sh600000`、`sz000858`;
130
+ - A 股主要指数,如:`sh000001`、`sz399001` 等;
131
+ - 港股个股,如:`hk00001`(普通)或通过扩展接口 `r_hk`(见 3.5);
132
+ - 美股个股,如:`usBABA`(但更推荐使用简要接口,见 3.6)。
133
+
134
+ ---
135
+
136
+ ### 3.2 简要行情接口(股票 / 指数 / 港股 / 美股)
137
+
138
+ **用途**:获取精简字段的行情数据,响应体更小,适合列表展示、概览刷新。
139
+
140
+ **参数格式**:
141
+
142
+ ```text
143
+ q=s_<market><code>
144
+ ```
145
+
146
+ **示例**:
147
+
148
+ - A 股简要:
149
+
150
+ ```text
151
+ http://qt.gtimg.cn/q=s_sz000858
152
+ http://qt.gtimg.cn/q=s_sh600519
153
+ ```
154
+
155
+ - 指数简要:
156
+
157
+ ```text
158
+ http://qt.gtimg.cn/q=s_sh000001 # 上证指数
159
+ ```
160
+
161
+ - 美股简要:
162
+
163
+ ```text
164
+ http://qt.gtimg.cn/q=s_usBABA # 阿里巴巴美股
165
+ ```
166
+
167
+ - 港股指数简要:
168
+
169
+ ```text
170
+ http://qt.gtimg.cn/q=s_r_hkHSI # 恒生指数
171
+ ```
172
+
173
+ **典型字段(简要版,按 `~` 分割)**:
174
+
175
+ > 以下为常见模式总结,实际字段数量及位置可能因市场而略有差异。
176
+
177
+ | 下标 | 含义 |
178
+ |------|-------------------------------------------|
179
+ | 0 | 所属市场标识(如:1=大陆、100=港股、200=美股等) |
180
+ | 1 | 名称 |
181
+ | 2 | 代码 |
182
+ | 3 | 当前价格 |
183
+ | 4 | 涨跌额 |
184
+ | 5 | 涨跌幅(%) |
185
+ | 6 | 成交量(手)或成交量 |
186
+ | 7 | 成交额(万)或总成交额 |
187
+ | 8+ | 其他信息(如总市值等,因标的不同略有差异)|
188
+
189
+ ---
190
+
191
+ ### 3.3 实时资金流向接口(主力 / 散户)
192
+
193
+ **用途**:获取个股的主力与散户资金流向指标。
194
+
195
+ **参数格式**:
196
+
197
+ ```text
198
+ q=ff_<market><code>
199
+ ```
200
+
201
+ **示例**:
202
+
203
+ ```text
204
+ http://qt.gtimg.cn/q=ff_sz000858
205
+ http://qt.gtimg.cn/q=ff_sh600519
206
+ ```
207
+
208
+ **典型字段含义(按 `~` 分割,节选)**:
209
+
210
+ | 下标 | 含义 |
211
+ |------|-------------------------------------|
212
+ | 0 | 代码 |
213
+ | 1 | 主力流入 |
214
+ | 2 | 主力流出 |
215
+ | 3 | 主力净流入 |
216
+ | 4 | 主力净流入 / 总资金流(比例) |
217
+ | 5 | 散户流入 |
218
+ | 6 | 散户流出 |
219
+ | 7 | 散户净流入 |
220
+ | 8 | 散户净流入 / 总资金流(比例) |
221
+ | 9 | 总资金流(1+2+5+6) |
222
+ | 12 | 名称 |
223
+ | 13 | 日期 |
224
+
225
+ ---
226
+
227
+ ### 3.4 盘口大单统计接口(买盘 / 卖盘)
228
+
229
+ **用途**:获取该标的买卖盘中大单/小单的分布占比,常用作“主力/散户”辅助指标。
230
+
231
+ **参数格式**:
232
+
233
+ ```text
234
+ q=s_pk<market><code>
235
+ ```
236
+
237
+ **示例**:
238
+
239
+ ```text
240
+ http://qt.gtimg.cn/q=s_pksz000858
241
+ http://qt.gtimg.cn/q=s_pksh600519
242
+ ```
243
+
244
+ **字段说明**(按 `~` 分割):
245
+
246
+ | 下标 | 含义 |
247
+ |------|----------------|
248
+ | 0 | 买盘大单占比 |
249
+ | 1 | 买盘小单占比 |
250
+ | 2 | 卖盘大单占比 |
251
+ | 3 | 卖盘小单占比 |
252
+
253
+ ---
254
+
255
+ ### 3.5 港股扩展行情接口(`r_hk`)
256
+
257
+ **用途**:港股标的的较为完整行情数据(字段结构与 A 股略有区别)。
258
+
259
+ **参数格式**:
260
+
261
+ ```text
262
+ q=r_hk<code> # 如港股 09988
263
+ ```
264
+
265
+ **示例**:
266
+
267
+ ```text
268
+ http://qt.gtimg.cn/q=r_hk09988
269
+ ```
270
+
271
+ 典型字段包含:当前价、昨收、今开、成交量、成交额、52 周高低、市盈率、市净率、每手股数、流通市值等,具体字段顺序和意义请以实际返回为准。
272
+
273
+ ---
274
+
275
+ ### 3.6 美股简要行情接口(`s_us`)
276
+
277
+ **用途**:获取美股标的的简要行情。
278
+
279
+ **参数格式**:
280
+
281
+ ```text
282
+ q=s_us<代码>
283
+ ```
284
+
285
+ **示例**:
286
+
287
+ ```text
288
+ http://qt.gtimg.cn/?q=s_usBABA
289
+ ```
290
+
291
+ 典型字段包括:市场标识、名称、代码、现价、涨跌额、涨跌幅、成交量、成交额和市值等,字段位置请以实际返回为准。
292
+
293
+ ---
294
+
295
+ ### 3.7 公募基金行情接口(`jj`)
296
+
297
+ **用途**:获取开放式基金(如混合型、债券型等)的净值相关数据。
298
+
299
+ **参数格式**:
300
+
301
+ ```text
302
+ q=jj<六位基金代码>
303
+ ```
304
+
305
+ **示例**:
306
+
307
+ ```text
308
+ http://qt.gtimg.cn/q=jj000001
309
+ ```
310
+
311
+ 基金返回串示例(节选):
312
+
313
+ ```text
314
+ v_jj000001="000001~华夏成长混合~0.0000~0.0000~~1.0270~3.6000~1.0827~2025-11-26~...";
315
+ ```
316
+
317
+ 典型字段大致包括:基金代码、基金名称、单位净值、累计净值、前一日净值、最新净值日期等,具体顺序和含义建议根据实际返回逐一核对。
318
+
319
+ ---
320
+
321
+ ### 3.8 指数简要接口(指数 / 港股指数 / 美股指数)
322
+
323
+ **用途**:获取指数层面的简要行情信息。
324
+
325
+ **参数格式**:
326
+
327
+ ```text
328
+ q=s_<market><index_code>
329
+ ```
330
+
331
+ **常见示例**:
332
+
333
+ - 上证指数:
334
+
335
+ ```text
336
+ http://qt.gtimg.cn/q=s_sh000001
337
+ ```
338
+
339
+ - 深成指、创业板等:
340
+
341
+ ```text
342
+ http://qt.gtimg.cn/q=s_sz399001,s_sz399006
343
+ ```
344
+
345
+ - 道琼斯指数:
346
+
347
+ ```text
348
+ http://qt.gtimg.cn/q=s_usDJI
349
+ ```
350
+
351
+ - 恒生指数:
352
+
353
+ ```text
354
+ http://qt.gtimg.cn/q=s_r_hkHSI
355
+ ```
356
+
357
+ - 其他指数示例:
358
+
359
+ ```text
360
+ http://qt.gtimg.cn/q=s_sh000847
361
+ ```
362
+
363
+ 字段含义与 3.2 的简要行情接口类似,但具体位置会有差异,建议针对每个指数实际打印返回串。
364
+
365
+ ---
366
+
367
+ ### 3.9 期货 / 其他衍生品(经验型)
368
+
369
+ 部分社区经验表明,商品期货等品种也可以通过类似股票的代码与 `q=` 接口获取行情,比如使用特定字母+数字组合(如:`RB0`、`AU0` 等)作为代码。
370
+
371
+ 由于期货合约代码体系复杂、缺乏统一文档,建议:
372
+
373
+ 1. 找到腾讯行情页面对应品种;
374
+ 2. 通过浏览器 DevTools 抓包,看前端实际请求的 `qt.gtimg.cn` URL;
375
+ 3. 总结出实际使用的代码与字段含义,而不要仅凭第三方表格。
376
+
377
+ ---
378
+
379
+ ### 3.10 批量查询与组合
380
+
381
+ 所有上述 `q=` 形式接口都支持 **逗号分隔的批量查询**:
382
+
383
+ ```text
384
+ # 同时查询 A 股、指数、港股、美股、基金
385
+ http://qt.gtimg.cn/q=sh600000,sz000858,s_sh000001,hk00001,s_usBABA,jj000001
386
+ ```
387
+
388
+ - 服务器会按顺序返回多行 `v_...="..."`;
389
+ - 可以按 `;` 切行,再根据每行变量名前缀(`v_s_` / `v_ff_` / `v_jj` 等)决定用哪一套解析逻辑。
390
+
391
+ ---
392
+
393
+ ## 4. 返回数据解析要点
394
+
395
+ ### 4.1 通用解析流程(示意)
396
+
397
+ 建议的通用解析步骤:
398
+
399
+ 1. 发起 GET 请求,拿到 `bytes` 响应体;
400
+ 2. 使用 GBK/GB2312 解码为 UTF-8 字符串;
401
+ 3. 按 `;` 拆分为多行字符串;
402
+ 4. 对每行:
403
+ - 忽略空行;
404
+ - 以 `=` 拆分为左侧变量名和右侧 `"..."` 内容;
405
+ - 去掉右侧两端双引号;
406
+ - 对内容按 `~` 分割为数组;
407
+ - 根据变量名前缀(`v_sz...` / `v_s_sz...` / `v_ff_sz...` / `v_jj...` 等)选择对应字段映射。
408
+
409
+ 伪代码示例(语言无关):
410
+
411
+ ```pseudo
412
+ resp_bytes = http_get("http://qt.gtimg.cn/q=sz000858")
413
+ text = decode_gbk(resp_bytes)
414
+
415
+ for line in split(text, ';'):
416
+ line = trim(line)
417
+ if line is empty: continue
418
+
419
+ name, raw = split_once(line, '=') # e.g. name = 'v_sz000858'
420
+ raw = strip_quotes(raw) # remove leading/trailing "
421
+
422
+ fields = split(raw, '~')
423
+
424
+ if name starts_with 'v_s_':
425
+ parse_simple_quote(fields)
426
+ elif name starts_with 'v_ff_':
427
+ parse_fund_flow(fields)
428
+ elif name starts_with 'v_jj':
429
+ parse_fund(fields)
430
+ else:
431
+ parse_full_quote(fields)
432
+ ```
433
+
434
+ ### 4.2 容错与版本差异
435
+
436
+ 由于这些接口并非正式公开 API,存在如下风险:
437
+
438
+ - 某些字段在不同时间段可能新增或废弃;
439
+ - 不同市场(A 股 / 港股 / 美股 / 基金)字段数量与含义会有细微差异;
440
+ - 个别字段意义在社区文章中仍存在“猜测”成分。
441
+
442
+ 建议:
443
+
444
+ - 解析时对数组长度做判断,字段不足时设置为默认值;
445
+ - 对暂时不需要的尾部字段,先留作原始字符串保存,方便后续升级;
446
+ - 重要业务逻辑不要依赖尚未验证或不稳定的字段。
447
+
448
+ ---
449
+
450
+ ## 5. 与其它腾讯财经域名的关系(扩展,可选)
451
+
452
+ 虽然本文档只聚焦 `qt.gtimg.cn`,但实际腾讯财经生态中还有:
453
+
454
+ - **K 线与分时数据**:`data.gtimg.cn/flashdata/...` 提供日 K、周 K、月 K、分时、五日分时等 JS 数据文件;
455
+ - **逐笔成交明细/大单数据**:`stock.gtimg.cn`、`stock.finance.qq.com` 等域名提供更细粒度明细数据。
456
+
457
+ 如果后续需要“历史行情 / K 线 / Tick 明细”层面的数据,可以在此基础上单独整理这些域名的接口。
458
+
459
+ ---
460
+
461
+ ## 6. 小结
462
+
463
+ 目前社区可确认、且相对稳定使用的 `qt.gtimg.cn` 主要接口族可概括为:
464
+
465
+ 1. **实时全量行情**:`q=<market><code>`
466
+ 2. **简要行情**:`q=s_<market><code>`
467
+ 3. **资金流向**:`q=ff_<market><code>`
468
+ 4. **盘口大单统计**:`q=s_pk<market><code>`
469
+ 5. **港股扩展行情**:`q=r_hk<code>`
470
+ 6. **美股简要行情**:`q=s_us<code>`
471
+ 7. **公募基金行情**:`q=jj<code>`
472
+ 8. **指数简要**:`q=s_<market><index>` / `q=s_r_hk<index>`
473
+
474
+ 在此基础上,你可以进一步:
475
+
476
+ - 封装内部 SDK / 客户端库;
477
+ - 定义统一的 DTO / 字段映射;
478
+ - 实现重试、限流与缓存策略;
479
+ - 补充自己业务关心的字段说明与示例。
480
+
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "stock-sdk",
3
+ "version": "1.0.0",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "scripts": {
7
+ "build": "tsc",
8
+ "test": "vitest run"
9
+ },
10
+ "keywords": [
11
+ "stock",
12
+ "tencent",
13
+ "qt.gtimg.cn",
14
+ "sdk"
15
+ ],
16
+ "author": "",
17
+ "license": "ISC",
18
+ "description": "Tencent qt.gtimg.cn stock quote SDK",
19
+ "dependencies": {
20
+ "axios": "^1.13.2",
21
+ "iconv-lite": "^0.7.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^24.10.2",
25
+ "typescript": "^5.9.3",
26
+ "vitest": "^4.0.15"
27
+ },
28
+ "publishConfig": {
29
+ "registry": "https://registry.npmjs.org/"
30
+ },
31
+ "packageManager": "yarn@4.6.0+sha512.5383cc12567a95f1d668fbe762dfe0075c595b4bfff433be478dbbe24e05251a8e8c3eb992a986667c1d53b6c3a9c85b8398c35a960587fbd9fa3a0915406728"
32
+ }
@@ -0,0 +1,97 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import TencentStockSDK from './index';
3
+
4
+ const sdk = new TencentStockSDK();
5
+
6
+ describe('TencentStockSDK', () => {
7
+ describe('getFullQuotes', () => {
8
+ it('should return A股全量行情', async () => {
9
+ const res = await sdk.getFullQuotes(['sz000858']);
10
+ expect(res.length).toBeGreaterThan(0);
11
+ const q = res[0];
12
+ expect(q.code).toBe('000858');
13
+ expect(q.name).toContain('粮');
14
+ expect(typeof q.price).toBe('number');
15
+ expect(q.bid.length).toBe(5);
16
+ expect(q.ask.length).toBe(5);
17
+ });
18
+ });
19
+
20
+ describe('getSimpleQuotes', () => {
21
+ it('should return 简要行情', async () => {
22
+ const res = await sdk.getSimpleQuotes(['s_sz000858']);
23
+ expect(res.length).toBeGreaterThan(0);
24
+ const q = res[0];
25
+ expect(q.code).toBe('000858');
26
+ expect(typeof q.price).toBe('number');
27
+ });
28
+
29
+ it('should return 指数简要行情', async () => {
30
+ const res = await sdk.getSimpleQuotes(['s_sh000001']);
31
+ expect(res.length).toBeGreaterThan(0);
32
+ const q = res[0];
33
+ expect(q.code).toBe('000001');
34
+ expect(q.name).toContain('指数');
35
+ });
36
+ });
37
+
38
+ describe('getFundFlow', () => {
39
+ it('should return 资金流向', async () => {
40
+ const res = await sdk.getFundFlow(['ff_sz000858']);
41
+ expect(res.length).toBeGreaterThan(0);
42
+ const q = res[0];
43
+ expect(q.code).toContain('sz000858');
44
+ expect(typeof q.mainInflow).toBe('number');
45
+ });
46
+ });
47
+
48
+ describe('getPanelLargeOrder', () => {
49
+ it('should return 盘口大单占比', async () => {
50
+ const res = await sdk.getPanelLargeOrder(['s_pksz000858']);
51
+ expect(res.length).toBeGreaterThan(0);
52
+ const q = res[0];
53
+ expect(typeof q.buyLargeRatio).toBe('number');
54
+ expect(typeof q.sellLargeRatio).toBe('number');
55
+ });
56
+ });
57
+
58
+ describe('getHKQuotes', () => {
59
+ it('should return 港股扩展行情', async () => {
60
+ const res = await sdk.getHKQuotes(['r_hk09988']);
61
+ expect(res.length).toBeGreaterThan(0);
62
+ const q = res[0];
63
+ expect(q.code).toBe('09988');
64
+ expect(typeof q.price).toBe('number');
65
+ });
66
+ });
67
+
68
+ describe('getUSQuotes', () => {
69
+ it('should return 美股简要行情', async () => {
70
+ const res = await sdk.getUSQuotes(['s_usBABA']);
71
+ expect(res.length).toBeGreaterThan(0);
72
+ const q = res[0];
73
+ expect(q.code).toContain('BABA');
74
+ expect(typeof q.price).toBe('number');
75
+ });
76
+ });
77
+
78
+ describe('getFundQuotes', () => {
79
+ it('should return 公募基金行情', async () => {
80
+ const res = await sdk.getFundQuotes(['jj000001']);
81
+ expect(res.length).toBeGreaterThan(0);
82
+ const q = res[0];
83
+ expect(q.code).toBe('000001');
84
+ expect(typeof q.nav).toBe('number');
85
+ });
86
+ });
87
+
88
+ describe('batchRaw', () => {
89
+ it('should return 批量混合查询原始结果', async () => {
90
+ const res = await sdk.batchRaw('sz000858,s_sh000001');
91
+ expect(res.length).toBe(2);
92
+ expect(res[0].key).toContain('sz000858');
93
+ expect(res[1].key).toContain('sh000001');
94
+ });
95
+ });
96
+ });
97
+