rquote 0.4.2__tar.gz → 0.4.4__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 (51) hide show
  1. {rquote-0.4.2 → rquote-0.4.4}/PKG-INFO +46 -2
  2. {rquote-0.4.2 → rquote-0.4.4}/README.md +45 -1
  3. {rquote-0.4.2 → rquote-0.4.4}/pyproject.toml +1 -1
  4. rquote-0.4.4/rquote/api/stock_info.py +103 -0
  5. rquote-0.4.4/rquote/utils/logging.py +45 -0
  6. {rquote-0.4.2 → rquote-0.4.4}/rquote.egg-info/PKG-INFO +46 -2
  7. rquote-0.4.2/rquote/api/stock_info.py +0 -51
  8. rquote-0.4.2/rquote/utils/logging.py +0 -25
  9. {rquote-0.4.2 → rquote-0.4.4}/rquote/__init__.py +0 -0
  10. {rquote-0.4.2 → rquote-0.4.4}/rquote/api/__init__.py +0 -0
  11. {rquote-0.4.2 → rquote-0.4.4}/rquote/api/lists.py +0 -0
  12. {rquote-0.4.2 → rquote-0.4.4}/rquote/api/price.py +0 -0
  13. {rquote-0.4.2 → rquote-0.4.4}/rquote/api/tick.py +0 -0
  14. {rquote-0.4.2 → rquote-0.4.4}/rquote/cache/__init__.py +0 -0
  15. {rquote-0.4.2 → rquote-0.4.4}/rquote/cache/base.py +0 -0
  16. {rquote-0.4.2 → rquote-0.4.4}/rquote/cache/memory.py +0 -0
  17. {rquote-0.4.2 → rquote-0.4.4}/rquote/cache/persistent.py +0 -0
  18. {rquote-0.4.2 → rquote-0.4.4}/rquote/config.py +0 -0
  19. {rquote-0.4.2 → rquote-0.4.4}/rquote/data_sources/__init__.py +0 -0
  20. {rquote-0.4.2 → rquote-0.4.4}/rquote/data_sources/base.py +0 -0
  21. {rquote-0.4.2 → rquote-0.4.4}/rquote/data_sources/sina.py +0 -0
  22. {rquote-0.4.2 → rquote-0.4.4}/rquote/data_sources/tencent.py +0 -0
  23. {rquote-0.4.2 → rquote-0.4.4}/rquote/exceptions.py +0 -0
  24. {rquote-0.4.2 → rquote-0.4.4}/rquote/factors/__init__.py +0 -0
  25. {rquote-0.4.2 → rquote-0.4.4}/rquote/factors/technical.py +0 -0
  26. {rquote-0.4.2 → rquote-0.4.4}/rquote/markets/__init__.py +0 -0
  27. {rquote-0.4.2 → rquote-0.4.4}/rquote/markets/base.py +0 -0
  28. {rquote-0.4.2 → rquote-0.4.4}/rquote/markets/cn_stock.py +0 -0
  29. {rquote-0.4.2 → rquote-0.4.4}/rquote/markets/factory.py +0 -0
  30. {rquote-0.4.2 → rquote-0.4.4}/rquote/markets/future.py +0 -0
  31. {rquote-0.4.2 → rquote-0.4.4}/rquote/markets/hk_stock.py +0 -0
  32. {rquote-0.4.2 → rquote-0.4.4}/rquote/markets/us_stock.py +0 -0
  33. {rquote-0.4.2 → rquote-0.4.4}/rquote/parsers/__init__.py +0 -0
  34. {rquote-0.4.2 → rquote-0.4.4}/rquote/parsers/kline.py +0 -0
  35. {rquote-0.4.2 → rquote-0.4.4}/rquote/plots.py +0 -0
  36. {rquote-0.4.2 → rquote-0.4.4}/rquote/utils/__init__.py +0 -0
  37. {rquote-0.4.2 → rquote-0.4.4}/rquote/utils/date.py +0 -0
  38. {rquote-0.4.2 → rquote-0.4.4}/rquote/utils/helpers.py +0 -0
  39. {rquote-0.4.2 → rquote-0.4.4}/rquote/utils/http.py +0 -0
  40. {rquote-0.4.2 → rquote-0.4.4}/rquote/utils/web.py +0 -0
  41. {rquote-0.4.2 → rquote-0.4.4}/rquote/utils.py +0 -0
  42. {rquote-0.4.2 → rquote-0.4.4}/rquote.egg-info/SOURCES.txt +0 -0
  43. {rquote-0.4.2 → rquote-0.4.4}/rquote.egg-info/dependency_links.txt +0 -0
  44. {rquote-0.4.2 → rquote-0.4.4}/rquote.egg-info/requires.txt +0 -0
  45. {rquote-0.4.2 → rquote-0.4.4}/rquote.egg-info/top_level.txt +0 -0
  46. {rquote-0.4.2 → rquote-0.4.4}/setup.cfg +0 -0
  47. {rquote-0.4.2 → rquote-0.4.4}/tests/test_api.py +0 -0
  48. {rquote-0.4.2 → rquote-0.4.4}/tests/test_cache.py +0 -0
  49. {rquote-0.4.2 → rquote-0.4.4}/tests/test_config.py +0 -0
  50. {rquote-0.4.2 → rquote-0.4.4}/tests/test_exceptions.py +0 -0
  51. {rquote-0.4.2 → rquote-0.4.4}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rquote
