aishare-txt 2025.11.6.13__py3-none-any.whl
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.
- AIShareTxt/__init__.py +63 -0
- AIShareTxt/ai/__init__.py +11 -0
- AIShareTxt/ai/client.py +313 -0
- AIShareTxt/ai/providers/__init__.py +8 -0
- AIShareTxt/core/__init__.py +17 -0
- AIShareTxt/core/analyzer.py +495 -0
- AIShareTxt/core/config.py +324 -0
- AIShareTxt/core/data_fetcher.py +593 -0
- AIShareTxt/core/report_generator.py +783 -0
- AIShareTxt/docs/AI_INTEGRATION.md +212 -0
- AIShareTxt/docs/README_/351/207/215/346/236/204/350/257/264/346/230/216.md +202 -0
- AIShareTxt/docs//351/207/215/346/236/204/345/256/214/346/210/220/346/200/273/347/273/223.md +148 -0
- AIShareTxt/examples/legacy_api.py +259 -0
- AIShareTxt/indicators/__init__.py +15 -0
- AIShareTxt/indicators/technical_indicators.py +507 -0
- AIShareTxt/tests/__init__.py +11 -0
- AIShareTxt/utils/__init__.py +17 -0
- AIShareTxt/utils/stock_list.py +305 -0
- AIShareTxt/utils/utils.py +578 -0
- aishare_txt-2025.11.6.13.dist-info/METADATA +475 -0
- aishare_txt-2025.11.6.13.dist-info/RECORD +25 -0
- aishare_txt-2025.11.6.13.dist-info/WHEEL +5 -0
- aishare_txt-2025.11.6.13.dist-info/entry_points.txt +2 -0
- aishare_txt-2025.11.6.13.dist-info/licenses/LICENSE +194 -0
- aishare_txt-2025.11.6.13.dist-info/top_level.txt +1 -0
AIShareTxt/__init__.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AIShareTxt - 股票技术指标分析工具包
|
|
3
|
+
|
|
4
|
+
一个功能强大的股票技术指标分析工具,支持多种技术指标计算、
|
|
5
|
+
AI集成分析和报告生成功能。
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "2025.11.06.13"
|
|
9
|
+
__author__ = "AIShareTxt Team"
|
|
10
|
+
|
|
11
|
+
# 导入核心类
|
|
12
|
+
from .core.analyzer import StockAnalyzer
|
|
13
|
+
from .core.data_fetcher import StockDataFetcher
|
|
14
|
+
from .core.report_generator import ReportGenerator
|
|
15
|
+
from .core.config import IndicatorConfig
|
|
16
|
+
|
|
17
|
+
# 导入技术指标
|
|
18
|
+
from .indicators.technical_indicators import TechnicalIndicators
|
|
19
|
+
|
|
20
|
+
# 导入AI客户端
|
|
21
|
+
from .ai.client import AIClient
|
|
22
|
+
|
|
23
|
+
# 导入工具
|
|
24
|
+
from .utils.utils import Logger
|
|
25
|
+
from .utils.stock_list import get_stock_list
|
|
26
|
+
|
|
27
|
+
# 定义公共API
|
|
28
|
+
__all__ = [
|
|
29
|
+
# 核心类
|
|
30
|
+
"StockAnalyzer",
|
|
31
|
+
"StockDataFetcher",
|
|
32
|
+
"ReportGenerator",
|
|
33
|
+
"IndicatorConfig",
|
|
34
|
+
|
|
35
|
+
# 技术指标
|
|
36
|
+
"TechnicalIndicators",
|
|
37
|
+
|
|
38
|
+
# AI客户端
|
|
39
|
+
"AIClient",
|
|
40
|
+
|
|
41
|
+
# 工具
|
|
42
|
+
"Logger",
|
|
43
|
+
"get_stock_list",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
# 便捷函数
|
|
47
|
+
def analyze_stock(symbol, period="1y", use_ai=False, ai_provider="deepseek"):
|
|
48
|
+
"""
|
|
49
|
+
便捷函数:分析股票技术指标
|
|
50
|
+
|
|
51
|
+
参数:
|
|
52
|
+
symbol: 股票代码
|
|
53
|
+
period: 数据周期,默认1年
|
|
54
|
+
use_ai: 是否使用AI分析
|
|
55
|
+
ai_provider: AI提供商,支持"deepseek"或"zhipu"
|
|
56
|
+
|
|
57
|
+
返回:
|
|
58
|
+
分析结果字典
|
|
59
|
+
"""
|
|
60
|
+
analyzer = StockAnalyzer()
|
|
61
|
+
return analyzer.analyze_stock(symbol)
|
|
62
|
+
|
|
63
|
+
|
AIShareTxt/ai/client.py
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
AI 客户端封装
|
|
5
|
+
支持多种AI提供商(DeepSeek、智谱AI)进行股票投资建议分析
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Optional, Union
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from openai import OpenAI # type: ignore[import-untyped]
|
|
14
|
+
HAS_OPENAI = True
|
|
15
|
+
except ImportError:
|
|
16
|
+
OpenAI = None # type: ignore[misc]
|
|
17
|
+
HAS_OPENAI = False
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
from zhipuai import ZhipuAI # type: ignore[import-untyped]
|
|
21
|
+
HAS_ZHIPUAI = True
|
|
22
|
+
except ImportError:
|
|
23
|
+
try:
|
|
24
|
+
# 尝试从 zai 包导入
|
|
25
|
+
from zai import ZhipuAiClient as ZhipuAI # type: ignore[import-untyped]
|
|
26
|
+
HAS_ZHIPUAI = True
|
|
27
|
+
except ImportError:
|
|
28
|
+
ZhipuAI = None # type: ignore[misc]
|
|
29
|
+
HAS_ZHIPUAI = False
|
|
30
|
+
|
|
31
|
+
from ..utils.utils import LoggerManager
|
|
32
|
+
|
|
33
|
+
logger = LoggerManager.get_logger('ai_client')
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class AIStockAnalyzer:
|
|
37
|
+
"""AI股票分析客户端"""
|
|
38
|
+
|
|
39
|
+
def __init__(self, api_key: Optional[str] = None, provider: Optional[str] = None):
|
|
40
|
+
"""
|
|
41
|
+
初始化AI客户端
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
api_key: AI API密钥(可选,默认从配置文件获取)
|
|
45
|
+
provider: AI提供商(可选,默认从配置文件获取),可选值: 'deepseek', 'zhipuai'
|
|
46
|
+
"""
|
|
47
|
+
try:
|
|
48
|
+
from ..core.config import IndicatorConfig as Config
|
|
49
|
+
config = Config()
|
|
50
|
+
|
|
51
|
+
# 确定使用的提供商
|
|
52
|
+
self.provider = provider or config.AI_CONFIG.get('default_provider', 'deepseek')
|
|
53
|
+
|
|
54
|
+
# 获取对应提供商的配置
|
|
55
|
+
provider_config = config.AI_CONFIG.get(self.provider, {})
|
|
56
|
+
|
|
57
|
+
# 优先使用传入的密钥,其次从配置文件获取
|
|
58
|
+
self.api_key = api_key or provider_config.get('api_key', '')
|
|
59
|
+
|
|
60
|
+
# 保存配置供后续使用
|
|
61
|
+
self.config = config
|
|
62
|
+
|
|
63
|
+
except Exception as e:
|
|
64
|
+
logger.error(f"配置加载失败: {e}")
|
|
65
|
+
self.provider = provider or 'deepseek'
|
|
66
|
+
self.api_key = api_key or os.getenv('DEEPSEEK_API_KEY', '')
|
|
67
|
+
self.config = None
|
|
68
|
+
|
|
69
|
+
self.client = None
|
|
70
|
+
|
|
71
|
+
# 根据提供商初始化对应的客户端
|
|
72
|
+
if self.provider == 'deepseek':
|
|
73
|
+
self._init_deepseek_client()
|
|
74
|
+
elif self.provider == 'zhipuai':
|
|
75
|
+
self._init_zhipuai_client()
|
|
76
|
+
else:
|
|
77
|
+
logger.error(f"不支持的AI提供商: {self.provider}")
|
|
78
|
+
|
|
79
|
+
def _init_deepseek_client(self):
|
|
80
|
+
"""初始化DeepSeek客户端"""
|
|
81
|
+
if not HAS_OPENAI:
|
|
82
|
+
logger.warning("未安装OpenAI客户端库,DeepSeek功能将不可用")
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
if not self.api_key:
|
|
86
|
+
logger.warning("未提供DeepSeek API密钥,请设置环境变量DEEPSEEK_API_KEY")
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
try:
|
|
90
|
+
base_url = "https://api.deepseek.com"
|
|
91
|
+
if self.config:
|
|
92
|
+
base_url = self.config.AI_CONFIG.get('deepseek', {}).get('base_url', base_url)
|
|
93
|
+
|
|
94
|
+
self.client = OpenAI( # type: ignore[misc]
|
|
95
|
+
api_key=self.api_key,
|
|
96
|
+
base_url=base_url
|
|
97
|
+
)
|
|
98
|
+
logger.info("DeepSeek客户端初始化成功")
|
|
99
|
+
except Exception as e:
|
|
100
|
+
logger.error(f"DeepSeek客户端初始化失败: {e}")
|
|
101
|
+
|
|
102
|
+
def _init_zhipuai_client(self):
|
|
103
|
+
"""初始化智谱AI客户端"""
|
|
104
|
+
if not HAS_ZHIPUAI:
|
|
105
|
+
logger.warning("未安装智谱AI客户端库,智谱AI功能将不可用")
|
|
106
|
+
return
|
|
107
|
+
|
|
108
|
+
if not self.api_key:
|
|
109
|
+
logger.warning("未提供智谱AI API密钥")
|
|
110
|
+
return
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
self.client = ZhipuAI(api_key=self.api_key) # type: ignore[misc]
|
|
114
|
+
logger.info("智谱AI客户端初始化成功")
|
|
115
|
+
except Exception as e:
|
|
116
|
+
logger.error(f"智谱AI客户端初始化失败: {e}")
|
|
117
|
+
|
|
118
|
+
def is_available(self) -> bool:
|
|
119
|
+
"""检查AI功能是否可用"""
|
|
120
|
+
if self.provider == 'deepseek':
|
|
121
|
+
return self.client is not None and HAS_OPENAI
|
|
122
|
+
elif self.provider == 'zhipuai':
|
|
123
|
+
return self.client is not None and HAS_ZHIPUAI
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
def analyze_investment_recommendation(self, technical_report: str, stock_code: str) -> int:
|
|
127
|
+
"""
|
|
128
|
+
基于技术分析报告生成投资建议
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
technical_report: 技术分析报告
|
|
132
|
+
stock_code: 股票代码
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
int: 投资建议 (1: 立即买入, -1: 不适合买入, 0: 观望等待)
|
|
136
|
+
"""
|
|
137
|
+
if not self.is_available():
|
|
138
|
+
logger.warning("AI功能不可用,返回默认观望建议")
|
|
139
|
+
return 0
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
from .config import Config
|
|
143
|
+
config = Config()
|
|
144
|
+
|
|
145
|
+
# 根据提供商选择调用不同的方法
|
|
146
|
+
if self.provider == 'deepseek':
|
|
147
|
+
return self._analyze_with_deepseek(technical_report, stock_code, config)
|
|
148
|
+
elif self.provider == 'zhipuai':
|
|
149
|
+
return self._analyze_with_zhipuai(technical_report, stock_code, config)
|
|
150
|
+
else:
|
|
151
|
+
logger.error(f"不支持的AI提供商: {self.provider}")
|
|
152
|
+
return 0
|
|
153
|
+
|
|
154
|
+
except Exception as e:
|
|
155
|
+
logger.error(f"AI分析失败: {e}")
|
|
156
|
+
return 0 # 出错时默认返回观望
|
|
157
|
+
|
|
158
|
+
def _analyze_with_deepseek(self, technical_report: str, stock_code: str, config) -> int:
|
|
159
|
+
"""使用DeepSeek进行分析"""
|
|
160
|
+
ai_config = config.AI_CONFIG['deepseek']
|
|
161
|
+
|
|
162
|
+
prompt = config.AI_CONFIG['recommendation']['prompt_template'].format(
|
|
163
|
+
stock_code=stock_code,
|
|
164
|
+
technical_report=technical_report
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
logger.info(f"发送DeepSeek请求,模型: {ai_config['model']}")
|
|
168
|
+
logger.info(f"系统消息: {config.AI_CONFIG['recommendation']['system_message']}")
|
|
169
|
+
logger.info(f"用户提示: {prompt[:200]}...") # 只显示前200个字符
|
|
170
|
+
|
|
171
|
+
response = self.client.chat.completions.create( # type: ignore[union-attr]
|
|
172
|
+
model=ai_config['model'],
|
|
173
|
+
messages=[
|
|
174
|
+
{"role": "system", "content": config.AI_CONFIG['recommendation']['system_message']},
|
|
175
|
+
{"role": "user", "content": prompt}
|
|
176
|
+
],
|
|
177
|
+
max_tokens=ai_config['max_tokens'],
|
|
178
|
+
temperature=ai_config['temperature'],
|
|
179
|
+
stream=False
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
logger.info(f"DeepSeek响应对象: {response}")
|
|
183
|
+
logger.info(f"DeepSeek响应choices: {response.choices}")
|
|
184
|
+
|
|
185
|
+
result_text = response.choices[0].message.content.strip() if response.choices[0].message.content else "" # type: ignore[union-attr]
|
|
186
|
+
logger.info(f"DeepSeek分析结果原始输出: '{result_text}'")
|
|
187
|
+
|
|
188
|
+
# 解析AI返回的结果
|
|
189
|
+
result = self._parse_ai_result(result_text)
|
|
190
|
+
logger.info(f"股票 {stock_code} DeepSeek投资建议: {result}")
|
|
191
|
+
|
|
192
|
+
return result
|
|
193
|
+
|
|
194
|
+
def _analyze_with_zhipuai(self, technical_report: str, stock_code: str, config) -> int:
|
|
195
|
+
"""使用智谱AI进行分析"""
|
|
196
|
+
ai_config = config.AI_CONFIG['zhipuai']
|
|
197
|
+
|
|
198
|
+
prompt = config.AI_CONFIG['recommendation']['prompt_template'].format(
|
|
199
|
+
stock_code=stock_code,
|
|
200
|
+
technical_report=technical_report
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
logger.info(f"发送智谱AI请求,模型: {ai_config['model']}")
|
|
204
|
+
logger.info(f"系统消息: {config.AI_CONFIG['recommendation']['system_message']}")
|
|
205
|
+
logger.info(f"用户提示: {prompt[:200]}...") # 只显示前200个字符
|
|
206
|
+
|
|
207
|
+
response = self.client.chat.completions.create( # type: ignore[union-attr]
|
|
208
|
+
model=ai_config['model'],
|
|
209
|
+
messages=[
|
|
210
|
+
{"role": "system", "content": config.AI_CONFIG['recommendation']['system_message']},
|
|
211
|
+
{"role": "user", "content": prompt}
|
|
212
|
+
],
|
|
213
|
+
max_tokens=ai_config['max_tokens'],
|
|
214
|
+
temperature=ai_config['temperature'],
|
|
215
|
+
thinking={
|
|
216
|
+
"type": "disabled", # 禁用深度思考模式
|
|
217
|
+
},
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
logger.info(f"智谱AI响应对象: {response}")
|
|
221
|
+
logger.info(f"智谱AI响应choices: {response.choices}")
|
|
222
|
+
|
|
223
|
+
result_text = response.choices[0].message.content.strip() if response.choices[0].message.content else "" # type: ignore[union-attr]
|
|
224
|
+
logger.info(f"智谱AI分析结果原始输出: '{result_text}'")
|
|
225
|
+
|
|
226
|
+
# 解析AI返回的结果
|
|
227
|
+
result = self._parse_ai_result(result_text)
|
|
228
|
+
logger.info(f"股票 {stock_code} 智谱AI投资建议: {result}")
|
|
229
|
+
|
|
230
|
+
return result
|
|
231
|
+
|
|
232
|
+
def _parse_ai_result(self, ai_response: str) -> int:
|
|
233
|
+
"""
|
|
234
|
+
解析AI返回的结果,确保符合规范
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
ai_response: AI的原始响应
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
int: 标准化的投资建议
|
|
241
|
+
"""
|
|
242
|
+
# 清理响应文本
|
|
243
|
+
clean_response = ai_response.strip().replace(" ", "").replace("\n", "")
|
|
244
|
+
|
|
245
|
+
# 尝试直接提取数字
|
|
246
|
+
if "1" in clean_response and "-1" not in clean_response:
|
|
247
|
+
return 1
|
|
248
|
+
elif "-1" in clean_response:
|
|
249
|
+
return -1
|
|
250
|
+
elif "0" in clean_response:
|
|
251
|
+
return 0
|
|
252
|
+
|
|
253
|
+
# 如果包含关键词,进行映射
|
|
254
|
+
buy_keywords = ["买入", "立即买入", "建议买入", "可以买入"]
|
|
255
|
+
avoid_keywords = ["不适合", "不建议", "风险", "避免", "卖出"]
|
|
256
|
+
wait_keywords = ["观望", "等待", "持有", "中性"]
|
|
257
|
+
|
|
258
|
+
for keyword in buy_keywords:
|
|
259
|
+
if keyword in clean_response:
|
|
260
|
+
return 1
|
|
261
|
+
|
|
262
|
+
for keyword in avoid_keywords:
|
|
263
|
+
if keyword in clean_response:
|
|
264
|
+
return -1
|
|
265
|
+
|
|
266
|
+
for keyword in wait_keywords:
|
|
267
|
+
if keyword in clean_response:
|
|
268
|
+
return 0
|
|
269
|
+
|
|
270
|
+
# 默认返回观望
|
|
271
|
+
logger.warning(f"无法解析AI响应: {ai_response},返回默认观望建议")
|
|
272
|
+
return 0
|
|
273
|
+
|
|
274
|
+
def get_recommendation_text(self, score: int) -> str:
|
|
275
|
+
"""
|
|
276
|
+
获取推荐结果的文本描述
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
score: 推荐分数
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
str: 文本描述
|
|
283
|
+
"""
|
|
284
|
+
score_map = {
|
|
285
|
+
1: "立即买入",
|
|
286
|
+
-1: "不适合买入",
|
|
287
|
+
0: "观望等待"
|
|
288
|
+
}
|
|
289
|
+
return score_map.get(score, "未知")
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
# 全局AI分析器实例
|
|
293
|
+
_ai_analyzer = None
|
|
294
|
+
|
|
295
|
+
def get_ai_analyzer(api_key: Optional[str] = None, provider: Optional[str] = None) -> AIStockAnalyzer:
|
|
296
|
+
"""
|
|
297
|
+
获取全局AI分析器实例
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
api_key: API密钥
|
|
301
|
+
provider: AI提供商('deepseek' 或 'zhipuai')
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
AIStockAnalyzer: AI分析器实例
|
|
305
|
+
"""
|
|
306
|
+
global _ai_analyzer
|
|
307
|
+
if _ai_analyzer is None or (api_key and _ai_analyzer.api_key != api_key) or (provider and _ai_analyzer.provider != provider):
|
|
308
|
+
_ai_analyzer = AIStockAnalyzer(api_key, provider)
|
|
309
|
+
return _ai_analyzer
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
# 向后兼容的别名
|
|
313
|
+
AIClient = AIStockAnalyzer
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AIShareTxt核心模块
|
|
3
|
+
|
|
4
|
+
包含股票分析器、数据获取器、报告生成器和配置管理等核心功能。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .analyzer import StockAnalyzer
|
|
8
|
+
from .data_fetcher import StockDataFetcher
|
|
9
|
+
from .report_generator import ReportGenerator
|
|
10
|
+
from .config import IndicatorConfig
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"StockAnalyzer",
|
|
14
|
+
"StockDataFetcher",
|
|
15
|
+
"ReportGenerator",
|
|
16
|
+
"IndicatorConfig",
|
|
17
|
+
]
|