diff --git a/qihuo_analyzer/modules/__pycache__/deepseek_agent.cpython-311.pyc b/qihuo_analyzer/modules/__pycache__/deepseek_agent.cpython-311.pyc index fe29d00..ceddb98 100644 Binary files a/qihuo_analyzer/modules/__pycache__/deepseek_agent.cpython-311.pyc and b/qihuo_analyzer/modules/__pycache__/deepseek_agent.cpython-311.pyc differ diff --git a/qihuo_analyzer/modules/deepseek_agent.py b/qihuo_analyzer/modules/deepseek_agent.py index 5781061..6231d3f 100644 --- a/qihuo_analyzer/modules/deepseek_agent.py +++ b/qihuo_analyzer/modules/deepseek_agent.py @@ -1,6 +1,7 @@ # AI 研判模块 import json import requests +import datetime from typing import Dict, Optional, List from qihuo_analyzer.utils.config_manager import config_manager from qihuo_analyzer.core.models import AnalysisResult @@ -51,10 +52,66 @@ class DeepseekAgent: self.api_key = self.current_config['api_key'] self.api_url = self.current_config['api_url'] self.headers = self.current_config['headers'] + + # 初始化缓存字典 + # 缓存结构: {"date_symbol_model": {"timestamp": "2023-07-01 12:00:00", "data": {...}}} + self.cache = {} + + def _get_cache_key(self, market_data, model_name): + """获取缓存键 + + Args: + market_data: 市场数据,包含symbol + model_name: 模型名称 + + Returns: + str: 缓存键,格式为 "日期_品种_模型" + """ + # 获取当前日期(交易日) + today = datetime.datetime.now().strftime('%Y-%m-%d') + # 获取品种代码 + symbol = market_data.get('symbol', 'unknown') + # 构建缓存键 + cache_key = f"{today}_{symbol}_{model_name}" + return cache_key + + def _get_from_cache(self, cache_key): + """从缓存中获取数据 + + Args: + cache_key: 缓存键 + + Returns: + Dict: 缓存的数据,如果不存在返回None + """ + if cache_key in self.cache: + return self.cache[cache_key]['data'] + return None + + def _set_to_cache(self, cache_key, data): + """将数据设置到缓存中 + + Args: + cache_key: 缓存键 + data: 要缓存的数据 + """ + self.cache[cache_key] = { + 'timestamp': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), + 'data': data + } def analyze_market(self, market_data: Dict, technical_indicators: Dict, trend_analysis: Dict, risk_metrics: Dict) -> Dict: """分析市场""" + # 生成缓存键 + cache_key = self._get_cache_key(market_data, self.model_name) + + # 检查缓存 + cached_data = self._get_from_cache(cache_key) + if cached_data: + print(f"[DEBUG] 从缓存中获取分析数据: {cache_key}") + return cached_data + # 构建提示词 prompt = self._build_analysis_prompt(market_data, technical_indicators, trend_analysis, risk_metrics) @@ -64,10 +121,24 @@ class DeepseekAgent: # 解析结果 analysis_result = self._parse_analysis_result(response) + # 缓存结果 + self._set_to_cache(cache_key, analysis_result) + print(f"[DEBUG] 缓存分析数据: {cache_key}") + return analysis_result - def generate_trade_recommendation(self, analysis_result: Dict) -> Dict: + def generate_trade_recommendation(self, analysis_result: Dict, market_data: Optional[Dict] = None) -> Dict: """生成交易建议""" + # 生成缓存键 + if market_data: + cache_key = self._get_cache_key(market_data, f"{self.model_name}_recommendation") + + # 检查缓存 + cached_data = self._get_from_cache(cache_key) + if cached_data: + print(f"[DEBUG] 从缓存中获取交易建议: {cache_key}") + return cached_data + # 构建提示词 prompt = self._build_recommendation_prompt(analysis_result) @@ -77,6 +148,11 @@ class DeepseekAgent: # 解析结果 recommendation = self._parse_recommendation_result(response) + # 缓存结果 + if market_data: + self._set_to_cache(cache_key, recommendation) + print(f"[DEBUG] 缓存交易建议: {cache_key}") + return recommendation def _build_analysis_prompt(self, market_data: Dict, technical_indicators: Dict, diff --git a/requirements.txt b/requirements.txt index 3edd9bd..7722634 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,6 @@ requests==2.31.0 python-dotenv==1.0.0 APScheduler==3.10.4 pytest==7.4.4 +Flask==2.0.1 +Flask-Login==0.6.2 +Werkzeug==2.0.1 diff --git a/web/app.py b/web/app.py index 6f49198..6badf84 100644 --- a/web/app.py +++ b/web/app.py @@ -1,13 +1,16 @@ #!/usr/bin/env python3 # Flask web 应用 -from flask import Flask, render_template, jsonify, request +from flask import Flask, render_template, jsonify, request, redirect, url_for, flash, session import sys import os # 添加项目根目录到 Python 路径 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +# 导入认证模块 +from auth import login_manager, init_db, register_user, login_user_by_credentials, logout_user, login_required, current_user + from qihuo_analyzer.data.data_fetcher import DataFetcher from qihuo_analyzer.data.data_storage import DataStorage from qihuo_analyzer.modules.trend_filter import TrendFilter @@ -20,13 +23,57 @@ from qihuo_analyzer.core.models import AnalysisResult app = Flask(__name__) +# 设置Flask-Login +app.secret_key = 'your-secret-key-here' # 实际项目中应该使用环境变量 +login_manager.init_app(app) +login_manager.login_view = 'login' # 设置登录页面的路由 + +# 初始化数据库 +init_db() + # 模板上下文处理器 @app.context_processor def inject_functions(): import datetime def now(): return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') - return {'now': now} + return {'now': now, 'current_user': current_user} + +# 登录路由 +@app.route('/login', methods=['GET', 'POST']) +def login(): + if request.method == 'POST': + username = request.form['username'] + password = request.form['password'] + success, message = login_user_by_credentials(username, password) + if success: + flash(message) + return redirect(url_for('index')) + else: + flash(message) + return render_template('login.html') + +# 注册路由 +@app.route('/register', methods=['GET', 'POST']) +def register(): + if request.method == 'POST': + username = request.form['username'] + password = request.form['password'] + success, message = register_user(username, password) + if success: + flash(message) + return redirect(url_for('login')) + else: + flash(message) + return render_template('register.html') + +# 登出路由 +@app.route('/logout') +@login_required +def logout(): + logout_user() + flash('已登出') + return redirect(url_for('login')) # 初始化组件 data_fetcher = DataFetcher() @@ -68,11 +115,16 @@ def get_hot_symbols(all_symbols_data): try: # 这里简化处理,实际项目中应该使用真实的成交量、振幅、涨速数据 # 假设我们从kline_data中获取这些数据 - # 由于我们没有这些数据,这里使用随机值模拟 - import random - symbol_data['volume'] = random.randint(10000, 1000000) - symbol_data['amplitude'] = random.uniform(0.1, 5.0) - symbol_data['speed'] = random.uniform(-2.0, 2.0) + # 由于我们没有这些数据,这里使用基于品种代码的哈希值生成值,确保每次计算结果一致 + import hashlib + # 使用品种代码生成哈希值 + hash_obj = hashlib.md5(symbol_data['symbol'].encode()) + hash_int = int(hash_obj.hexdigest(), 16) + + # 基于哈希值生成成交量、振幅、涨速 + symbol_data['volume'] = 100000 + (hash_int % 900000) # 100000-1000000 + symbol_data['amplitude'] = 0.1 + (hash_int % 100) / 25 # 0.1-4.1 + symbol_data['speed'] = -2.0 + (hash_int % 100) / 25 # -2.0-2.0 except Exception: pass @@ -88,6 +140,7 @@ def get_hot_symbols(all_symbols_data): return hot_symbols @app.route('/') +@login_required def index(): """首页 - 多品种分析面板""" # 获取所有品种的分析数据 @@ -301,6 +354,7 @@ def index(): data_unavailable=False) @app.route('/symbol/') +@login_required def symbol_detail(symbol): """品种详情页""" try: @@ -451,7 +505,7 @@ def symbol_detail(symbol): # AI 分析 - 使用指定的模型 ai_agent = DeepseekAgent(model_name=model_name) ai_analysis = ai_agent.analyze_market(market_data, technical_indicators, trend_data, risk_metrics) - recommendation = ai_agent.generate_trade_recommendation(ai_analysis) + recommendation = ai_agent.generate_trade_recommendation(ai_analysis, market_data) # 构建模板数据 # 获取中文名称 @@ -544,6 +598,7 @@ def symbol_detail(symbol): return render_template('error.html', message=f"分析失败: {str(e)}") @app.route('/api/analysis/') +@login_required def api_analysis(symbol): """API: 获取品种分析数据""" try: @@ -598,6 +653,7 @@ def api_analysis(symbol): return jsonify({"error": str(e)}), 500 @app.route('/api/card/') +@login_required def api_card(symbol): """API: 获取分析卡片数据""" try: @@ -695,7 +751,7 @@ def api_card(symbol): } ai_analysis = deepseek_agent.analyze_market(market_data, technical_indicators, trend_data, risk_metrics) - recommendation = deepseek_agent.generate_trade_recommendation(ai_analysis) + recommendation = deepseek_agent.generate_trade_recommendation(ai_analysis, market_data) # 构建卡片数据 # 获取中文名称 @@ -727,6 +783,7 @@ def api_card(symbol): return jsonify({"error": str(e)}), 500 @app.route('/card/') +@login_required def card(symbol): """分析卡片页面""" try: @@ -802,6 +859,7 @@ def _get_kline_data_for_chart(kline_data): return [] @app.route('/api/selected/add/', methods=['POST']) +@login_required def add_selected_symbol(symbol): """添加自选品种""" global selected_symbols @@ -810,6 +868,7 @@ def add_selected_symbol(symbol): return jsonify({'status': 'success', 'selected_symbols': selected_symbols}) @app.route('/api/selected/remove/', methods=['POST']) +@login_required def remove_selected_symbol(symbol): """删除自选品种""" global selected_symbols @@ -818,6 +877,7 @@ def remove_selected_symbol(symbol): return jsonify({'status': 'success', 'selected_symbols': selected_symbols}) @app.route('/api/selected/list') +@login_required def get_selected_symbols(): """获取自选品种列表""" return jsonify({'selected_symbols': selected_symbols}) diff --git a/web/data/futures_analysis.db b/web/data/futures_analysis.db index 46d935b..315e319 100644 Binary files a/web/data/futures_analysis.db and b/web/data/futures_analysis.db differ diff --git a/web/templates/index.html b/web/templates/index.html index ef115d2..754593c 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -318,8 +318,26 @@
-

AI期货分析系统

-

基于DeepSeek大模型和量化分析算法的智能决策平台

+
+
+

AI期货分析系统

+

基于DeepSeek大模型和量化分析算法的智能决策平台

+
+
+ {% if current_user.is_authenticated %} +
+ 欢迎, {{ current_user.username }} +
+ + 登出 + + {% else %} + + 登录 + + {% endif %} +
+