# 金融数据抽象层设计 ## 概述 在"炼妖壶-稷下学宫AI辩论系统"中,我们需要构建一个统一的金融数据抽象层,以支持多种数据源(包括现有的RapidAPI永动机引擎、新增的OpenBB集成引擎,以及未来可能添加的其他数据提供商)。该抽象层将为上层AI智能体提供一致的数据接口,同时隐藏底层数据源的具体实现细节。 ## 设计目标 1. **统一接口**:为所有金融数据访问提供一致的API 2. **可扩展性**:易于添加新的数据提供商 3. **容错性**:当主数据源不可用时,能够自动切换到备用数据源 4. **性能优化**:支持缓存和异步数据获取 5. **类型安全**:使用Python类型注解确保数据结构的一致性 ## 核心组件 ### 1. 数据模型 (Data Models) 定义标准化的金融数据结构: ```python # src/jixia/models/financial_data_models.py from dataclasses import dataclass from typing import Optional, List from datetime import datetime @dataclass class StockQuote: symbol: str price: float change: float change_percent: float volume: int timestamp: datetime @dataclass class HistoricalPrice: date: datetime open: float high: float low: float close: float volume: int @dataclass class CompanyProfile: symbol: str name: str industry: str sector: str market_cap: float pe_ratio: Optional[float] dividend_yield: Optional[float] @dataclass class FinancialNews: title: str summary: str url: str timestamp: datetime sentiment: Optional[float] # -1 (负面) to 1 (正面) ``` ### 2. 抽象基类 (Abstract Base Class) 定义数据提供商的通用接口: ```python # src/jixia/engines/data_abstraction.py from abc import ABC, abstractmethod from typing import List, Optional from src.jixia.models.financial_data_models import StockQuote, HistoricalPrice, CompanyProfile, FinancialNews class DataProvider(ABC): """金融数据提供商抽象基类""" @abstractmethod def get_quote(self, symbol: str) -> Optional[StockQuote]: """获取股票报价""" pass @abstractmethod def get_historical_prices(self, symbol: str, days: int = 30) -> List[HistoricalPrice]: """获取历史价格数据""" pass @abstractmethod def get_company_profile(self, symbol: str) -> Optional[CompanyProfile]: """获取公司概况""" pass @abstractmethod def get_news(self, symbol: str, limit: int = 10) -> List[FinancialNews]: """获取相关新闻""" pass @property @abstractmethod def name(self) -> str: """数据提供商名称""" pass @property @abstractmethod def priority(self) -> int: """优先级(数字越小优先级越高)""" pass ``` ### 3. Provider适配器 (Provider Adapters) 为每个具体的数据源实现适配器: #### RapidAPI永动机引擎适配器 ```python # src/jixia/engines/rapidapi_adapter.py from typing import List, Optional from src.jixia.engines.data_abstraction import DataProvider from src.jixia.models.financial_data_models import StockQuote, HistoricalPrice, CompanyProfile, FinancialNews from src.jixia.engines.perpetual_engine import JixiaPerpetualEngine from config.settings import get_rapidapi_key class RapidAPIDataProvider(DataProvider): """RapidAPI永动机引擎适配器""" def __init__(self): self.engine = JixiaPerpetualEngine(get_rapidapi_key()) self._name = "RapidAPI" self._priority = 2 # 中等优先级 def get_quote(self, symbol: str) -> Optional[StockQuote]: result = self.engine.get_immortal_data("吕洞宾", "quote", symbol) if result.success and result.data: # 解析RapidAPI返回的数据并转换为StockQuote # 这里需要根据实际API返回的数据结构进行调整 return StockQuote( symbol=symbol, price=result.data.get("price", 0), change=result.data.get("change", 0), change_percent=result.data.get("change_percent", 0), volume=result.data.get("volume", 0), timestamp=result.data.get("timestamp") ) return None def get_historical_prices(self, symbol: str, days: int = 30) -> List[HistoricalPrice]: # 实现历史价格数据获取逻辑 pass def get_company_profile(self, symbol: str) -> Optional[CompanyProfile]: # 实现公司概况获取逻辑 pass def get_news(self, symbol: str, limit: int = 10) -> List[FinancialNews]: # 实现新闻获取逻辑 pass @property def name(self) -> str: return self._name @property def priority(self) -> int: return self._priority ``` #### OpenBB引擎适配器 ```python # src/jixia/engines/openbb_adapter.py from typing import List, Optional from src.jixia.engines.data_abstraction import DataProvider from src.jixia.models.financial_data_models import StockQuote, HistoricalPrice, CompanyProfile, FinancialNews from src.jixia.engines.openbb_engine import OpenBBEngine class OpenBBDataProvider(DataProvider): """OpenBB引擎适配器""" def __init__(self): self.engine = OpenBBEngine() self._name = "OpenBB" self._priority = 1 # 最高优先级 def get_quote(self, symbol: str) -> Optional[StockQuote]: result = self.engine.get_immortal_data("吕洞宾", "price", symbol) if result.success and result.data: # 解析OpenBB返回的数据并转换为StockQuote return StockQuote( symbol=symbol, price=result.data.get("close", 0), change=0, # 需要计算 change_percent=0, # 需要计算 volume=result.data.get("volume", 0), timestamp=result.data.get("date") ) return None def get_historical_prices(self, symbol: str, days: int = 30) -> List[HistoricalPrice]: # 实现历史价格数据获取逻辑 pass def get_company_profile(self, symbol: str) -> Optional[CompanyProfile]: # 实现公司概况获取逻辑 pass def get_news(self, symbol: str, limit: int = 10) -> List[FinancialNews]: # 实现新闻获取逻辑 pass @property def name(self) -> str: return self._name @property def priority(self) -> int: return self._priority ``` ### 4. 数据抽象层管理器 (Data Abstraction Layer Manager) 管理多个数据提供商并提供统一接口: ```python # src/jixia/engines/data_abstraction_layer.py from typing import List, Optional from src.jixia.engines.data_abstraction import DataProvider from src.jixia.models.financial_data_models import StockQuote, HistoricalPrice, CompanyProfile, FinancialNews import asyncio class DataAbstractionLayer: """金融数据抽象层管理器""" def __init__(self): self.providers: List[DataProvider] = [] self._initialize_providers() def _initialize_providers(self): """初始化所有可用的数据提供商""" # 根据配置和环境动态加载适配器 try: from src.jixia.engines.rapidapi_adapter import RapidAPIDataProvider self.providers.append(RapidAPIDataProvider()) except ImportError: pass # RapidAPI引擎不可用 try: from src.jixia.engines.openbb_adapter import OpenBBDataProvider self.providers.append(OpenBBDataProvider()) except ImportError: pass # OpenBB引擎不可用 # 按优先级排序 self.providers.sort(key=lambda p: p.priority) def get_quote(self, symbol: str) -> Optional[StockQuote]: """获取股票报价(带故障转移)""" for provider in self.providers: try: quote = provider.get_quote(symbol) if quote: return quote except Exception as e: print(f"警告: {provider.name} 获取报价失败: {e}") continue return None async def get_quote_async(self, symbol: str) -> Optional[StockQuote]: """异步获取股票报价(带故障转移)""" for provider in self.providers: try: # 如果提供商支持异步方法,则使用异步方法 if hasattr(provider, 'get_quote_async'): quote = await provider.get_quote_async(symbol) else: # 否则在执行器中运行同步方法 quote = await asyncio.get_event_loop().run_in_executor( None, provider.get_quote, symbol ) if quote: return quote except Exception as e: print(f"警告: {provider.name} 获取报价失败: {e}") continue return None def get_historical_prices(self, symbol: str, days: int = 30) -> List[HistoricalPrice]: """获取历史价格数据(带故障转移)""" for provider in self.providers: try: prices = provider.get_historical_prices(symbol, days) if prices: return prices except Exception as e: print(f"警告: {provider.name} 获取历史价格失败: {e}") continue return [] def get_company_profile(self, symbol: str) -> Optional[CompanyProfile]: """获取公司概况(带故障转移)""" for provider in self.providers: try: profile = provider.get_company_profile(symbol) if profile: return profile except Exception as e: print(f"警告: {provider.name} 获取公司概况失败: {e}") continue return None def get_news(self, symbol: str, limit: int = 10) -> List[FinancialNews]: """获取相关新闻(带故障转移)""" for provider in self.providers: try: news = provider.get_news(symbol, limit) if news: return news except Exception as e: print(f"警告: {provider.name} 获取新闻失败: {e}") continue return [] ``` ## 八仙与数据源的智能映射 ```python # src/jixia/engines/baxian_data_mapping.py # 设计八仙与数据源的智能映射 immortal_data_mapping = { '吕洞宾': { 'specialty': 'technical_analysis', # 技术分析专家 'preferred_data_types': ['historical', 'price'], 'data_providers': ['OpenBB', 'RapidAPI'] }, '何仙姑': { 'specialty': 'risk_metrics', # 风险控制专家 'preferred_data_types': ['price', 'profile'], 'data_providers': ['RapidAPI', 'OpenBB'] }, '张果老': { 'specialty': 'historical_data', # 历史数据分析师 'preferred_data_types': ['historical'], 'data_providers': ['OpenBB', 'RapidAPI'] }, '韩湘子': { 'specialty': 'sector_analysis', # 新兴资产专家 'preferred_data_types': ['profile', 'news'], 'data_providers': ['RapidAPI', 'OpenBB'] }, '汉钟离': { 'specialty': 'market_movers', # 热点追踪 'preferred_data_types': ['news', 'price'], 'data_providers': ['RapidAPI', 'OpenBB'] }, '蓝采和': { 'specialty': 'value_discovery', # 潜力股发现 'preferred_data_types': ['screener', 'profile'], 'data_providers': ['OpenBB', 'RapidAPI'] }, '铁拐李': { 'specialty': 'contrarian_analysis', # 逆向思维专家 'preferred_data_types': ['profile', 'short_interest'], 'data_providers': ['RapidAPI', 'OpenBB'] }, '曹国舅': { 'specialty': 'macro_economics', # 宏观经济分析师 'preferred_data_types': ['profile', 'institutional_holdings'], 'data_providers': ['OpenBB', 'RapidAPI'] } } ``` ## 缓存策略 为了提高性能,我们将实现多级缓存策略: ```python # src/jixia/engines/data_cache.py import time from typing import Any, Optional from functools import lru_cache class DataCache: """金融数据缓存""" def __init__(self): self._cache = {} self._cache_times = {} self.default_ttl = 60 # 默认缓存时间(秒) def get(self, key: str) -> Optional[Any]: """获取缓存数据""" if key in self._cache: # 检查是否过期 if time.time() - self._cache_times[key] < self.default_ttl: return self._cache[key] else: # 删除过期缓存 del self._cache[key] del self._cache_times[key] return None def set(self, key: str, value: Any, ttl: Optional[int] = None): """设置缓存数据""" self._cache[key] = value self._cache_times[key] = time.time() if ttl: # 可以为特定数据设置不同的TTL pass # 实际实现中需要更复杂的TTL管理机制 @lru_cache(maxsize=128) def get_quote_cache(self, symbol: str) -> Optional[Any]: """LRU缓存装饰器示例""" # 这个方法将自动缓存最近128个调用的结果 pass ``` ## 数据质量监控机制 为了确保数据的准确性和可靠性,我们将实现数据质量监控: ```python # src/jixia/engines/data_quality_monitor.py from typing import Dict, Any from datetime import datetime class DataQualityMonitor: """数据质量监控""" def __init__(self): self.provider_stats = {} def record_access(self, provider_name: str, success: bool, response_time: float, data_size: int): """记录数据访问统计""" if provider_name not in self.provider_stats: self.provider_stats[provider_name] = { 'total_requests': 0, 'successful_requests': 0, 'failed_requests': 0, 'total_response_time': 0, 'total_data_size': 0, 'last_access': None } stats = self.provider_stats[provider_name] stats['total_requests'] += 1 if success: stats['successful_requests'] += 1 else: stats['failed_requests'] += 1 stats['total_response_time'] += response_time stats['total_data_size'] += data_size stats['last_access'] = datetime.now() def get_provider_health(self, provider_name: str) -> Dict[str, Any]: """获取提供商健康状况""" if provider_name not in self.provider_stats: return {'status': 'unknown'} stats = self.provider_stats[provider_name] success_rate = stats['successful_requests'] / stats['total_requests'] if stats['total_requests'] > 0 else 0 avg_response_time = stats['total_response_time'] / stats['total_requests'] if stats['total_requests'] > 0 else 0 status = 'healthy' if success_rate > 0.95 and avg_response_time < 2.0 else 'degraded' if success_rate > 0.8 else 'unhealthy' return { 'status': status, 'success_rate': success_rate, 'avg_response_time': avg_response_time, 'total_requests': stats['total_requests'], 'last_access': stats['last_access'] } ``` ## 使用示例 ```python # 示例:在智能体中使用数据抽象层 from src.jixia.engines.data_abstraction_layer import DataAbstractionLayer from src.jixia.models.financial_data_models import StockQuote # 初始化数据抽象层 dal = DataAbstractionLayer() # 获取股票报价 quote = dal.get_quote("AAPL") if quote: print(f"Apple股价: ${quote.price}") else: print("无法获取股价数据") # 异步获取报价 import asyncio async def async_example(): quote = await dal.get_quote_async("GOOGL") if quote: print(f"Google股价: ${quote.price}") # asyncio.run(async_example()) ``` ## 总结 这个金融数据抽象层设计提供了以下优势: 1. **统一接口**:所有智能体都可以通过相同的接口访问任何数据源 2. **故障转移**:当主数据源不可用时,自动切换到备用数据源 3. **可扩展性**:可以轻松添加新的数据提供商适配器 4. **性能优化**:通过缓存机制提高数据访问速度 5. **质量监控**:实时监控各数据源的健康状况 6. **文化融合**:通过八仙与数据源的智能映射,保持项目的文化特色 这将为"炼妖壶-稷下学宫AI辩论系统"提供一个强大、可靠且可扩展的金融数据基础。