3
- Version: 0.4.2
3
+ Version: 0.4.4
4
4
  Summary: Mostly day quotes of cn/hk/us/fund/future markets, side with quote list fetch
5
5
  Requires-Python: >=3.9.0
6
6
  Description-Content-Type: text/markdown
@@ -18,7 +18,7 @@ Requires-Dist: duckdb>=0.9.0; extra == "persistent"
18
18
 
19
19
  ## 版本信息
20
20
 
21
- 当前版本:**0.4.2**
21
+ 当前版本:**0.4.4**
22
22
 
23
23
  ## 主要特性
24
24
 
@@ -346,6 +346,50 @@ os.environ['RQUOTE_HTTP_TIMEOUT'] = '20'
346
346
  config_from_env = config.Config.from_env()
347
347
  ```
348
348
 
349
+ ### 日志配置
350
+
351
+ **默认情况下,日志功能是关闭的。** 如果需要启用日志,可以通过环境变量手动开启:
352
+
353
+ #### 通过环境变量开启日志
354
+
355
+ ```bash
356
+ # 设置日志级别为 INFO(会同时输出到文件和控制台)
357
+ export RQUOTE_LOG_LEVEL=INFO
358
+
359
+ # 可选:自定义日志文件路径(默认为 /tmp/rquote.log)
360
+ export RQUOTE_LOG_FILE=/path/to/your/logfile.log
361
+
362
+ # 然后运行你的Python脚本
363
+ python your_script.py
364
+ ```
365
+
366
+ #### 支持的日志级别
367
+
368
+ - `DEBUG`: 详细的调试信息
369
+ - `INFO`: 一般信息(推荐)
370
+ - `WARNING`: 警告信息
371
+ - `ERROR`: 错误信息
372
+ - `CRITICAL`: 严重错误
373
+
374
+ #### 在Python代码中开启日志
375
+
376
+ ```python
377
+ import os
378
+
379
+ # 在导入 rquote 之前设置环境变量
380
+ os.environ['RQUOTE_LOG_LEVEL'] = 'INFO'
381
+ os.environ['RQUOTE_LOG_FILE'] = '/tmp/rquote.log' # 可选
382
+
383
+ from rquote import get_price
384
+
385
+ # 现在日志已启用
386
+ sid, name, df = get_price('sh000001')
387
+ ```
388
+
389
+ #### 关闭日志
390
+
391
+ 如果不设置 `RQUOTE_LOG_LEVEL` 环境变量,或者设置为空值,日志功能将保持关闭状态(默认行为)。
392
+
349
393
  ### 使用改进的HTTP客户端
350
394
 
351
395
  ```python
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## 版本信息
6
6
 
7
- 当前版本:**0.4.2**
7
+ 当前版本:**0.4.4**
8
8
 
9
9
  ## 主要特性
10
10
 
@@ -332,6 +332,50 @@ os.environ['RQUOTE_HTTP_TIMEOUT'] = '20'
332
332
  config_from_env = config.Config.from_env()
