qdata-quote 0.2.2__tar.gz → 0.3.0__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.
Files changed (21) hide show
  1. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/PKG-INFO +23 -8
  2. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/README.md +22 -7
  3. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/pyproject.toml +1 -1
  4. qdata_quote-0.3.0/src/qdata_quote/__init__.py +4 -0
  5. qdata_quote-0.3.0/src/qdata_quote/stock_codes.py +74 -0
  6. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/uv.lock +1 -1
  7. qdata_quote-0.2.2/src/qdata_quote/__init__.py +0 -3
  8. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/.gitignore +0 -0
  9. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/docs/superpowers/plans/2026-06-12-quote-service.md +0 -0
  10. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/docs/superpowers/specs/2026-06-12-quote-service-design.md +0 -0
  11. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/src/qdata_quote/bench.py +0 -0
  12. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/src/qdata_quote/service.py +0 -0
  13. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/src/qdata_quote/sources/__init__.py +0 -0
  14. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/src/qdata_quote/sources/base.py +0 -0
  15. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/src/qdata_quote/sources/sina.py +0 -0
  16. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/src/qdata_quote/sources/tencent.py +0 -0
  17. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/src/qdata_quote/types.py +0 -0
  18. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/tests/test_service.py +0 -0
  19. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/tests/test_sina.py +0 -0
  20. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/tests/test_tencent.py +0 -0
  21. {qdata_quote-0.2.2 → qdata_quote-0.3.0}/tests/test_types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qdata-quote
3
- Version: 0.2.2
3
+ Version: 0.3.0
4
4
  Summary: 实时行情采集服务,支持新浪和腾讯数据源
5
5
  License-Expression: MIT
6
6
  Requires-Python: >=3.10
@@ -25,12 +25,13 @@ pip install qdata-quote
25
25
  ## 快速开始
26
26
 
27
27
  ```python
28
- from qdata_quote import QuoteService
28
+ from qdata_quote import QuoteService, get_stock_codes
29
29
 
30
- service = QuoteService()
30
+ # 获取全市场股票代码(首次从网络获取约 4 秒,后续读缓存 <1ms)
31
+ codes = get_stock_codes()
31
32
 
32
- # 设置全市场股票代码(必需)
33
- service.set_stock_codes(["000001", "600000", "600036", "300750"])
33
+ service = QuoteService()
34
+ service.set_stock_codes(codes)
34
35
 
35
36
  # 同步获取指定股票行情
36
37
  df = service.get_real_sync(["000001", "600000"])
@@ -45,6 +46,20 @@ df = asyncio.run(service.get_real(["000001", "600000"]))
45
46
  df_all = asyncio.run(service.get_all())
46
47
  ```
47
48
 
49
+ ## 获取股票代码
50
+
51
+ ```python
52
+ from qdata_quote import get_stock_codes
53
+
54
+ # 读取缓存(如果没有缓存则自动获取)
55
+ codes = get_stock_codes()
56
+
57
+ # 强制从网络刷新
58
+ codes = get_stock_codes(refresh=True)
59
+ ```
60
+
61
+ 缓存文件位置:`~/.qdata_quote/stock_codes.json`
62
+
48
63
  ## 数据源
49
64
 
50
65
  支持两个数据源,通过 `source` 参数指定:
@@ -109,18 +124,18 @@ df = service.get_real_sync(["000001"], source="tencent")
109
124
  ```python
110
125
  # 同步
111
126
  with QuoteService() as service:
112
- service.set_stock_codes(codes)
127
+ service.set_stock_codes(get_stock_codes())
113
128
  df = service.get_all_sync()
114
129
 
115
130
  # 异步
116
131
  async with QuoteService() as service:
117
- service.set_stock_codes(codes)
132
+ service.set_stock_codes(get_stock_codes())
118
133
  df = await service.get_all()
119
134
  ```
120
135
 
121
136
  ## 性能对比
122
137
 
123
- 与 easyquotation 对比(5610 只股票):
138
+ 与 easyquotation 对比(5500+ 只股票):
124
139
 
125
140
  | 数据源 | easyquotation | qdata_quote sync | qdata_quote async |
126
141
  |--------|--------------|-------------------|-------------------|
@@ -11,12 +11,13 @@ pip install qdata-quote
11
11
  ## 快速开始
12
12
 
13
13
  ```python
14
- from qdata_quote import QuoteService
14
+ from qdata_quote import QuoteService, get_stock_codes
15
15
 
16
- service = QuoteService()
16
+ # 获取全市场股票代码(首次从网络获取约 4 秒,后续读缓存 <1ms)
17
+ codes = get_stock_codes()
17
18
 
18
- # 设置全市场股票代码(必需)
19
- service.set_stock_codes(["000001", "600000", "600036", "300750"])
19
+ service = QuoteService()
20
+ service.set_stock_codes(codes)
20
21
 
21
22
  # 同步获取指定股票行情
22
23
  df = service.get_real_sync(["000001", "600000"])
@@ -31,6 +32,20 @@ df = asyncio.run(service.get_real(["000001", "600000"]))
31
32
  df_all = asyncio.run(service.get_all())
32
33
  ```
33
34
 
35
+ ## 获取股票代码
36
+
37
+ ```python
38
+ from qdata_quote import get_stock_codes
39
+
40
+ # 读取缓存(如果没有缓存则自动获取)
41
+ codes = get_stock_codes()
42
+
43
+ # 强制从网络刷新
44
+ codes = get_stock_codes(refresh=True)
45
+ ```
46
+
47
+ 缓存文件位置:`~/.qdata_quote/stock_codes.json`
48
+
34
49
  ## 数据源
35
50
 
36
51
  支持两个数据源,通过 `source` 参数指定:
@@ -95,18 +110,18 @@ df = service.get_real_sync(["000001"], source="tencent")
95
110
  ```python
96
111
  # 同步
97
112
  with QuoteService() as service:
98
- service.set_stock_codes(codes)
113
+ service.set_stock_codes(get_stock_codes())
99
114
  df = service.get_all_sync()
100
115
 
101
116
  # 异步
102
117
  async with QuoteService() as service:
103
- service.set_stock_codes(codes)
118
+ service.set_stock_codes(get_stock_codes())
104
119
  df = await service.get_all()
105
120
  ```
106
121
 
107
122
  ## 性能对比
108
123
 
109
- 与 easyquotation 对比(5610 只股票):
124
+ 与 easyquotation 对比(5500+ 只股票):
110
125
 
111
126
  | 数据源 | easyquotation | qdata_quote sync | qdata_quote async |
112
127
  |--------|--------------|-------------------|-------------------|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "qdata-quote"
7
- version = "0.2.2"
7
+ version = "0.3.0"
8
8
  description = "实时行情采集服务,支持新浪和腾讯数据源"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -0,0 +1,4 @@
1
+ from .service import QuoteService
2
+ from .stock_codes import get_stock_codes
3
+
4
+ __all__ = ["QuoteService", "get_stock_codes"]
@@ -0,0 +1,74 @@
1
+ """全市场股票代码获取与缓存"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import os
7
+ from concurrent.futures import ThreadPoolExecutor
8
+ from pathlib import Path
9
+
10
+ import requests
11
+
12
+ _CACHE_PATH = Path.home() / ".qdata_quote" / "stock_codes.json"
13
+
14
+
15
+ def get_stock_codes(refresh: bool = False) -> list[str]:
16
+ """获取全市场 A 股股票代码列表
17
+
18
+ 首次调用从新浪 API 获取并缓存到本地,后续直接读取缓存。
19
+
20
+ Args:
21
+ refresh: 是否强制从网络刷新,默认 False 读取缓存
22
+
23
+ Returns:
24
+ 股票代码列表,如 ["000001", "000002", "600000", ...]
25
+ """
26
+ if not refresh and _CACHE_PATH.exists():
27
+ with open(_CACHE_PATH) as f:
28
+ return json.load(f)
29
+
30
+ codes = _fetch_from_sina()
31
+ _CACHE_PATH.parent.mkdir(parents=True, exist_ok=True)
32
+ with open(_CACHE_PATH, "w") as f:
33
+ json.dump(codes, f)
34
+ return codes
35
+
36
+
37
+ def _fetch_from_sina() -> list[str]:
38
+ """从新浪 API 并发分页获取全部 A 股代码"""
39
+ session = requests.Session()
40
+ session.headers.update(
41
+ {
42
+ "Referer": "https://finance.sina.com.cn/",
43
+ "User-Agent": (
44
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
45
+ "AppleWebKit/537.36 (KHTML, like Gecko) "
46
+ "Chrome/120.0.0.0 Safari/537.36"
47
+ ),
48
+ }
49
+ )
50
+ base_url = (
51
+ "https://vip.stock.finance.sina.com.cn/quotes_service/"
52
+ "api/json_v2.php/Market_Center.getHQNodeData?"
53
+ "page={}&num=80&sort=symbol&asc=1&node=hs_a&symbol="
54
+ )
55
+
56
+ def fetch_page(page):
57
+ try:
58
+ r = session.get(base_url.format(page), timeout=10)
59
+ data = json.loads(r.text)
60
+ return [s["code"] for s in data] if data else []
61
+ except Exception:
62
+ return []
63
+
64
+ # 80 页覆盖约 6400 只,超过当前 A 股总数
65
+ with ThreadPoolExecutor(max_workers=20) as pool:
66
+ results = pool.map(fetch_page, range(1, 81))
67
+
68
+ all_codes = []
69
+ for codes in results:
70
+ all_codes.extend(codes)
71
+
72
+ session.close()
73
+ # 去重保序
74
+ return list(dict.fromkeys(all_codes))
@@ -1103,7 +1103,7 @@ wheels = [
1103
1103
 
1104
1104
  [[package]]
1105
1105
  name = "qdata-quote"
1106
- version = "0.2.0"
1106
+ version = "0.2.2"
1107
1107
  source = { editable = "." }
1108
1108
  dependencies = [
1109
1109
  { name = "aiohttp" },
@@ -1,3 +0,0 @@
1
- from .service import QuoteService
2
-
3
- __all__ = ["QuoteService"]
File without changes