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
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
重构后的股票分析器主模块
|
|
5
|
+
作为协调器,整合数据获取、指标计算和报告生成功能
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import warnings
|
|
9
|
+
from .data_fetcher import StockDataFetcher
|
|
10
|
+
from ..indicators.technical_indicators import TechnicalIndicators
|
|
11
|
+
from .report_generator import ReportGenerator
|
|
12
|
+
from ..utils.utils import Logger, LoggerManager, Utils, DataValidator, ErrorHandler
|
|
13
|
+
from .config import IndicatorConfig as Config
|
|
14
|
+
|
|
15
|
+
warnings.filterwarnings('ignore')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class StockAnalyzer:
|
|
19
|
+
"""重构后的股票分析器主类"""
|
|
20
|
+
|
|
21
|
+
def __init__(self):
|
|
22
|
+
"""初始化分析器组件"""
|
|
23
|
+
# 初始化日志系统
|
|
24
|
+
LoggerManager.setup_logging()
|
|
25
|
+
self.logger = LoggerManager.get_logger('stock_analyzer')
|
|
26
|
+
|
|
27
|
+
self.config = Config()
|
|
28
|
+
self.data_fetcher = StockDataFetcher()
|
|
29
|
+
self.indicators_calculator = TechnicalIndicators()
|
|
30
|
+
self.report_generator = ReportGenerator()
|
|
31
|
+
self.utils = Utils()
|
|
32
|
+
|
|
33
|
+
# 数据存储
|
|
34
|
+
self.stock_data = None
|
|
35
|
+
self.stock_code = None
|
|
36
|
+
self.stock_info = None
|
|
37
|
+
self.fund_flow_data = None
|
|
38
|
+
self.indicators = None
|
|
39
|
+
|
|
40
|
+
def analyze_stock(self, stock_code, enable_performance_monitor=False):
|
|
41
|
+
"""
|
|
42
|
+
分析指定股票的技术指标
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
stock_code (str): 股票代码
|
|
46
|
+
enable_performance_monitor (bool): 是否启用性能监控
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
str: 分析报告
|
|
50
|
+
"""
|
|
51
|
+
# 性能监控
|
|
52
|
+
monitor = None
|
|
53
|
+
if enable_performance_monitor:
|
|
54
|
+
monitor = PerformanceMonitor()
|
|
55
|
+
monitor.start()
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
self.logger.info(f"开始分析股票:{stock_code}")
|
|
59
|
+
|
|
60
|
+
# 验证股票代码
|
|
61
|
+
if not self.utils.validate_stock_code(stock_code):
|
|
62
|
+
error_msg = "错误:股票代码格式不正确,请使用6位数字格式(如:000001)"
|
|
63
|
+
self.logger.error(error_msg)
|
|
64
|
+
return error_msg
|
|
65
|
+
|
|
66
|
+
self.stock_code = stock_code
|
|
67
|
+
|
|
68
|
+
# 步骤1:获取股票基本信息
|
|
69
|
+
self.logger.info("步骤1/4:获取股票基本信息...")
|
|
70
|
+
self.stock_info = self.data_fetcher.get_stock_basic_info(stock_code)
|
|
71
|
+
if monitor:
|
|
72
|
+
monitor.checkpoint("获取基本信息")
|
|
73
|
+
|
|
74
|
+
# 步骤2:获取主力资金流数据
|
|
75
|
+
self.logger.info("步骤2/4:获取主力资金流数据...")
|
|
76
|
+
self.fund_flow_data = self.data_fetcher.get_fund_flow_data(stock_code)
|
|
77
|
+
if monitor:
|
|
78
|
+
monitor.checkpoint("获取资金流数据")
|
|
79
|
+
|
|
80
|
+
# 步骤3:获取股票价格数据
|
|
81
|
+
self.logger.info("步骤3/4:获取股票价格数据...")
|
|
82
|
+
self.stock_data = self.data_fetcher.fetch_stock_data(stock_code)
|
|
83
|
+
|
|
84
|
+
if self.stock_data is None:
|
|
85
|
+
return f"{self.config.ERROR_MESSAGES['no_data']}: {stock_code}"
|
|
86
|
+
|
|
87
|
+
# 验证数据质量
|
|
88
|
+
is_valid, error_msg = DataValidator.validate_price_data(self.stock_data)
|
|
89
|
+
if not is_valid:
|
|
90
|
+
return f"数据质量验证失败: {error_msg}"
|
|
91
|
+
|
|
92
|
+
# 检查数据长度
|
|
93
|
+
min_length = self.config.DATA_CONFIG.get('min_data_length', 250)
|
|
94
|
+
is_sufficient, length_msg = self.utils.check_data_quality(self.stock_data, min_length)
|
|
95
|
+
if not is_sufficient:
|
|
96
|
+
self.logger.warning(f"警告: {length_msg}")
|
|
97
|
+
|
|
98
|
+
if monitor:
|
|
99
|
+
monitor.checkpoint("获取价格数据")
|
|
100
|
+
|
|
101
|
+
# 步骤4:计算技术指标
|
|
102
|
+
self.logger.info("步骤4/4:计算技术指标...")
|
|
103
|
+
self.indicators = self.indicators_calculator.calculate_all_indicators(self.stock_data)
|
|
104
|
+
|
|
105
|
+
if self.indicators is None:
|
|
106
|
+
return f"{self.config.ERROR_MESSAGES['calculation_failed']}: 可能是数据不足"
|
|
107
|
+
|
|
108
|
+
# 验证指标数据
|
|
109
|
+
is_valid, error_msg = DataValidator.validate_indicators(self.indicators)
|
|
110
|
+
if not is_valid:
|
|
111
|
+
return f"指标验证失败: {error_msg}"
|
|
112
|
+
|
|
113
|
+
# 将资金流数据添加到指标中
|
|
114
|
+
if self.fund_flow_data:
|
|
115
|
+
self.indicators.update(self.fund_flow_data)
|
|
116
|
+
|
|
117
|
+
if monitor:
|
|
118
|
+
monitor.checkpoint("计算技术指标")
|
|
119
|
+
|
|
120
|
+
# 生成报告
|
|
121
|
+
self.logger.info("生成分析报告...")
|
|
122
|
+
report = self.report_generator.generate_report(
|
|
123
|
+
stock_code,
|
|
124
|
+
self.indicators,
|
|
125
|
+
self.stock_info
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
if monitor:
|
|
129
|
+
monitor.checkpoint("生成报告")
|
|
130
|
+
monitor.finish()
|
|
131
|
+
|
|
132
|
+
return report
|
|
133
|
+
|
|
134
|
+
except Exception as e:
|
|
135
|
+
error_context = f"分析股票 {stock_code}"
|
|
136
|
+
self.utils.log_error(e, error_context)
|
|
137
|
+
ErrorHandler.handle_api_error(e, "股票分析")
|
|
138
|
+
return f"分析过程中出错:{str(e)}"
|
|
139
|
+
|
|
140
|
+
def quick_analyze(self, stock_code):
|
|
141
|
+
"""
|
|
142
|
+
快速分析(不包含资金流数据,提高速度)
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
stock_code (str): 股票代码
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
str: 分析报告
|
|
149
|
+
"""
|
|
150
|
+
try:
|
|
151
|
+
self.logger.info(f"快速分析股票:{stock_code}")
|
|
152
|
+
|
|
153
|
+
# 验证股票代码
|
|
154
|
+
if not self.utils.validate_stock_code(stock_code):
|
|
155
|
+
error_msg = "错误:股票代码格式不正确"
|
|
156
|
+
self.logger.error(error_msg)
|
|
157
|
+
return error_msg
|
|
158
|
+
|
|
159
|
+
self.stock_code = stock_code
|
|
160
|
+
|
|
161
|
+
# 获取股票价格数据
|
|
162
|
+
self.stock_data = self.data_fetcher.fetch_stock_data(stock_code)
|
|
163
|
+
|
|
164
|
+
if self.stock_data is None:
|
|
165
|
+
return f"{self.config.ERROR_MESSAGES['no_data']}: {stock_code}"
|
|
166
|
+
|
|
167
|
+
# 计算技术指标
|
|
168
|
+
self.indicators = self.indicators_calculator.calculate_all_indicators(self.stock_data)
|
|
169
|
+
|
|
170
|
+
if self.indicators is None:
|
|
171
|
+
return f"{self.config.ERROR_MESSAGES['calculation_failed']}"
|
|
172
|
+
|
|
173
|
+
# 生成报告(不包含基本信息和资金流)
|
|
174
|
+
report = self.report_generator.generate_report(
|
|
175
|
+
stock_code,
|
|
176
|
+
self.indicators,
|
|
177
|
+
None # 不包含基本信息
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
return report
|
|
181
|
+
|
|
182
|
+
except Exception as e:
|
|
183
|
+
error_context = f"快速分析股票 {stock_code}"
|
|
184
|
+
self.utils.log_error(e, error_context)
|
|
185
|
+
return f"快速分析过程中出错:{str(e)}"
|
|
186
|
+
|
|
187
|
+
def get_current_indicators(self):
|
|
188
|
+
"""
|
|
189
|
+
获取当前计算的指标数据
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
dict: 指标数据字典
|
|
193
|
+
"""
|
|
194
|
+
return self.indicators
|
|
195
|
+
|
|
196
|
+
def get_current_stock_data(self):
|
|
197
|
+
"""
|
|
198
|
+
获取当前的股票数据
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
pd.DataFrame: 股票数据
|
|
202
|
+
"""
|
|
203
|
+
return self.stock_data
|
|
204
|
+
|
|
205
|
+
def get_current_stock_info(self):
|
|
206
|
+
"""
|
|
207
|
+
获取当前的股票基本信息
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
dict: 股票基本信息
|
|
211
|
+
"""
|
|
212
|
+
return self.stock_info
|
|
213
|
+
|
|
214
|
+
def export_indicators_to_dict(self):
|
|
215
|
+
"""
|
|
216
|
+
导出指标数据为字典格式
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
dict: 包含所有数据的字典
|
|
220
|
+
"""
|
|
221
|
+
if not self.indicators:
|
|
222
|
+
return None
|
|
223
|
+
|
|
224
|
+
# 为了确保JSON序列化安全,对所有数据进行清理
|
|
225
|
+
export_data = {
|
|
226
|
+
'stock_code': self.stock_code,
|
|
227
|
+
'analysis_time': self.utils.get_current_time(),
|
|
228
|
+
'stock_info': self._serialize_data(self.stock_info),
|
|
229
|
+
'indicators': self._serialize_data(self.indicators),
|
|
230
|
+
'fund_flow': self._serialize_data(self.fund_flow_data)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return export_data
|
|
234
|
+
|
|
235
|
+
def _serialize_data(self, data):
|
|
236
|
+
"""
|
|
237
|
+
将数据中的日期对象转换为字符串,确保JSON序列化安全
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
data: 需要序列化的数据
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
序列化后的数据
|
|
244
|
+
"""
|
|
245
|
+
if data is None:
|
|
246
|
+
return None
|
|
247
|
+
|
|
248
|
+
if isinstance(data, dict):
|
|
249
|
+
result = {}
|
|
250
|
+
for key, value in data.items():
|
|
251
|
+
result[key] = self._serialize_data(value)
|
|
252
|
+
return result
|
|
253
|
+
elif isinstance(data, (list, tuple)):
|
|
254
|
+
return [self._serialize_data(item) for item in data]
|
|
255
|
+
elif hasattr(data, 'strftime'): # 日期对象
|
|
256
|
+
return data.strftime('%Y-%m-%d')
|
|
257
|
+
elif hasattr(data, 'isoformat'): # datetime对象
|
|
258
|
+
return data.isoformat()
|
|
259
|
+
else:
|
|
260
|
+
return data
|
|
261
|
+
|
|
262
|
+
def validate_analysis_environment(self):
|
|
263
|
+
"""
|
|
264
|
+
验证分析环境
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
tuple: (是否通过验证, 错误消息列表)
|
|
268
|
+
"""
|
|
269
|
+
errors = []
|
|
270
|
+
|
|
271
|
+
try:
|
|
272
|
+
# 检查必要的包
|
|
273
|
+
import akshare as ak
|
|
274
|
+
import talib
|
|
275
|
+
import pandas as pd
|
|
276
|
+
import numpy as np
|
|
277
|
+
except ImportError as e:
|
|
278
|
+
errors.append(f"缺少必要的包: {str(e)}")
|
|
279
|
+
|
|
280
|
+
# 检查配置
|
|
281
|
+
if not hasattr(self.config, 'MA_PERIODS'):
|
|
282
|
+
errors.append("配置文件不完整")
|
|
283
|
+
|
|
284
|
+
# 检查组件初始化
|
|
285
|
+
if not self.data_fetcher:
|
|
286
|
+
errors.append("数据获取器初始化失败")
|
|
287
|
+
|
|
288
|
+
if not self.indicators_calculator:
|
|
289
|
+
errors.append("指标计算器初始化失败")
|
|
290
|
+
|
|
291
|
+
if not self.report_generator:
|
|
292
|
+
errors.append("报告生成器初始化失败")
|
|
293
|
+
|
|
294
|
+
return len(errors) == 0, errors
|
|
295
|
+
|
|
296
|
+
def get_supported_indicators(self):
|
|
297
|
+
"""
|
|
298
|
+
获取支持的指标列表
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
dict: 按类别组织的指标列表
|
|
302
|
+
"""
|
|
303
|
+
indicators_info = {
|
|
304
|
+
'移动平均线': {
|
|
305
|
+
'MA': f"周期: {self.config.MA_PERIODS['short'] + self.config.MA_PERIODS['medium'] + self.config.MA_PERIODS['long']}",
|
|
306
|
+
'EMA': f"周期: {self.config.EMA_PERIODS}",
|
|
307
|
+
'WMA': f"周期: {self.config.WMA_PERIODS}"
|
|
308
|
+
},
|
|
309
|
+
'均线衍生指标': {
|
|
310
|
+
'BIAS': f"乖离率,周期: {self.config.BIAS_PERIODS}",
|
|
311
|
+
'MACD': f"参数: {self.config.MACD_CONFIG}",
|
|
312
|
+
'Bollinger Bands': f"参数: {self.config.BOLLINGER_BANDS_CONFIG}"
|
|
313
|
+
},
|
|
314
|
+
'量价指标': {
|
|
315
|
+
'VWAP': f"成交量加权平均价,周期: {self.config.VWAP_PERIOD}",
|
|
316
|
+
'OBV': "能量潮指标"
|
|
317
|
+
},
|
|
318
|
+
'趋势强度': {
|
|
319
|
+
'ADX/DMI': f"趋势方向指标,周期: {self.config.ADX_PERIOD}"
|
|
320
|
+
},
|
|
321
|
+
'动量振荡': {
|
|
322
|
+
'RSI': f"相对强弱指数,周期: {self.config.RSI_PERIODS}",
|
|
323
|
+
'Stochastic': f"随机振荡器,参数: {self.config.STOCH_CONFIG}"
|
|
324
|
+
},
|
|
325
|
+
'波动率': {
|
|
326
|
+
'ATR': f"平均真实波幅,周期: {self.config.ATR_PERIOD}"
|
|
327
|
+
},
|
|
328
|
+
'成交量': {
|
|
329
|
+
'Volume Ratio': "量比指标",
|
|
330
|
+
'Volume Trend': "成交量趋势"
|
|
331
|
+
},
|
|
332
|
+
'资金流': {
|
|
333
|
+
'Fund Flow': "主力资金流向",
|
|
334
|
+
'5-day Fund Flow': "5日累计资金流"
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return indicators_info
|
|
339
|
+
|
|
340
|
+
def get_analysis_summary(self):
|
|
341
|
+
"""
|
|
342
|
+
获取分析摘要
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
dict: 分析摘要信息
|
|
346
|
+
"""
|
|
347
|
+
if not self.indicators:
|
|
348
|
+
return None
|
|
349
|
+
|
|
350
|
+
summary = {
|
|
351
|
+
'stock_code': self.stock_code,
|
|
352
|
+
'current_price': self.indicators.get('current_price', 0),
|
|
353
|
+
'analysis_date': self.indicators.get('date', ''),
|
|
354
|
+
'data_points': len(self.stock_data) if self.stock_data is not None else 0,
|
|
355
|
+
'indicators_count': len(self.indicators),
|
|
356
|
+
'has_fund_flow': '主力净流入额' in self.indicators,
|
|
357
|
+
'has_basic_info': self.stock_info is not None
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return summary
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def quick_test(stock_code):
|
|
364
|
+
"""快速测试单个股票的便捷函数"""
|
|
365
|
+
analyzer = StockAnalyzer()
|
|
366
|
+
logger = LoggerManager.get_logger('stock_analyzer')
|
|
367
|
+
|
|
368
|
+
print(f"快速测试股票:{stock_code}")
|
|
369
|
+
print(Utils.create_separator())
|
|
370
|
+
logger.info(f"开始快速测试股票:{stock_code}")
|
|
371
|
+
|
|
372
|
+
try:
|
|
373
|
+
# 验证分析环境
|
|
374
|
+
is_valid, errors = analyzer.validate_analysis_environment()
|
|
375
|
+
if not is_valid:
|
|
376
|
+
print("环境验证失败:")
|
|
377
|
+
logger.error("环境验证失败")
|
|
378
|
+
for error in errors:
|
|
379
|
+
print(f" - {error}")
|
|
380
|
+
logger.error(f"环境错误: {error}")
|
|
381
|
+
return False
|
|
382
|
+
|
|
383
|
+
# 执行分析
|
|
384
|
+
report = analyzer.analyze_stock(stock_code, enable_performance_monitor=True)
|
|
385
|
+
print("\n" + report)
|
|
386
|
+
|
|
387
|
+
# 显示分析摘要
|
|
388
|
+
summary = analyzer.get_analysis_summary()
|
|
389
|
+
if summary:
|
|
390
|
+
print(f"\n分析摘要:")
|
|
391
|
+
print(f" 数据点数: {summary['data_points']}")
|
|
392
|
+
print(f" 指标数量: {summary['indicators_count']}")
|
|
393
|
+
print(f" 包含资金流: {'是' if summary['has_fund_flow'] else '否'}")
|
|
394
|
+
print(f" 包含基本信息: {'是' if summary['has_basic_info'] else '否'}")
|
|
395
|
+
logger.info(f"快速测试完成 - 数据点数: {summary['data_points']}, 指标数量: {summary['indicators_count']}")
|
|
396
|
+
|
|
397
|
+
logger.info(f"快速测试股票 {stock_code} 成功完成")
|
|
398
|
+
return True
|
|
399
|
+
except Exception as e:
|
|
400
|
+
Utils.log_error(e, f"测试股票 {stock_code}")
|
|
401
|
+
return False
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def main():
|
|
405
|
+
"""主函数"""
|
|
406
|
+
analyzer = StockAnalyzer()
|
|
407
|
+
utils = Utils()
|
|
408
|
+
logger = LoggerManager.get_logger('stock_analyzer')
|
|
409
|
+
|
|
410
|
+
print("股票技术指标分析器 (重构版)")
|
|
411
|
+
print(utils.create_separator())
|
|
412
|
+
print("提示:可以在命令行直接运行 python stock_analyzer.py 000001 来快速测试")
|
|
413
|
+
logger.info("股票技术指标分析器启动")
|
|
414
|
+
|
|
415
|
+
# 验证分析环境
|
|
416
|
+
print("\n验证分析环境...")
|
|
417
|
+
logger.info("开始验证分析环境")
|
|
418
|
+
is_valid, errors = analyzer.validate_analysis_environment()
|
|
419
|
+
if not is_valid:
|
|
420
|
+
print("环境验证失败:")
|
|
421
|
+
logger.error("环境验证失败")
|
|
422
|
+
for error in errors:
|
|
423
|
+
print(f" ❌ {error}")
|
|
424
|
+
logger.error(f"环境错误: {error}")
|
|
425
|
+
return
|
|
426
|
+
else:
|
|
427
|
+
print("✅ 环境验证通过")
|
|
428
|
+
logger.info("环境验证通过")
|
|
429
|
+
|
|
430
|
+
# 检查命令行参数
|
|
431
|
+
stock_code = utils.parse_command_line_args()
|
|
432
|
+
if stock_code:
|
|
433
|
+
logger.info(f"使用命令行参数启动快速测试: {stock_code}")
|
|
434
|
+
quick_test(stock_code)
|
|
435
|
+
return
|
|
436
|
+
|
|
437
|
+
# 交互模式
|
|
438
|
+
while True:
|
|
439
|
+
try:
|
|
440
|
+
print(f"\n{utils.create_separator('-', 40)}")
|
|
441
|
+
stock_code = utils.get_user_input(
|
|
442
|
+
"请输入股票代码(如:000001,输入 'quit' 退出):",
|
|
443
|
+
['quit', 'exit', 'q']
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
if stock_code is None:
|
|
447
|
+
print("谢谢使用!")
|
|
448
|
+
logger.info("用户退出程序")
|
|
449
|
+
break
|
|
450
|
+
|
|
451
|
+
if not stock_code:
|
|
452
|
+
print("请输入有效的股票代码")
|
|
453
|
+
continue
|
|
454
|
+
|
|
455
|
+
logger.info(f"用户输入股票代码: {stock_code}")
|
|
456
|
+
|
|
457
|
+
# 询问分析模式
|
|
458
|
+
print("\n选择分析模式:")
|
|
459
|
+
print("1. 完整分析(包含基本信息和资金流)")
|
|
460
|
+
print("2. 快速分析(仅技术指标)")
|
|
461
|
+
|
|
462
|
+
mode_choice = utils.get_user_input("请选择模式 (1/2): ")
|
|
463
|
+
|
|
464
|
+
if mode_choice == '2':
|
|
465
|
+
print("\n执行快速分析...")
|
|
466
|
+
logger.info(f"开始快速分析股票: {stock_code}")
|
|
467
|
+
report = analyzer.quick_analyze(stock_code)
|
|
468
|
+
else:
|
|
469
|
+
print("\n执行完整分析...")
|
|
470
|
+
logger.info(f"开始完整分析股票: {stock_code}")
|
|
471
|
+
report = analyzer.analyze_stock(stock_code, enable_performance_monitor=True)
|
|
472
|
+
|
|
473
|
+
print("\n" + report)
|
|
474
|
+
|
|
475
|
+
# 显示分析摘要
|
|
476
|
+
summary = analyzer.get_analysis_summary()
|
|
477
|
+
if summary:
|
|
478
|
+
print(f"\n{utils.create_separator('-', 30)}")
|
|
479
|
+
print("分析摘要:")
|
|
480
|
+
print(f" 股票代码: {summary['stock_code']}")
|
|
481
|
+
print(f" 当前价格: {summary['current_price']:.2f}")
|
|
482
|
+
print(f" 数据点数: {summary['data_points']}")
|
|
483
|
+
print(f" 指标数量: {summary['indicators_count']}")
|
|
484
|
+
logger.info(f"分析完成 - {summary['stock_code']}: 数据点{summary['data_points']}, 指标{summary['indicators_count']}")
|
|
485
|
+
|
|
486
|
+
except KeyboardInterrupt:
|
|
487
|
+
if utils.handle_keyboard_interrupt():
|
|
488
|
+
logger.info("程序被用户中断")
|
|
489
|
+
break
|
|
490
|
+
except Exception as e:
|
|
491
|
+
utils.log_error(e, "主程序")
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
if __name__ == "__main__":
|
|
495
|
+
main()
|