333
333
  ```
334
334
 
335
+ ### 日志配置
336
+
337
+ **默认情况下,日志功能是关闭的。** 如果需要启用日志,可以通过环境变量手动开启:
338
+
339
+ #### 通过环境变量开启日志
340
+
341
+ ```bash
342
+ # 设置日志级别为 INFO(会同时输出到文件和控制台)
343
+ export RQUOTE_LOG_LEVEL=INFO
344
+
345
+ # 可选:自定义日志文件路径(默认为 /tmp/rquote.log)
346
+ export RQUOTE_LOG_FILE=/path/to/your/logfile.log
347
+
348
+ # 然后运行你的Python脚本
349
+ python your_script.py
350
+ ```
351
+
352
+ #### 支持的日志级别
353
+
354
+ - `DEBUG`: 详细的调试信息
355
+ - `INFO`: 一般信息(推荐)
356
+ - `WARNING`: 警告信息
357
+ - `ERROR`: 错误信息
358
+ - `CRITICAL`: 严重错误
359
+
360
+ #### 在Python代码中开启日志
361
+
362
+ ```python
363
+ import os
364
+
365
+ # 在导入 rquote 之前设置环境变量
366
+ os.environ['RQUOTE_LOG_LEVEL'] = 'INFO'
367
+ os.environ['RQUOTE_LOG_FILE'] = '/tmp/rquote.log' # 可选
368
+
369
+ from rquote import get_price
370
+
371
+ # 现在日志已启用
372
+ sid, name, df = get_price('sh000001')
373
+ ```
374
+
375
+ #### 关闭日志
376
+
377
+ 如果不设置 `RQUOTE_LOG_LEVEL` 环境变量,或者设置为空值,日志功能将保持关闭状态(默认行为)。
378
+
335
379
  ### 使用改进的HTTP客户端
336
380
 
337
381
  ```python
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rquote"
7
- version = "0.4.2"
7
+ version = "0.4.4"
8
8
  description = "Mostly day quotes of cn/hk/us/fund/future markets, side with quote list fetch"
9
9
  readme = "README.md"
10
10
  # requires-python = ">=3.6.1" # duckdb requires higher python version
