diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ed99415 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,27 @@ +# 使用 Python 3.9 作为基础镜像 +FROM python:3.10-slim + +# 设置工作目录 +WORKDIR /app + +# 安装系统依赖 +RUN apt-get update && apt-get install -y \ + libgl1-mesa-glx \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# 复制项目文件 +COPY . /app/ + +# 安装 Python 依赖 +RUN pip install --no-cache-dir -r requirements.txt +RUN pip install akshare --upgrade -i https://pypi.org/simple + +# 设置环境变量 +ENV PYTHONPATH=/app + +# 暴露端口(如果需要) +EXPOSE 8888 + +# 启动命令 +CMD ["python", "web_server.py"] \ No newline at end of file diff --git a/gui.py b/gui.py deleted file mode 100644 index 57b16f1..0000000 --- a/gui.py +++ /dev/null @@ -1,218 +0,0 @@ -import sys -from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, - QHBoxLayout, QLineEdit, QPushButton, QTextBrowser, - QLabel, QTextEdit, QMessageBox, QProgressBar) -from PyQt6.QtCore import Qt, QThread, pyqtSignal -from PyQt6.QtGui import QFont -import markdown2 -from stock_analyzer import StockAnalyzer # 导入股票分析器 - -class AnalysisWorker(QThread): - """后台工作线程,用于执行分析任务""" - finished = pyqtSignal(dict) - error = pyqtSignal(str) - progress = pyqtSignal(int) - - def __init__(self, analyzer, stock_code): - super().__init__() - self.analyzer = analyzer - self.stock_code = stock_code - - def run(self): - try: - report = self.analyzer.analyze_stock(self.stock_code) - self.finished.emit(report) - except Exception as e: - self.error.emit(str(e)) - -class BatchAnalysisWorker(QThread): - """后台工作线程,用于执行批量分析任务""" - finished = pyqtSignal(list) - error = pyqtSignal(str) - progress = pyqtSignal(int) - - def __init__(self, analyzer, stock_list): - super().__init__() - self.analyzer = analyzer - self.stock_list = stock_list - - def run(self): - try: - results = [] - total = len(self.stock_list) - for i, stock_code in enumerate(self.stock_list): - report = self.analyzer.analyze_stock(stock_code) - results.append(report) - self.progress.emit(int((i + 1) / total * 100)) - self.finished.emit(results) - except Exception as e: - self.error.emit(str(e)) - -class StockAnalyzerGUI(QMainWindow): - def __init__(self): - super().__init__() - self.analyzer = StockAnalyzer() - self.initUI() - - def initUI(self): - self.setWindowTitle('股票分析系统') - self.setGeometry(100, 100, 1200, 800) - - # 创建中央部件和布局 - central_widget = QWidget() - self.setCentralWidget(central_widget) - layout = QVBoxLayout(central_widget) - - # 创建输入区域 - input_layout = QHBoxLayout() - - # 单只股票分析部分 - single_stock_layout = QVBoxLayout() - single_label = QLabel('单只股票分析:') - single_label.setFont(QFont('Arial', 12, QFont.Weight.Bold)) - self.single_stock_input = QLineEdit() - self.single_stock_input.setPlaceholderText('输入股票代码(如:600000)') - self.single_stock_input.setFont(QFont('Arial', 10)) - self.analyze_btn = QPushButton('分析') - self.analyze_btn.setFont(QFont('Arial', 10, QFont.Weight.Bold)) - self.analyze_btn.clicked.connect(self.analyze_single_stock) - single_stock_layout.addWidget(single_label) - single_stock_layout.addWidget(self.single_stock_input) - single_stock_layout.addWidget(self.analyze_btn) - - # 批量分析部分 - batch_stock_layout = QVBoxLayout() - batch_label = QLabel('批量股票分析:') - batch_label.setFont(QFont('Arial', 12, QFont.Weight.Bold)) - self.batch_stock_input = QTextEdit() - self.batch_stock_input.setPlaceholderText('输入多个股票代码,每行一个') - self.batch_stock_input.setFont(QFont('Arial', 10)) - self.batch_stock_input.setMaximumHeight(100) - self.batch_analyze_btn = QPushButton('批量分析') - self.batch_analyze_btn.setFont(QFont('Arial', 10, QFont.Weight.Bold)) - self.batch_analyze_btn.clicked.connect(self.analyze_multiple_stocks) - batch_stock_layout.addWidget(batch_label) - batch_stock_layout.addWidget(self.batch_stock_input) - batch_stock_layout.addWidget(self.batch_analyze_btn) - - input_layout.addLayout(single_stock_layout) - input_layout.addLayout(batch_stock_layout) - - # 添加进度条 - self.progress_bar = QProgressBar() - self.progress_bar.setVisible(False) - - # 添加结果显示区域 - self.result_browser = QTextBrowser() - self.result_browser.setOpenExternalLinks(True) - self.result_browser.setFont(QFont('Arial', 10)) - - layout.addLayout(input_layout) - layout.addWidget(self.progress_bar) - layout.addWidget(self.result_browser) - - def format_report(self, report, is_single=True): - """将分析报告格式化为Markdown格式""" - md = f"""# 股票分析报告 - {report['stock_code']} - -## 基本信息 -- 分析日期:{report['analysis_date']} -- 当前价格:{report['price']:.2f} -- 价格变动:{report['price_change']:.2f}% - -## 技术指标 -- 均线趋势:{report['ma_trend']} -- RSI指标:{report['rsi']:.2f} -- MACD信号:{report['macd_signal']} -- 成交量状态:{report['volume_status']} - -## 评分与建议 -- 综合评分:{report['score']}分 -- 投资建议:{report['recommendation']} - -## AI分析 -{report['ai_analysis']} - ---- -""" - return md - - def analyze_single_stock(self): - """分析单只股票""" - stock_code = self.single_stock_input.text().strip() - if not stock_code: - QMessageBox.warning(self, '警告', '请输入股票代码') - return - - self.analyze_btn.setEnabled(False) - self.progress_bar.setVisible(True) - self.progress_bar.setValue(0) - - # 创建工作线程 - self.worker = AnalysisWorker(self.analyzer, stock_code) - self.worker.finished.connect(self.handle_single_analysis_result) - self.worker.error.connect(self.handle_analysis_error) - self.worker.progress.connect(self.progress_bar.setValue) - self.worker.start() - - def handle_single_analysis_result(self, report): - """处理单只股票分析结果""" - markdown_text = self.format_report(report) - html_content = markdown2.markdown(markdown_text) - self.result_browser.setHtml(html_content) - self.analyze_btn.setEnabled(True) - self.progress_bar.setVisible(False) - - def analyze_multiple_stocks(self): - """批量分析股票""" - text = self.batch_stock_input.toPlainText().strip() - if not text: - QMessageBox.warning(self, '警告', '请输入股票代码') - return - - stock_list = [code.strip() for code in text.split('\n') if code.strip()] - - self.batch_analyze_btn.setEnabled(False) - self.progress_bar.setVisible(True) - self.progress_bar.setValue(0) - - # 创建工作线程 - self.batch_worker = BatchAnalysisWorker(self.analyzer, stock_list) - self.batch_worker.finished.connect(self.handle_batch_analysis_result) - self.batch_worker.error.connect(self.handle_analysis_error) - self.batch_worker.progress.connect(self.progress_bar.setValue) - self.batch_worker.start() - - def handle_batch_analysis_result(self, recommendations): - """处理批量分析结果""" - # 生成markdown格式的报告 - markdown_text = "# 批量股票分析报告\n\n" - for rec in recommendations: - markdown_text += self.format_report(rec, False) - - html_content = markdown2.markdown(markdown_text) - self.result_browser.setHtml(html_content) - self.batch_analyze_btn.setEnabled(True) - self.progress_bar.setVisible(False) - - def handle_analysis_error(self, error_message): - """处理分析错误""" - QMessageBox.critical(self, '错误', f'分析过程中出现错误:{error_message}') - self.analyze_btn.setEnabled(True) - self.batch_analyze_btn.setEnabled(True) - self.progress_bar.setVisible(False) - -def main(): - app = QApplication(sys.argv) - - # 设置应用程序样式 - app.setStyle('Fusion') - - # 创建并显示主窗口 - window = StockAnalyzerGUI() - window.show() - - sys.exit(app.exec()) - -if __name__ == '__main__': - main() diff --git a/gui2.py b/gui2.py deleted file mode 100644 index 4124871..0000000 --- a/gui2.py +++ /dev/null @@ -1,497 +0,0 @@ -import sys -from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, - QHBoxLayout, QLineEdit, QPushButton, QTextBrowser, - QLabel, QTextEdit, QMessageBox, QProgressBar, - QFrame, QSizePolicy) -from PyQt6.QtCore import Qt, QThread, pyqtSignal -from PyQt6.QtGui import QFont, QPalette, QColor -import markdown2 -from stock_analyzer import StockAnalyzer - -class ModernFrame(QFrame): - """现代化的面板组件""" - def __init__(self, parent=None): - super().__init__(parent) - self.setFrameStyle(QFrame.Shape.StyledPanel | QFrame.Shadow.Raised) - self.setStyleSheet(""" - ModernFrame { - background-color: #ffffff; - border-radius: 10px; - border: 1px solid #e0e0e0; - } - """) - -class ModernButton(QPushButton): - """现代化的按钮组件""" - def __init__(self, text, parent=None, primary=True): - super().__init__(text, parent) - self.setMinimumHeight(40) - if primary: - self.setStyleSheet(""" - QPushButton { - background-color: #1a73e8; - color: white; - border: none; - border-radius: 5px; - padding: 8px 16px; - font-weight: bold; - } - QPushButton:hover { - background-color: #1557b0; - } - QPushButton:pressed { - background-color: #0d47a1; - } - QPushButton:disabled { - background-color: #cccccc; - } - """) - else: - self.setStyleSheet(""" - QPushButton { - background-color: #f8f9fa; - color: #1a73e8; - border: 1px solid #dadce0; - border-radius: 5px; - padding: 8px 16px; - font-weight: bold; - } - QPushButton:hover { - background-color: #f1f3f4; - border-color: #d2e3fc; - } - QPushButton:pressed { - background-color: #e8eaed; - } - QPushButton:disabled { - color: #5f6368; - border-color: #e0e0e0; - } - """) - -class ModernLineEdit(QLineEdit): - """现代化的输入框组件""" - def __init__(self, parent=None): - super().__init__(parent) - self.setMinimumHeight(40) - self.setStyleSheet(""" - QLineEdit { - border: 2px solid #e0e0e0; - border-radius: 5px; - padding: 8px 12px; - background-color: white; - selection-background-color: #cce0ff; - } - QLineEdit:focus { - border-color: #1a73e8; - } - QLineEdit:hover { - border-color: #999999; - } - """) - -class ModernTextEdit(QTextEdit): - """现代化的多行文本输入框组件""" - def __init__(self, parent=None): - super().__init__(parent) - self.setStyleSheet(""" - QTextEdit { - border: 2px solid #e0e0e0; - border-radius: 5px; - padding: 8px; - background-color: white; - selection-background-color: #cce0ff; - } - QTextEdit:focus { - border-color: #1a73e8; - } - QTextEdit:hover { - border-color: #999999; - } - """) - -class ModernProgressBar(QProgressBar): - """现代化的进度条组件""" - def __init__(self, parent=None): - super().__init__(parent) - self.setStyleSheet(""" - QProgressBar { - border: none; - border-radius: 3px; - background-color: #f0f0f0; - height: 6px; - text-align: center; - } - QProgressBar::chunk { - background-color: #1a73e8; - border-radius: 3px; - } - """) - self.setTextVisible(False) - -class AnalysisWorker(QThread): - """后台工作线程,用于执行分析任务""" - finished = pyqtSignal(dict) - error = pyqtSignal(str) - progress = pyqtSignal(int) - - def __init__(self, analyzer, stock_code): - super().__init__() - self.analyzer = analyzer - self.stock_code = stock_code - - def run(self): - try: - report = self.analyzer.analyze_stock(self.stock_code) - self.finished.emit(report) - except Exception as e: - self.error.emit(str(e)) - -class BatchAnalysisWorker(QThread): - """后台工作线程,用于执行批量分析任务""" - finished = pyqtSignal(list) - error = pyqtSignal(str) - progress = pyqtSignal(int) - - def __init__(self, analyzer, stock_list): - super().__init__() - self.analyzer = analyzer - self.stock_list = stock_list - - def run(self): - try: - results = [] - total = len(self.stock_list) - for i, stock_code in enumerate(self.stock_list): - report = self.analyzer.analyze_stock(stock_code) - results.append(report) - self.progress.emit(int((i + 1) / total * 100)) - self.finished.emit(results) - except Exception as e: - self.error.emit(str(e)) - -class ModernStockAnalyzerGUI(QMainWindow): - def __init__(self): - super().__init__() - self.analyzer = StockAnalyzer() - self.init_ui() - self.adjust_size_and_position() - - def adjust_size_and_position(self): - """调整窗口大小和位置以适应不同分辨率""" - screen = QApplication.primaryScreen() - if screen: - geometry = screen.availableGeometry() - # 设置窗口大小为屏幕的75% - width = int(geometry.width() * 0.75) - height = int(geometry.height() * 0.75) - self.resize(width, height) - - # 居中显示 - center = geometry.center() - frame = self.frameGeometry() - frame.moveCenter(center) - self.move(frame.topLeft()) - - def init_ui(self): - self.setWindowTitle('现代股票分析系统') - self.setStyleSheet(""" - QMainWindow { - background-color: #f8f9fa; - } - """) - - # 创建中央部件和主布局 - central_widget = QWidget() - self.setCentralWidget(central_widget) - main_layout = QVBoxLayout(central_widget) - main_layout.setSpacing(20) - main_layout.setContentsMargins(20, 20, 20, 20) - - # 创建标题 - title_label = QLabel('股票分析系统') - title_label.setStyleSheet(""" - QLabel { - color: #202124; - font-size: 24px; - font-weight: bold; - margin-bottom: 20px; - } - """) - main_layout.addWidget(title_label, alignment=Qt.AlignmentFlag.AlignTop) - - # 创建输入区域容器 - input_container = ModernFrame() - input_layout = QHBoxLayout(input_container) - input_layout.setSpacing(20) - input_layout.setContentsMargins(20, 20, 20, 20) - - # 单只股票分析部分 - single_stock_frame = self.create_single_stock_section() - input_layout.addWidget(single_stock_frame) - - # 分隔线 - separator = QFrame() - separator.setFrameShape(QFrame.Shape.VLine) - separator.setStyleSheet("background-color: #e0e0e0;") - input_layout.addWidget(separator) - - # 批量分析部分 - batch_stock_frame = self.create_batch_stock_section() - input_layout.addWidget(batch_stock_frame) - - main_layout.addWidget(input_container) - - # 进度条 - self.progress_bar = ModernProgressBar() - self.progress_bar.setVisible(False) - main_layout.addWidget(self.progress_bar) - - # 结果显示区域 - result_frame = ModernFrame() - result_layout = QVBoxLayout(result_frame) - result_layout.setContentsMargins(15, 15, 15, 15) - - result_label = QLabel('分析结果') - result_label.setStyleSheet(""" - QLabel { - color: #202124; - font-size: 18px; - font-weight: bold; - } - """) - result_layout.addWidget(result_label) - - self.result_browser = QTextBrowser() - self.result_browser.setOpenExternalLinks(True) - self.result_browser.setStyleSheet(""" - QTextBrowser { - border: none; - background-color: white; - font-size: 14px; - line-height: 1.5; - } - """) - result_layout.addWidget(self.result_browser) - - main_layout.addWidget(result_frame) - - def create_single_stock_section(self): - """创建单只股票分析部分""" - frame = QFrame() - layout = QVBoxLayout(frame) - layout.setSpacing(15) - - label = QLabel('单只股票分析') - label.setStyleSheet(""" - QLabel { - color: #202124; - font-size: 16px; - font-weight: bold; - } - """) - layout.addWidget(label) - - self.single_stock_input = ModernLineEdit() - self.single_stock_input.setPlaceholderText('输入股票代码(如:600000)') - layout.addWidget(self.single_stock_input) - - self.analyze_btn = ModernButton('分析') - self.analyze_btn.clicked.connect(self.analyze_single_stock) - layout.addWidget(self.analyze_btn) - - layout.addStretch() - return frame - - def create_batch_stock_section(self): - """创建批量分析部分""" - frame = QFrame() - layout = QVBoxLayout(frame) - layout.setSpacing(15) - - label = QLabel('批量股票分析') - label.setStyleSheet(""" - QLabel { - color: #202124; - font-size: 16px; - font-weight: bold; - } - """) - layout.addWidget(label) - - self.batch_stock_input = ModernTextEdit() - self.batch_stock_input.setPlaceholderText('输入多个股票代码,每行一个') - self.batch_stock_input.setMinimumHeight(100) - layout.addWidget(self.batch_stock_input) - - self.batch_analyze_btn = ModernButton('批量分析') - self.batch_analyze_btn.clicked.connect(self.analyze_multiple_stocks) - layout.addWidget(self.batch_analyze_btn) - - layout.addStretch() - return frame - - def format_report(self, report, is_single=True): - """将分析报告格式化为现代化的Markdown格式""" - md = f"""# 股票分析报告 - {report['stock_code']} - -## 基本信息 -- **分析日期:** {report['analysis_date']} -- **当前价格:** ¥{report['price']:.2f} -- **价格变动:** {report['price_change']:.2f}% - -## 技术指标 -- **均线趋势:** {report['ma_trend']} -- **RSI指标:** {report['rsi']:.2f} -- **MACD信号:** {report['macd_signal']} -- **成交量状态:** {report['volume_status']} - -## 评分与建议 -- **综合评分:** {report['score']}分 -- **投资建议:** {report['recommendation']} - -## AI分析 -{report['ai_analysis']} - ---- -""" - return md - - def analyze_single_stock(self): - """分析单只股票""" - stock_code = self.single_stock_input.text().strip() - if not stock_code: - self.show_warning('请输入股票代码') - return - - self.analyze_btn.setEnabled(False) - self.progress_bar.setVisible(True) - self.progress_bar.setValue(0) - - self.worker = AnalysisWorker(self.analyzer, stock_code) - self.worker.finished.connect(self.handle_single_analysis_result) - self.worker.error.connect(self.handle_analysis_error) - self.worker.progress.connect(self.progress_bar.setValue) - self.worker.start() - - def analyze_multiple_stocks(self): - """批量分析股票""" - text = self.batch_stock_input.toPlainText().strip() - if not text: - self.show_warning('请输入股票代码') - return - - stock_list = [code.strip() for code in text.split('\n') if code.strip()] - - self.batch_analyze_btn.setEnabled(False) - self.progress_bar.setVisible(True) - self.progress_bar.setValue(0) - - self.batch_worker = BatchAnalysisWorker(self.analyzer, stock_list) - self.batch_worker.finished.connect(self.handle_batch_analysis_result) - self.batch_worker.error.connect(self.handle_analysis_error) - self.batch_worker.progress.connect(self.progress_bar.setValue) - self.batch_worker.start() - - def handle_single_analysis_result(self, report): - """处理单只股票分析结果""" - markdown_text = self.format_report(report) - html_content = markdown2.markdown(markdown_text, extras=['tables', 'fenced-code-blocks']) - self.result_browser.setHtml(html_content) - self.analyze_btn.setEnabled(True) - self.progress_bar.setVisible(False) - - def handle_batch_analysis_result(self, recommendations): - """处理批量分析结果""" - markdown_text = "# 批量股票分析报告\n\n" - for rec in recommendations: - markdown_text += self.format_report(rec, False) - - html_content = markdown2.markdown(markdown_text, extras=['tables', 'fenced-code-blocks']) - self.result_browser.setHtml(html_content) - self.batch_analyze_btn.setEnabled(True) - self.progress_bar.setVisible(False) - - def handle_analysis_error(self, error_message): - """处理分析错误""" - self.show_error(f'分析过程中出现错误:{error_message}') - self.analyze_btn.setEnabled(True) - self.batch_analyze_btn.setEnabled(True) - self.progress_bar.setVisible(False) - - def show_warning(self, message): - """显示警告对话框""" - warning = QMessageBox(self) - warning.setIcon(QMessageBox.Icon.Warning) - warning.setWindowTitle('警告') - warning.setText(message) - warning.setStandardButtons(QMessageBox.StandardButton.Ok) - warning.setStyleSheet(""" - QMessageBox { - background-color: white; - } - QMessageBox QLabel { - color: #202124; - min-width: 200px; - } - QPushButton { - background-color: #1a73e8; - color: white; - border: none; - border-radius: 4px; - padding: 8px 16px; - min-width: 80px; - } - QPushButton:hover { - background-color: #1557b0; - } - QPushButton:pressed { - background-color: #0d47a1; - } - """) - warning.exec() - - def show_error(self, message): - """显示错误对话框""" - error = QMessageBox(self) - error.setIcon(QMessageBox.Icon.Critical) - error.setWindowTitle('错误') - error.setText(message) - error.setStandardButtons(QMessageBox.StandardButton.Ok) - error.setStyleSheet(""" - QMessageBox { - background-color: white; - } - QMessageBox QLabel { - color: #202124; - min-width: 200px; - } - QPushButton { - background-color: #1a73e8; - color: white; - border: none; - border-radius: 4px; - padding: 8px 16px; - min-width: 80px; - } - QPushButton:hover { - background-color: #1557b0; - } - QPushButton:pressed { - background-color: #0d47a1; - } - """) - error.exec() - -def main(): - app = QApplication(sys.argv) - app.setStyle('Fusion') - - # 创建并显示主窗口 - window = ModernStockAnalyzerGUI() - window.show() - - sys.exit(app.exec()) - -if __name__ == '__main__': - main() diff --git a/requirements.txt b/requirements.txt index 2f7f9d7..a79b0b4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # 基础科学计算和数据处理库 -numpy==2.0.0 +numpy==2.1.2 pandas==2.2.2 scipy==1.15.1 @@ -7,13 +7,11 @@ scipy==1.15.1 akshare==1.15.87 tqdm==4.67.1 -# GUI库 -PyQt6==6.8.1 -markdown2==2.5.3 # 网络和API请求 requests==2.32.3 python-dotenv==1.0.1 +flask==3.1.0 # 日志和系统工具 loguru==0.7.2 diff --git a/stock_analyzer.py b/stock_analyzer.py index db8dac1..0b083e1 100644 --- a/stock_analyzer.py +++ b/stock_analyzer.py @@ -18,7 +18,7 @@ class StockAnalyzer: load_dotenv() # 设置 Gemini API - self.gemini_api_url = "https://api.xxx.xxx" + self.gemini_api_url = os.getenv('GEMINI_API_URL') self.gemini_api_key = os.getenv('GEMINI_API_KEY') # 配置参数 @@ -30,8 +30,15 @@ class StockAnalyzer: 'volume_ma_period': 20, 'atr_period': 14 } + + # 添加市场类型枚举 + self.MARKET_TYPES = { + 'A': 'A股', + 'HK': '港股', + 'CRYPTO': '加密货币' + } - def get_stock_data(self, stock_code, start_date=None, end_date=None): + def get_stock_data(self, stock_code, market_type='A', start_date=None, end_date=None, ): """获取股票数据""" import akshare as ak @@ -41,11 +48,33 @@ class StockAnalyzer: end_date = datetime.now().strftime('%Y%m%d') try: - # 使用 akshare 获取股票数据 - df = ak.stock_zh_a_hist(symbol=stock_code, - start_date=start_date, - end_date=end_date, - adjust="qfq") + # 根据市场类型获取数据 + if market_type == 'A': + df = ak.stock_zh_a_hist( + symbol=stock_code, + start_date=start_date, + end_date=end_date, + adjust="qfq" + ) + # A股数据列名映射 + elif market_type == 'HK': + df = ak.stock_hk_daily( + symbol=stock_code, + adjust="qfq" + ) + elif market_type == 'US': + df = ak.stock_us_hist( + symbol=stock_code, + start_date=start_date, + end_date=end_date, + adjust="qfq" + ) + elif market_type == 'CRYPTO': + df = ak.crypto_js_spot( + symbol=stock_code + ) + else: + raise ValueError(f"不支持的市场类型: {market_type}") # 重命名列名以匹配分析需求 df = df.rename(columns={ @@ -225,7 +254,7 @@ class StockAnalyzer: } data = { - "model": "gemini-1.5-flash", + "model": os.getenv('GEMINI_API_MODEL'), "messages": [{"role": "user", "content": prompt}] } @@ -233,9 +262,12 @@ class StockAnalyzer: f"{self.gemini_api_url}/v1/chat/completions", headers=headers, json=data, - timeout=10 + timeout=30 ) - + print(headers) + print(data) + print(response.json()) + if response.status_code == 200: return response.json()['choices'][0]['message']['content'] else: @@ -258,11 +290,11 @@ class StockAnalyzer: else: return '强烈建议卖出' - def analyze_stock(self, stock_code): + def analyze_stock(self, stock_code, market_type='A'): """分析单个股票""" try: # 获取股票数据 - df = self.get_stock_data(stock_code) + df = self.get_stock_data(stock_code, market_type) # 计算技术指标 df = self.calculate_indicators(df) @@ -295,13 +327,13 @@ class StockAnalyzer: self.logger.error(f"分析股票时出错: {str(e)}") raise - def scan_market(self, stock_list, min_score=60): + def scan_market(self, stock_list, min_score=60, market_type='A'): """扫描市场,寻找符合条件的股票""" recommendations = [] for stock_code in stock_list: try: - report = self.analyze_stock(stock_code) + report = self.analyze_stock(stock_code, market_type) if report['score'] >= min_score: recommendations.append(report) except Exception as e: diff --git a/templates/index.html b/templates/index.html index 6bd1b55..cf641f1 100644 --- a/templates/index.html +++ b/templates/index.html @@ -10,130 +10,206 @@