# 数据存储模块 import sqlite3 import json import os from datetime import datetime from typing import Dict, Optional, List import pandas as pd from qihuo_analyzer.utils.config_manager import config_manager class DataStorage: """数据存储管理器""" def __init__(self): self.db_path = config_manager.db_path self._init_database() def _init_database(self): """初始化数据库""" # 确保数据库目录存在 db_dir = os.path.dirname(self.db_path) if db_dir and not os.path.exists(db_dir): os.makedirs(db_dir) # 连接数据库 conn = sqlite3.connect(self.db_path) cursor = conn.cursor() # 创建表 # 分析结果表 cursor.execute(''' CREATE TABLE IF NOT EXISTS analysis_results ( id INTEGER PRIMARY KEY AUTOINCREMENT, symbol TEXT NOT NULL, timestamp TEXT NOT NULL, trend TEXT, probability REAL, direction TEXT, cycle TEXT, atr REAL, adx REAL, support REAL, resistance REAL, stop_loss REAL, target_price REAL, position_size REAL, risk_ratio REAL, fund_flow TEXT, signals TEXT, created_at TEXT DEFAULT CURRENT_TIMESTAMP ) ''') # 历史K线数据表 cursor.execute(''' CREATE TABLE IF NOT EXISTS kline_data ( id INTEGER PRIMARY KEY AUTOINCREMENT, symbol TEXT NOT NULL, duration TEXT NOT NULL, datetime TEXT NOT NULL, open REAL, high REAL, low REAL, close REAL, volume INTEGER, open_interest INTEGER, created_at TEXT DEFAULT CURRENT_TIMESTAMP, UNIQUE(symbol, duration, datetime) ) ''') # 交易建议表 cursor.execute(''' CREATE TABLE IF NOT EXISTS trade_recommendations ( id INTEGER PRIMARY KEY AUTOINCREMENT, symbol TEXT NOT NULL, timestamp TEXT NOT NULL, direction TEXT, entry_price REAL, stop_loss REAL, target_price REAL, position_size REAL, execution_plan TEXT, risk_tips TEXT, status TEXT DEFAULT 'pending', created_at TEXT DEFAULT CURRENT_TIMESTAMP ) ''') # 风险监控表 cursor.execute(''' CREATE TABLE IF NOT EXISTS risk_monitoring ( id INTEGER PRIMARY KEY AUTOINCREMENT, symbol TEXT NOT NULL, timestamp TEXT NOT NULL, current_price REAL, entry_price REAL, stop_loss REAL, target_price REAL, current_profit REAL, risk_status TEXT, created_at TEXT DEFAULT CURRENT_TIMESTAMP ) ''') conn.commit() conn.close() def save_analysis_result(self, result: Dict) -> bool: """保存分析结果""" try: conn = sqlite3.connect(self.db_path) cursor = conn.cursor() # 准备数据 data = { 'symbol': result.get('symbol', ''), 'timestamp': result.get('timestamp', datetime.now().isoformat()), 'trend': result.get('trend'), 'probability': result.get('probability'), 'direction': result.get('direction'), 'cycle': result.get('cycle'), 'atr': result.get('atr'), 'adx': result.get('adx'), 'support': result.get('support'), 'resistance': result.get('resistance'), 'stop_loss': result.get('stop_loss'), 'target_price': result.get('target_price'), 'position_size': result.get('position_size'), 'risk_ratio': result.get('risk_ratio'), 'fund_flow': json.dumps(result.get('fund_flow', {})) if result.get('fund_flow') else None, 'signals': json.dumps(result.get('signals', {})) if result.get('signals') else None } # 插入数据 cursor.execute(''' INSERT INTO analysis_results ( symbol, timestamp, trend, probability, direction, cycle, atr, adx, support, resistance, stop_loss, target_price, position_size, risk_ratio, fund_flow, signals ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''', ( data['symbol'], data['timestamp'], data['trend'], data['probability'], data['direction'], data['cycle'], data['atr'], data['adx'], data['support'], data['resistance'], data['stop_loss'], data['target_price'], data['position_size'], data['risk_ratio'], data['fund_flow'], data['signals'] )) conn.commit() conn.close() return True except Exception as e: print(f"保存分析结果失败:{e}") return False def save_kline_data(self, symbol: str, duration: str, df: pd.DataFrame) -> bool: """保存K线数据""" try: conn = sqlite3.connect(self.db_path) cursor = conn.cursor() # 批量插入数据 data_to_insert = [] for idx, row in df.iterrows(): data_to_insert.append(( symbol, duration, idx.isoformat(), row['open'], row['high'], row['low'], row['close'], row['volume'], row['open_interest'] )) # 使用事务批量插入 if data_to_insert: cursor.executemany(''' INSERT OR IGNORE INTO kline_data ( symbol, duration, datetime, open, high, low, close, volume, open_interest ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ''', data_to_insert) conn.commit() conn.close() return True except Exception as e: print(f"保存K线数据失败:{e}") return False def save_trade_recommendation(self, recommendation: Dict) -> bool: """保存交易建议""" try: conn = sqlite3.connect(self.db_path) cursor = conn.cursor() # 准备数据 data = { 'symbol': recommendation.get('symbol', ''), 'timestamp': recommendation.get('timestamp', datetime.now().isoformat()), 'direction': recommendation.get('direction'), 'entry_price': recommendation.get('entry_price'), 'stop_loss': recommendation.get('stop_loss'), 'target_price': recommendation.get('target_price'), 'position_size': recommendation.get('position_size'), 'execution_plan': recommendation.get('execution_plan'), 'risk_tips': recommendation.get('risk_tips') } # 插入数据 cursor.execute(''' INSERT INTO trade_recommendations ( symbol, timestamp, direction, entry_price, stop_loss, target_price, position_size, execution_plan, risk_tips ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ''', ( data['symbol'], data['timestamp'], data['direction'], data['entry_price'], data['stop_loss'], data['target_price'], data['position_size'], data['execution_plan'], data['risk_tips'] )) conn.commit() conn.close() return True except Exception as e: print(f"保存交易建议失败:{e}") return False def save_risk_monitoring(self, monitoring_data: Dict) -> bool: """保存风险监控数据""" try: conn = sqlite3.connect(self.db_path) cursor = conn.cursor() # 准备数据 data = { 'symbol': monitoring_data.get('symbol', ''), 'timestamp': monitoring_data.get('timestamp', datetime.now().isoformat()), 'current_price': monitoring_data.get('current_price'), 'entry_price': monitoring_data.get('entry_price'), 'stop_loss': monitoring_data.get('stop_loss'), 'target_price': monitoring_data.get('target_price'), 'current_profit': monitoring_data.get('current_profit'), 'risk_status': monitoring_data.get('risk_status') } # 插入数据 cursor.execute(''' INSERT INTO risk_monitoring ( symbol, timestamp, current_price, entry_price, stop_loss, target_price, current_profit, risk_status ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ''', ( data['symbol'], data['timestamp'], data['current_price'], data['entry_price'], data['stop_loss'], data['target_price'], data['current_profit'], data['risk_status'] )) conn.commit() conn.close() return True except Exception as e: print(f"保存风险监控数据失败:{e}") return False def get_analysis_results(self, symbol: str, limit: int = 100) -> pd.DataFrame: """获取分析结果""" try: conn = sqlite3.connect(self.db_path) query = f""" SELECT * FROM analysis_results WHERE symbol = ? ORDER BY timestamp DESC LIMIT ? """ df = pd.read_sql_query(query, conn, params=(symbol, limit)) conn.close() # 解析JSON字段 if not df.empty: df['fund_flow'] = df['fund_flow'].apply(lambda x: json.loads(x) if x else {}) df['signals'] = df['signals'].apply(lambda x: json.loads(x) if x else {}) return df except Exception as e: print(f"获取分析结果失败:{e}") return pd.DataFrame() def get_kline_data(self, symbol: str, duration: str, limit: int = 200) -> pd.DataFrame: """获取K线数据""" try: conn = sqlite3.connect(self.db_path) query = f""" SELECT * FROM kline_data WHERE symbol = ? AND duration = ? ORDER BY datetime DESC LIMIT ? """ df = pd.read_sql_query(query, conn, params=(symbol, duration, limit)) conn.close() if not df.empty: # 转换时间格式并设置索引 df['datetime'] = pd.to_datetime(df['datetime']) df = df.sort_values('datetime') df.set_index('datetime', inplace=True) # 选择需要的列 df = df[['open', 'high', 'low', 'close', 'volume', 'open_interest']] return df except Exception as e: print(f"获取K线数据失败:{e}") return pd.DataFrame() def get_trade_recommendations(self, symbol: str, status: Optional[str] = None) -> pd.DataFrame: """获取交易建议""" try: conn = sqlite3.connect(self.db_path) if status: query = f""" SELECT * FROM trade_recommendations WHERE symbol = ? AND status = ? ORDER BY timestamp DESC """ df = pd.read_sql_query(query, conn, params=(symbol, status)) else: query = f""" SELECT * FROM trade_recommendations WHERE symbol = ? ORDER BY timestamp DESC """ df = pd.read_sql_query(query, conn, params=(symbol,)) conn.close() return df except Exception as e: print(f"获取交易建议失败:{e}") return pd.DataFrame() def update_recommendation_status(self, recommendation_id: int, status: str) -> bool: """更新交易建议状态""" try: conn = sqlite3.connect(self.db_path) cursor = conn.cursor() cursor.execute(''' UPDATE trade_recommendations SET status = ? WHERE id = ? ''', (status, recommendation_id)) conn.commit() conn.close() return True except Exception as e: print(f"更新交易建议状态失败:{e}") return False def delete_old_data(self, days: int = 30) -> bool: """删除旧数据""" try: conn = sqlite3.connect(self.db_path) cursor = conn.cursor() # 计算删除时间点 delete_time = (datetime.now() - pd.Timedelta(days=days)).isoformat() # 删除旧的分析结果 cursor.execute('DELETE FROM analysis_results WHERE created_at < ?', (delete_time,)) # 删除旧的K线数据 cursor.execute('DELETE FROM kline_data WHERE created_at < ?', (delete_time,)) # 删除旧的交易建议 cursor.execute('DELETE FROM trade_recommendations WHERE created_at < ?', (delete_time,)) # 删除旧的风险监控数据 cursor.execute('DELETE FROM risk_monitoring WHERE created_at < ?', (delete_time,)) conn.commit() conn.close() return True except Exception as e: print(f"删除旧数据失败:{e}") return False