@@ -0,0 +1,103 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 股票信息相关API
4
+ """
5
+ import json
6
+ from typing import List, Optional, Any
7
+ from ..utils import hget
8
+ from ..exceptions import HTTPError
9
+ from ..cache import Cache
10
+ from ..cache.memory import DictCache as DictCacheAdapter
11
+
12
+
13
+ def _normalize_stock_code(code: str) -> str:
14
+ """标准化股票代码"""
15
+ return {'6': 'sh', '0': 'sz', '3': 'sz'}.get(code[0], '') + code if code[0] in ['6', '0', '3'] else code
16
+
17
+
18
+ def _get_cache_adapter(dd: Optional[Any]) -> Optional[Cache]:
19
+ """获取缓存适配器"""
20
+ if dd is None:
21
+ return None
22
+ if isinstance(dd, dict):
23
+ return DictCacheAdapter(dd)
24
+ elif isinstance(dd, Cache):
25
+ return dd
26
+ elif hasattr(dd, 'get') and hasattr(dd, 'put'):
27
+ return DictCacheAdapter(dd)
28
+ return None
29
+
30
+
31
+ def _fetch_stock_plate_data(normalized_code: str, data_key: str, error_msg: str) -> List[str]:
32
+ """获取股票板块数据的通用函数"""
33
+ url = f'https://proxy.finance.qq.com/ifzqgtimg/appstock/app/stockinfo/plateNew?code={normalized_code}&app=wzq&zdf=1'
34
+ a = hget(url)
35
+ if not a:
36
+ raise HTTPError(f'Failed to fetch {error_msg} from QQ Finance')
37
+ data = json.loads(a.text)
38
+ if data.get('code') != 0:
39
+ raise HTTPError('API returned error: {}'.format(data.get('msg', 'Unknown error')))
40
+ return data.get('data', {}).get(data_key, [])
41
+
42
+
43
+ def get_stock_concepts(i: str, dd: Optional[Any] = None) -> List[str]:
44
+ """
45
+ 获取指定股票所属的概念板块
46
+
47
+ Args:
48
+ i: 股票代码
49
+ dd: data dictionary或Cache对象,任何有get/put方法的本地缓存
50
+
51
+ Returns:
52
+ 概念代码列表
53
+ """
54
+ cache = _get_cache_adapter(dd)
55
+ normalized_code = _normalize_stock_code(i)
56
+ cache_key = f'stock_concepts:{normalized_code}'
57
+
58
+ # 尝试从缓存获取
59
+ if cache:
60
+ cached_result = cache.get(cache_key)
61
+ if cached_result is not None:
62
+ return cached_result
63
+
64
+ # 缓存未命中,请求网络
65
+ result = _fetch_stock_plate_data(normalized_code, 'concept', 'concepts')
66
+
67
+ # 存入缓存
68
+ if cache:
69
+ cache.put(cache_key, result)
70
+
71
+ return result
72
+
73
+
74
+ def get_stock_industry(i: str, dd: Optional[Any] = None) -> List[str]:
75
+ """
76
+ 获取指定股票所属的行业板块
77
+
78
+ Args:
79
+ i: 股票代码
80
+ dd: data dictionary或Cache对象,任何有get/put方法的本地缓存
81
+
82
+ Returns:
83
+ 行业代码列表
84
+ """
85
+ cache = _get_cache_adapter(dd)
86
+ normalized_code = _normalize_stock_code(i)
87
+ cache_key = f'stock_industry:{normalized_code}'
88
+
89
+ # 尝试从缓存获取
90
+ if cache:
91
+ cached_result = cache.get(cache_key)
92
+ if cached_result is not None:
93
+ return cached_result
94
+
95
+ # 缓存未命中,请求网络
96
+ result = _fetch_stock_plate_data(normalized_code, 'plate', 'industry')
97
+
98
+ # 存入缓存
99
+ if cache:
100
+ cache.put(cache_key, result)
101
+
102
+ return result
103
+
@@ -0,0 +1,45 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 日志工具
4
+ """
5
+ import logging
6
+ import os
7
+
8
+
9
+ def setup_logger():
10
+ """设置日志记录器"""
11
+ logger = logging.getLogger('rquote')
12
+ if not logger.handlers:
13
+ # 默认关闭日志,通过环境变量 RQUOTE_LOG_LEVEL 控制
14
+ log_level = os.getenv('RQUOTE_LOG_LEVEL', '').upper()
15
+ log_file = os.getenv('RQUOTE_LOG_FILE', '/tmp/rquote.log')
16
+
17
+ # 如果设置了有效的日志级别,则启用日志
18
+ if log_level in ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'):
19
+ # 将字符串级别转换为logging级别
20
+ level_map = {
21
+ 'DEBUG': logging.DEBUG,
22
+ 'INFO': logging.INFO,
23
+ 'WARNING': logging.WARNING,
24
+ 'ERROR': logging.ERROR,
25
+ 'CRITICAL': logging.CRITICAL,
26
+ }
27
+ logger.setLevel(level_map[log_level])
28
+
29
+ # 添加文件handler
30
+ file_handler = logging.FileHandler(log_file)
31
+ formatter = logging.Formatter('%(asctime)-15s:%(lineno)s %(message)s')
32
+ file_handler.setFormatter(formatter)
33
+ logger.addHandler(file_handler)
34
+
35
+ # 添加控制台handler
36
+ logger.addHandler(logging.StreamHandler())
37
+ else:
38
+ # 默认关闭日志:设置为CRITICAL级别,不添加handler
39
+ logger.setLevel(logging.CRITICAL)
40
+
41
+ return logger
42
+
43
+
44
+ logger = setup_logger()
45
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rquote
3
- Version: 0.4.2
3
+ Version: 0.4.4
4
4
  Summary: Mostly day quotes of cn/hk/us/fund/future markets, side with quote list fetch
5
5
  Requires-Python: >=3.9.0
6
6
  Description-Content-Type: text/markdown
@@ -18,7 +18,7 @@ Requires-Dist: duckdb>=0.9.0; extra == "persistent"
18
18
 
19
19
  ## 版本信息
20
20
 
21
- 当前版本:**0.4.2**
21
+ 当前版本:**0.4.4**
22
22
 
23
23
  ## 主要特性
24
24
 
@@ -346,6 +346,50 @@ os.environ['RQUOTE_HTTP_TIMEOUT'] = '20'
346
346
  config_from_env = config.Config.from_env()
