rquote 0.3.8__tar.gz → 0.4.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.
- {rquote-0.3.8/rquote.egg-info → rquote-0.4.0}/PKG-INFO +57 -5
- rquote-0.3.8/PKG-INFO → rquote-0.4.0/README.md +53 -15
- {rquote-0.3.8 → rquote-0.4.0}/pyproject.toml +5 -2
- {rquote-0.3.8 → rquote-0.4.0}/rquote/__init__.py +6 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/api/price.py +43 -2
- rquote-0.4.0/rquote/cache/__init__.py +14 -0
- rquote-0.4.0/rquote/cache/persistent.py +421 -0
- rquote-0.4.0/rquote/markets/base.py +196 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/markets/cn_stock.py +13 -13
- rquote-0.4.0/rquote/markets/future.py +177 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/markets/hk_stock.py +5 -14
- {rquote-0.3.8 → rquote-0.4.0}/rquote/markets/us_stock.py +8 -9
- {rquote-0.3.8 → rquote-0.4.0}/rquote/parsers/kline.py +12 -4
- rquote-0.3.8/README.md → rquote-0.4.0/rquote.egg-info/PKG-INFO +67 -3
- {rquote-0.3.8 → rquote-0.4.0}/rquote.egg-info/SOURCES.txt +1 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote.egg-info/requires.txt +3 -0
- rquote-0.4.0/tests/test_cache.py +357 -0
- rquote-0.3.8/rquote/cache/__init__.py +0 -9
- rquote-0.3.8/rquote/markets/base.py +0 -49
- rquote-0.3.8/rquote/markets/future.py +0 -92
- rquote-0.3.8/tests/test_cache.py +0 -71
- {rquote-0.3.8 → rquote-0.4.0}/rquote/api/__init__.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/api/lists.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/api/stock_info.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/api/tick.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/cache/base.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/cache/memory.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/config.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/data_sources/__init__.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/data_sources/base.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/data_sources/sina.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/data_sources/tencent.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/exceptions.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/factors/__init__.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/factors/technical.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/markets/__init__.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/markets/factory.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/parsers/__init__.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/plots.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/utils/__init__.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/utils/date.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/utils/helpers.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/utils/http.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/utils/logging.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/utils/web.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote/utils.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote.egg-info/dependency_links.txt +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/rquote.egg-info/top_level.txt +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/setup.cfg +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/tests/test_api.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/tests/test_config.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/tests/test_exceptions.py +0 -0
- {rquote-0.3.8 → rquote-0.4.0}/tests/test_utils.py +0 -0
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rquote
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Mostly day quotes of cn/hk/us/fund/future markets, side with quote list fetch
|
|
5
|
-
Requires-Python: >=3.
|
|
5
|
+
Requires-Python: >=3.9.0
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
7
7
|
Requires-Dist: build>=0.9.0
|
|
8
8
|
Requires-Dist: httpx>=0.20.0
|
|
9
9
|
Requires-Dist: pandas>=1.0.0
|
|
10
10
|
Requires-Dist: setuptools>=42
|
|
11
11
|
Requires-Dist: twine>=3.8.0
|
|
12
|
+
Provides-Extra: persistent
|
|
13
|
+
Requires-Dist: duckdb>=0.9.0; extra == "persistent"
|
|
12
14
|
|
|
13
15
|
# rquote
|
|
14
16
|
|
|
@@ -60,17 +62,67 @@ sid, name, df = get_price('sz000001', sdate='2024-01-01', edate='2024-02-01')
|
|
|
60
62
|
|
|
61
63
|
### 使用缓存
|
|
62
64
|
|
|
65
|
+
#### 内存缓存(MemoryCache)
|
|
66
|
+
|
|
63
67
|
```python
|
|
64
68
|
from rquote import get_price, MemoryCache
|
|
65
69
|
|
|
66
70
|
# 创建缓存实例
|
|
67
71
|
cache = MemoryCache(ttl=3600) # 缓存1小时
|
|
68
72
|
|
|
69
|
-
# 使用缓存(通过dd
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
# 使用缓存(通过dd参数传递MemoryCache实例)
|
|
74
|
+
sid, name, df = get_price('sh000001', dd=cache)
|
|
75
|
+
|
|
76
|
+
# 注意:MemoryCache 是内存缓存,数据仅在当前进程运行期间有效
|
|
77
|
+
# 脚本运行结束后,缓存数据会丢失
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**缓存生命周期说明:**
|
|
81
|
+
- `MemoryCache` 是纯内存缓存,数据存储在进程内存中
|
|
82
|
+
- 缓存数据仅在当前脚本运行期间有效
|
|
83
|
+
- 脚本运行结束后,所有缓存数据会丢失
|
|
84
|
+
|
|
85
|
+
#### 持久化缓存(PersistentCache)
|
|
86
|
+
|
|
87
|
+
持久化缓存支持跨进程/跨运行的缓存持久化,数据会保存到本地文件。
|
|
88
|
+
|
|
89
|
+
**安装可选依赖:**
|
|
90
|
+
```bash
|
|
91
|
+
pip install rquote[persistent]
|
|
92
|
+
# 或
|
|
93
|
+
uv pip install "rquote[persistent]"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**使用持久化缓存:**
|
|
97
|
+
```python
|
|
98
|
+
from rquote import get_price, PersistentCache
|
|
99
|
+
|
|
100
|
+
# 创建持久化缓存实例
|
|
101
|
+
# 默认使用 duckdb(如果已安装),否则使用 pickle 文件
|
|
102
|
+
cache = PersistentCache(ttl=86400) # 缓存24小时,默认路径:~/.rquote/cache.db
|
|
103
|
+
|
|
104
|
+
# 或指定自定义路径
|
|
105
|
+
cache = PersistentCache(db_path='./my_cache.db', use_duckdb=True)
|
|
106
|
+
|
|
107
|
+
# 使用缓存
|
|
108
|
+
sid, name, df = get_price('sh000001', dd=cache)
|
|
109
|
+
|
|
110
|
+
# 持久化缓存支持智能扩展:
|
|
111
|
+
# - 当请求的结束日期不在缓存中时,会自动从缓存的最新日期向前扩展
|
|
112
|
+
# - 当请求的开始日期不在缓存中时,会自动从缓存的最早日期向后扩展
|
|
113
|
+
# - 数据会自动合并,避免重复请求
|
|
114
|
+
|
|
115
|
+
# 关闭缓存(可选,程序退出时会自动保存)
|
|
116
|
+
cache.close()
|
|
72
117
|
```
|
|
73
118
|
|
|
119
|
+
**持久化缓存特性:**
|
|
120
|
+
- ✅ 跨进程/跨运行持久化:数据保存在本地文件,下次运行仍可使用
|
|
121
|
+
- ✅ 智能数据合并:相同股票的数据会自动合并,key 不包含日期范围
|
|
122
|
+
- ✅ 智能扩展:当请求的日期范围超出缓存时,自动扩展并合并数据
|
|
123
|
+
- ✅ 支持 TTL:可设置缓存过期时间
|
|
124
|
+
- ✅ 可选 duckdb:如果安装了 duckdb,使用 duckdb 存储(性能更好),否则使用 pickle 文件
|
|
125
|
+
|
|
74
126
|
## 主要功能
|
|
75
127
|
|
|
76
128
|
### 历史价格数据获取
|
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: rquote
|
|
3
|
-
Version: 0.3.8
|
|
4
|
-
Summary: Mostly day quotes of cn/hk/us/fund/future markets, side with quote list fetch
|
|
5
|
-
Requires-Python: >=3.6.1
|
|
6
|
-
Description-Content-Type: text/markdown
|
|
7
|
-
Requires-Dist: build>=0.9.0
|
|
8
|
-
Requires-Dist: httpx>=0.20.0
|
|
9
|
-
Requires-Dist: pandas>=1.0.0
|
|
10
|
-
Requires-Dist: setuptools>=42
|
|
11
|
-
Requires-Dist: twine>=3.8.0
|
|
12
|
-
|
|
13
1
|
# rquote
|
|
14
2
|
|
|
15
3
|
`rquote` 是一个提供 A股/港股/美股/ETF基金/期货 历史数据获取的Python库
|
|
@@ -60,17 +48,67 @@ sid, name, df = get_price('sz000001', sdate='2024-01-01', edate='2024-02-01')
|
|
|
60
48
|
|
|
61
49
|
### 使用缓存
|
|
62
50
|
|
|
51
|
+
#### 内存缓存(MemoryCache)
|
|
52
|
+
|
|
63
53
|
```python
|
|
64
54
|
from rquote import get_price, MemoryCache
|
|
65
55
|
|
|
66
56
|
# 创建缓存实例
|
|
67
57
|
cache = MemoryCache(ttl=3600) # 缓存1小时
|
|
68
58
|
|
|
69
|
-
# 使用缓存(通过dd
|
|
70
|
-
|
|
71
|
-
|
|
59
|
+
# 使用缓存(通过dd参数传递MemoryCache实例)
|
|
60
|
+
sid, name, df = get_price('sh000001', dd=cache)
|
|
61
|
+
|
|
62
|
+
# 注意:MemoryCache 是内存缓存,数据仅在当前进程运行期间有效
|
|
63
|
+
# 脚本运行结束后,缓存数据会丢失
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**缓存生命周期说明:**
|
|
67
|
+
- `MemoryCache` 是纯内存缓存,数据存储在进程内存中
|
|
68
|
+
- 缓存数据仅在当前脚本运行期间有效
|
|
69
|
+
- 脚本运行结束后,所有缓存数据会丢失
|
|
70
|
+
|
|
71
|
+
#### 持久化缓存(PersistentCache)
|
|
72
|
+
|
|
73
|
+
持久化缓存支持跨进程/跨运行的缓存持久化,数据会保存到本地文件。
|
|
74
|
+
|
|
75
|
+
**安装可选依赖:**
|
|
76
|
+
```bash
|
|
77
|
+
pip install rquote[persistent]
|
|
78
|
+
# 或
|
|
79
|
+
uv pip install "rquote[persistent]"
|
|
72
80
|
```
|
|
73
81
|
|
|
82
|
+
**使用持久化缓存:**
|
|
83
|
+
```python
|
|
84
|
+
from rquote import get_price, PersistentCache
|
|
85
|
+
|
|
86
|
+
# 创建持久化缓存实例
|
|
87
|
+
# 默认使用 duckdb(如果已安装),否则使用 pickle 文件
|
|
88
|
+
cache = PersistentCache(ttl=86400) # 缓存24小时,默认路径:~/.rquote/cache.db
|
|
89
|
+
|
|
90
|
+
# 或指定自定义路径
|
|
91
|
+
cache = PersistentCache(db_path='./my_cache.db', use_duckdb=True)
|
|
92
|
+
|
|
93
|
+
# 使用缓存
|
|
94
|
+
sid, name, df = get_price('sh000001', dd=cache)
|
|
95
|
+
|
|
96
|
+
# 持久化缓存支持智能扩展:
|
|
97
|
+
# - 当请求的结束日期不在缓存中时,会自动从缓存的最新日期向前扩展
|
|
98
|
+
# - 当请求的开始日期不在缓存中时,会自动从缓存的最早日期向后扩展
|
|
99
|
+
# - 数据会自动合并,避免重复请求
|
|
100
|
+
|
|
101
|
+
# 关闭缓存(可选,程序退出时会自动保存)
|
|
102
|
+
cache.close()
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**持久化缓存特性:**
|
|
106
|
+
- ✅ 跨进程/跨运行持久化:数据保存在本地文件,下次运行仍可使用
|
|
107
|
+
- ✅ 智能数据合并:相同股票的数据会自动合并,key 不包含日期范围
|
|
108
|
+
- ✅ 智能扩展:当请求的日期范围超出缓存时,自动扩展并合并数据
|
|
109
|
+
- ✅ 支持 TTL:可设置缓存过期时间
|
|
110
|
+
- ✅ 可选 duckdb:如果安装了 duckdb,使用 duckdb 存储(性能更好),否则使用 pickle 文件
|
|
111
|
+
|
|
74
112
|
## 主要功能
|
|
75
113
|
|
|
76
114
|
### 历史价格数据获取
|
|
@@ -4,10 +4,11 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rquote"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "Mostly day quotes of cn/hk/us/fund/future markets, side with quote list fetch"
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.6.1"
|
|
10
|
+
# requires-python = ">=3.6.1" # duckdb requires higher python version
|
|
11
|
+
requires-python = ">=3.9.0"
|
|
11
12
|
dependencies = [
|
|
12
13
|
"build>=0.9.0",
|
|
13
14
|
"httpx>=0.20.0",
|
|
@@ -15,3 +16,5 @@ dependencies = [
|
|
|
15
16
|
"setuptools>=42",
|
|
16
17
|
"twine>=3.8.0",
|
|
17
18
|
]
|
|
19
|
+
[project.optional-dependencies]
|
|
20
|
+
persistent = ["duckdb>=0.9.0"]
|
|
@@ -35,6 +35,11 @@ from .plots import PlotUtils
|
|
|
35
35
|
from . import config
|
|
36
36
|
from . import exceptions
|
|
37
37
|
from .cache import MemoryCache, Cache
|
|
38
|
+
# 尝试导入持久化缓存(可选依赖)
|
|
39
|
+
try:
|
|
40
|
+
from .cache import PersistentCache
|
|
41
|
+
except ImportError:
|
|
42
|
+
PersistentCache = None
|
|
38
43
|
from .utils.http import HTTPClient
|
|
39
44
|
|
|
40
45
|
|
|
@@ -93,5 +98,6 @@ __all__ = [
|
|
|
93
98
|
'exceptions',
|
|
94
99
|
'MemoryCache',
|
|
95
100
|
'Cache',
|
|
101
|
+
'PersistentCache',
|
|
96
102
|
'HTTPClient',
|
|
97
103
|
]
|
|
@@ -11,6 +11,33 @@ from ..utils.date import check_date_format
|
|
|
11
11
|
from ..exceptions import SymbolError
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
def _normalize_dataframe_index(df: pd.DataFrame) -> pd.DataFrame:
|
|
15
|
+
"""
|
|
16
|
+
统一处理 DataFrame 索引,转换为 DatetimeIndex
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
df: 输入的 DataFrame
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
处理后的 DataFrame,索引为 DatetimeIndex
|
|
23
|
+
"""
|
|
24
|
+
if df.empty:
|
|
25
|
+
return df
|
|
26
|
+
|
|
27
|
+
# 如果已经是 DatetimeIndex,直接返回
|
|
28
|
+
if isinstance(df.index, pd.DatetimeIndex):
|
|
29
|
+
return df
|
|
30
|
+
|
|
31
|
+
# 尝试转换为 DatetimeIndex
|
|
32
|
+
try:
|
|
33
|
+
df.index = pd.to_datetime(df.index)
|
|
34
|
+
except (ValueError, TypeError) as e:
|
|
35
|
+
# 如果转换失败,保持原样(可能是其他类型的索引)
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
return df
|
|
39
|
+
|
|
40
|
+
|
|
14
41
|
def get_price(i: str, sdate: str = '', edate: str = '', freq: str = 'day',
|
|
15
42
|
days: int = 320, fq: str = 'qfq', dd=None) -> Tuple[str, str, pd.DataFrame]:
|
|
16
43
|
'''
|
|
@@ -49,7 +76,12 @@ def get_price(i: str, sdate: str = '', edate: str = '', freq: str = 'day',
|
|
|
49
76
|
market = MarketFactory.create_from_symbol(i, cache=cache)
|
|
50
77
|
|
|
51
78
|
# 调用市场的get_price方法
|
|
52
|
-
|
|
79
|
+
symbol, name, df = market.get_price(i, sdate=sdate, edate=edate, freq=freq, days=days, fq=fq)
|
|
80
|
+
|
|
81
|
+
# 统一后处理:转换索引为 DatetimeIndex
|
|
82
|
+
df = _normalize_dataframe_index(df)
|
|
83
|
+
|
|
84
|
+
return symbol, name, df
|
|
53
85
|
|
|
54
86
|
|
|
55
87
|
def get_price_longer(i: str, l: int = 2, dd=None) -> Tuple[str, str, pd.DataFrame]:
|
|
@@ -65,7 +97,16 @@ def get_price_longer(i: str, l: int = 2, dd=None) -> Tuple[str, str, pd.DataFram
|
|
|
65
97
|
(symbol, name, DataFrame)
|
|
66
98
|
"""
|
|
67
99
|
_, name, a = get_price(i, dd=dd)
|
|
68
|
-
|
|
100
|
+
# 使用 DatetimeIndex 的格式化方法(get_price 已统一转换为 DatetimeIndex)
|
|
101
|
+
if isinstance(a.index, pd.DatetimeIndex) and len(a.index) > 0:
|
|
102
|
+
d1 = a.index[0].strftime('%Y%m%d')
|
|
103
|
+
else:
|
|
104
|
+
# 降级处理:如果索引不是 DatetimeIndex(理论上不应该发生),尝试格式化
|
|
105
|
+
try:
|
|
106
|
+
d1 = str(a.index[0])[:8] if len(str(a.index[0])) >= 8 else str(a.index[0])
|
|
107
|
+
except:
|
|
108
|
+
d1 = a.index.format()[0] if hasattr(a.index, 'format') else str(a.index[0])
|
|
109
|
+
|
|
69
110
|
for y in range(1, l):
|
|
70
111
|
d0 = str(int(d1[:4]) - 1) + d1[4:]
|
|
71
112
|
a = pd.concat((get_price(i, d0, d1, dd=dd)[2], a), 0).drop_duplicates()
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
缓存模块
|
|
4
|
+
"""
|
|
5
|
+
from .base import Cache
|
|
6
|
+
from .memory import MemoryCache
|
|
7
|
+
|
|
8
|
+
# 尝试导入持久化缓存(可选依赖)
|
|
9
|
+
try:
|
|
10
|
+
from .persistent import PersistentCache
|
|
11
|
+
__all__ = ['Cache', 'MemoryCache', 'PersistentCache']
|
|
12
|
+
except ImportError:
|
|
13
|
+
__all__ = ['Cache', 'MemoryCache']
|
|
14
|
+
|