347
347
  ```
348
348
 
349
+ ### 日志配置
350
+
351
+ **默认情况下,日志功能是关闭的。** 如果需要启用日志,可以通过环境变量手动开启:
352
+
353
+ #### 通过环境变量开启日志
354
+
355
+ ```bash
356
+ # 设置日志级别为 INFO(会同时输出到文件和控制台)
357
+ export RQUOTE_LOG_LEVEL=INFO
358
+
359
+ # 可选:自定义日志文件路径(默认为 /tmp/rquote.log)
360
+ export RQUOTE_LOG_FILE=/path/to/your/logfile.log
361
+
362
+ # 然后运行你的Python脚本
363
+ python your_script.py
364
+ ```
365
+
366
+ #### 支持的日志级别
367
+
368
+ - `DEBUG`: 详细的调试信息
369
+ - `INFO`: 一般信息(推荐)
370
+ - `WARNING`: 警告信息
371
+ - `ERROR`: 错误信息
372
+ - `CRITICAL`: 严重错误
373
+
374
+ #### 在Python代码中开启日志
375
+
376
+ ```python
377
+ import os
378
+
379
+ # 在导入 rquote 之前设置环境变量
380
+ os.environ['RQUOTE_LOG_LEVEL'] = 'INFO'
381
+ os.environ['RQUOTE_LOG_FILE'] = '/tmp/rquote.log' # 可选
382
+
383
+ from rquote import get_price
384
+
385
+ # 现在日志已启用
386
+ sid, name, df = get_price('sh000001')
387
+ ```
388
+
389
+ #### 关闭日志
390
+
391
+ 如果不设置 `RQUOTE_LOG_LEVEL` 环境变量,或者设置为空值,日志功能将保持关闭状态(默认行为)。
392
+
349
393
  ### 使用改进的HTTP客户端
350
394
 
351
395
  ```python
@@ -1,51 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- 股票信息相关API
4
- """
5
- import json
6
- from typing import List
7
- from ..utils import hget
8
- from ..exceptions import HTTPError
9
-
10
-
11
- def get_stock_concepts(i: str) -> List[str]:
12
- """
13
- 获取指定股票所属的概念板块
14
-
15
- Args:
16
- i: 股票代码
17
-
18
- Returns:
19
- 概念代码列表
20
- """
21
- i = {'6': 'sh', '0': 'sz', '3': 'sz'}.get(i[0], '') + i if i[0] in ['6', '0', '3'] else i
22
- url = f'https://proxy.finance.qq.com/ifzqgtimg/appstock/app/stockinfo/plateNew?code={i}&app=wzq&zdf=1'
23
- a = hget(url)
24
- if not a:
25
- raise HTTPError('Failed to fetch concepts from QQ Finance')
26
- data = json.loads(a.text)
27
- if data.get('code') != 0:
28
- raise HTTPError('API returned error: {}'.format(data.get('msg', 'Unknown error')))
29
- return data.get('data', {}).get('concept', [])
30
-
31
-
32
- def get_stock_industry(i: str) -> List[str]:
33
- """
34
- 获取指定股票所属的行业板块
35
-
36
- Args:
37
- i: 股票代码
38
-
39
- Returns:
40
- 行业代码列表
41
- """
42
- i = {'6': 'sh', '0': 'sz', '3': 'sz'}.get(i[0], '') + i if i[0] in ['6', '0', '3'] else i
43
- url = f'https://proxy.finance.qq.com/ifzqgtimg/appstock/app/stockinfo/plateNew?code={i}&app=wzq&zdf=1'
44
- a = hget(url)
45
- if not a:
46
- raise HTTPError('Failed to fetch industry from QQ Finance')
47
- data = json.loads(a.text)
48
- if data.get('code') != 0:
49
- raise HTTPError('API returned error: {}'.format(data.get('msg', 'Unknown error')))
50
- return data.get('data', {}).get('plate', [])
51
-
@@ -1,25 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- 日志工具
4
- """
5
- import logging
6
-
7
-
8
- def setup_logger():
9
- """设置日志记录器"""
10
- logger = logging.getLogger('rquote')
11
- if not logger.handlers:
12
- logger.setLevel(logging.INFO)
13
- file_handler = logging.FileHandler('/tmp/rquote.log')
14
-
15
- formatter = logging.Formatter('%(asctime)-15s:%(lineno)s %(message)s')
16
- file_handler.setFormatter(formatter)
17
-
18
- logger.addHandler(file_handler)
19
- logger.addHandler(logging.StreamHandler())
20
-
21
- return logger
22
-
23
-
24
- logger = setup_logger()
25
-
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes