TradingAgents/tradingagents/dataflows/optimized_us_data.py.diff

680 lines
28 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 文件差异报告
# 当前文件: tradingagents\dataflows\optimized_us_data.py
# 中文版文件: TradingAgentsCN\tradingagents\dataflows\optimized_us_data.py
# 生成时间: 周日 2025/07/06
--- current/optimized_us_data.py+++ chinese_version/optimized_us_data.py@@ -1,7 +1,7 @@ #!/usr/bin/env python3
"""
-Optimized US Stock Data Fetcher
-Integrates caching strategy to reduce API calls and improve response speed
+优化的美股数据获取工具
+集成缓存策略减少API调用提高响应速度
"""
import os
@@ -16,24 +16,24 @@
class OptimizedUSDataProvider:
- """Optimized US Stock Data Provider - Integrates caching and API rate limiting"""
+ """优化的美股数据提供器 - 集成缓存和API限制处理"""
def __init__(self):
self.cache = get_cache()
self.config = get_config()
self.last_api_call = 0
- self.min_api_interval = 1.0 # Minimum API call interval (seconds)
-
- print("📊 Optimized US stock data provider initialized")
+ self.min_api_interval = 1.0 # 最小API调用间隔
+
+ print("📊 优化美股数据提供器初始化完成")
def _wait_for_rate_limit(self):
- """Wait for API rate limit"""
+ """等待API限制"""
current_time = time.time()
time_since_last_call = current_time - self.last_api_call
if time_since_last_call < self.min_api_interval:
wait_time = self.min_api_interval - time_since_last_call
- print(f"⏳ API rate limit wait {wait_time:.1f}s...")
+ print(f"⏳ API限制等待 {wait_time:.1f}s...")
time.sleep(wait_time)
self.last_api_call = time.time()
@@ -41,364 +41,292 @@ def get_stock_data(self, symbol: str, start_date: str, end_date: str,
force_refresh: bool = False) -> str:
"""
- Get US stock data - prioritize cache usage
+ 获取美股数据 - 优先使用缓存
Args:
- symbol: Stock symbol
- start_date: Start date (YYYY-MM-DD)
- end_date: End date (YYYY-MM-DD)
- force_refresh: Whether to force refresh cache
-
+ symbol: 股票代码
+ start_date: 开始日期 (YYYY-MM-DD)
+ end_date: 结束日期 (YYYY-MM-DD)
+ force_refresh: 是否强制刷新缓存
+
Returns:
- Formatted stock data string
+ 格式化的股票数据字符串
"""
+ print(f"📈 获取美股数据: {symbol} ({start_date} 到 {end_date})")
+
+ # 检查缓存(除非强制刷新)
+ if not force_refresh:
+ # 优先查找FINNHUB缓存
+ cache_key = self.cache.find_cached_stock_data(
+ symbol=symbol,
+ start_date=start_date,
+ end_date=end_date,
+ data_source="finnhub"
+ )
+
+ # 如果没有FINNHUB缓存查找Yahoo Finance缓存
+ if not cache_key:
+ cache_key = self.cache.find_cached_stock_data(
+ symbol=symbol,
+ start_date=start_date,
+ end_date=end_date,
+ data_source="yfinance"
+ )
+
+ if cache_key:
+ cached_data = self.cache.load_stock_data(cache_key)
+ if cached_data:
+ print(f"⚡ 从缓存加载美股数据: {symbol}")
+ return cached_data
+
+ # 缓存未命中从API获取 - 优先使用FINNHUB
+ formatted_data = None
+ data_source = None
+
+ # 尝试FINNHUB API优先
try:
- # Check cache first (unless force refresh)
- if not force_refresh:
- cache_key = self.cache.find_cached_stock_data(
- symbol, start_date, end_date, "optimized_yfinance"
- )
-
- if cache_key and self.cache.is_cache_valid(cache_key, symbol):
- cached_data = self.cache.load_stock_data(cache_key)
- if cached_data:
- print(f"📖 Using cached data for {symbol}")
- if isinstance(cached_data, pd.DataFrame):
- return self._format_stock_data(cached_data, symbol)
- else:
- return cached_data
-
- # Fetch new data from API
- print(f"🌐 Fetching new data for {symbol} from {start_date} to {end_date}")
-
- # Wait for rate limit
+ print(f"🌐 从FINNHUB API获取数据: {symbol}")
self._wait_for_rate_limit()
-
- # Try Yahoo Finance first
+
+ formatted_data = self._get_data_from_finnhub(symbol, start_date, end_date)
+ if formatted_data and "❌" not in formatted_data:
+ data_source = "finnhub"
+ print(f"✅ FINNHUB数据获取成功: {symbol}")
+ else:
+ print(f"⚠️ FINNHUB数据获取失败尝试备用方案")
+ formatted_data = None
+
+ except Exception as e:
+ print(f"❌ FINNHUB API调用失败: {e}")
+ formatted_data = None
+
+ # 备用方案Yahoo Finance API
+ if not formatted_data:
try:
- data = self._fetch_from_yfinance(symbol, start_date, end_date)
- if data is not None and not data.empty:
- # Cache the DataFrame
- cache_key = self.cache.save_stock_data(
- symbol, data, start_date, end_date, "optimized_yfinance"
- )
+ print(f"🌐 从Yahoo Finance API获取数据: {symbol}")
+ self._wait_for_rate_limit()
+
+ # 获取数据
+ ticker = yf.Ticker(symbol.upper())
+ data = ticker.history(start=start_date, end=end_date)
+
+ if data.empty:
+ error_msg = f"未找到股票 '{symbol}' 在 {start_date} 到 {end_date} 期间的数据"
+ print(f"❌ {error_msg}")
+ else:
+ # 格式化数据
+ formatted_data = self._format_stock_data(symbol, data, start_date, end_date)
+ data_source = "yfinance"
+ print(f"✅ Yahoo Finance数据获取成功: {symbol}")
+
+ except Exception as e:
+ print(f"❌ Yahoo Finance API调用失败: {e}")
+ formatted_data = None
+
+ # 如果所有API都失败生成备用数据
+ if not formatted_data:
+ error_msg = "所有美股数据源都不可用"
+ print(f"❌ {error_msg}")
+ return self._generate_fallback_data(symbol, start_date, end_date, error_msg)
+
+ # 保存到缓存
+ self.cache.save_stock_data(
+ symbol=symbol,
+ data=formatted_data,
+ start_date=start_date,
+ end_date=end_date,
+ data_source=data_source
+ )
+
+ return formatted_data
+
+ def _format_stock_data(self, symbol: str, data: pd.DataFrame,
+ start_date: str, end_date: str) -> str:
+ """格式化股票数据为字符串"""
+
+ # 移除时区信息
+ if data.index.tz is not None:
+ data.index = data.index.tz_localize(None)
+
+ # 四舍五入数值
+ numeric_columns = ["Open", "High", "Low", "Close", "Adj Close"]
+ for col in numeric_columns:
+ if col in data.columns:
+ data[col] = data[col].round(2)
+
+ # 获取最新价格和统计信息
+ latest_price = data['Close'].iloc[-1]
+ price_change = data['Close'].iloc[-1] - data['Close'].iloc[0]
+ price_change_pct = (price_change / data['Close'].iloc[0]) * 100
+
+ # 计算技术指标
+ data['MA5'] = data['Close'].rolling(window=5).mean()
+ data['MA10'] = data['Close'].rolling(window=10).mean()
+ data['MA20'] = data['Close'].rolling(window=20).mean()
+
+ # 计算RSI
+ delta = data['Close'].diff()
+ gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
+ loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
+ rs = gain / loss
+ rsi = 100 - (100 / (1 + rs))
+
+ # 格式化输出
+ result = f"""# {symbol} 美股数据分析
+
+## 📊 基本信息
+- 股票代码: {symbol}
+- 数据期间: {start_date} 至 {end_date}
+- 数据条数: {len(data)}条
+- 最新价格: ${latest_price:.2f}
+- 期间涨跌: ${price_change:+.2f} ({price_change_pct:+.2f}%)
+
+## 📈 价格统计
+- 期间最高: ${data['High'].max():.2f}
+- 期间最低: ${data['Low'].min():.2f}
+- 平均成交量: {data['Volume'].mean():,.0f}
+
+## 🔍 技术指标
+- MA5: ${data['MA5'].iloc[-1]:.2f}
+- MA10: ${data['MA10'].iloc[-1]:.2f}
+- MA20: ${data['MA20'].iloc[-1]:.2f}
+- RSI: {rsi.iloc[-1]:.2f}
+
+## 📋 最近5日数据
+{data.tail().to_string()}
+
+数据来源: Yahoo Finance API
+更新时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+"""
+
+ return result
+
+ def _try_get_old_cache(self, symbol: str, start_date: str, end_date: str) -> Optional[str]:
+ """尝试获取过期的缓存数据作为备用"""
+ try:
+ # 查找任何相关的缓存不考虑TTL
+ for metadata_file in self.cache.metadata_dir.glob(f"*_meta.json"):
+ try:
+ import json
+ with open(metadata_file, 'r', encoding='utf-8') as f:
+ metadata = json.load(f)
- # Format and return
- formatted_data = self._format_stock_data(data, symbol)
- print(f"✅ Successfully fetched and cached data for {symbol}")
- return formatted_data
- else:
- print(f"⚠️ No data returned from Yahoo Finance for {symbol}")
-
- except Exception as e:
- print(f"❌ Yahoo Finance error for {symbol}: {e}")
-
- # Fallback: Try FINNHUB (if API key available)
- try:
- finnhub_data = self._fetch_from_finnhub(symbol, start_date, end_date)
- if finnhub_data:
- # Cache the string data
- cache_key = self.cache.save_stock_data(
- symbol, finnhub_data, start_date, end_date, "optimized_finnhub"
- )
- print(f"✅ Successfully fetched data from FINNHUB for {symbol}")
- return finnhub_data
-
- except Exception as e:
- print(f"❌ FINNHUB error for {symbol}: {e}")
-
- # If all fails, return error message
- error_msg = f"❌ Failed to fetch data for {symbol} from {start_date} to {end_date}"
- print(error_msg)
- return error_msg
-
+ if (metadata.get('symbol') == symbol and
+ metadata.get('data_type') == 'stock_data' and
+ metadata.get('market_type') == 'us'):
+
+ cache_key = metadata_file.stem.replace('_meta', '')
+ cached_data = self.cache.load_stock_data(cache_key)
+ if cached_data:
+ return cached_data + "\n\n⚠ 注意: 使用的是过期缓存数据"
+ except Exception:
+ continue
+ except Exception:
+ pass
+
+ return None
+
+ def _get_data_from_finnhub(self, symbol: str, start_date: str, end_date: str) -> str:
+ """从FINNHUB API获取股票数据"""
+ try:
+ import finnhub
+ import os
+ from datetime import datetime, timedelta
+
+ # 获取API密钥
+ api_key = os.getenv('FINNHUB_API_KEY')
+ if not api_key:
+ return None
+
+ client = finnhub.Client(api_key=api_key)
+
+ # 获取实时报价
+ quote = client.quote(symbol.upper())
+ if not quote or 'c' not in quote:
+ return None
+
+ # 获取公司信息
+ profile = client.company_profile2(symbol=symbol.upper())
+ company_name = profile.get('name', symbol.upper()) if profile else symbol.upper()
+
+ # 格式化数据
+ current_price = quote.get('c', 0)
+ change = quote.get('d', 0)
+ change_percent = quote.get('dp', 0)
+
+ formatted_data = f"""# {symbol.upper()} 美股数据分析
+
+## 📊 实时行情
+- 股票名称: {company_name}
+- 当前价格: ${current_price:.2f}
+- 涨跌额: ${change:+.2f}
+- 涨跌幅: {change_percent:+.2f}%
+- 开盘价: ${quote.get('o', 0):.2f}
+- 最高价: ${quote.get('h', 0):.2f}
+- 最低价: ${quote.get('l', 0):.2f}
+- 前收盘: ${quote.get('pc', 0):.2f}
+- 更新时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+
+## 📈 数据概览
+- 数据期间: {start_date} 至 {end_date}
+- 数据来源: FINNHUB API (实时数据)
+- 当前价位相对位置: {((current_price - quote.get('l', current_price)) / max(quote.get('h', current_price) - quote.get('l', current_price), 0.01) * 100):.1f}%
+- 日内振幅: {((quote.get('h', 0) - quote.get('l', 0)) / max(quote.get('pc', 1), 0.01) * 100):.2f}%
+
+生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+"""
+
+ return formatted_data
+
except Exception as e:
- error_msg = f"❌ Unexpected error fetching data for {symbol}: {e}"
- print(error_msg)
- return error_msg
-
- def _fetch_from_yfinance(self, symbol: str, start_date: str, end_date: str) -> Optional[pd.DataFrame]:
- """Fetch data from Yahoo Finance"""
- try:
- ticker = yf.Ticker(symbol)
- data = ticker.history(start=start_date, end=end_date)
-
- if data.empty:
- print(f"⚠️ No data available for {symbol} in the specified date range")
- return None
-
- # Reset index to make Date a column
- data = data.reset_index()
-
- # Ensure we have the required columns
- required_columns = ['Date', 'Open', 'High', 'Low', 'Close', 'Volume']
- missing_columns = [col for col in required_columns if col not in data.columns]
-
- if missing_columns:
- print(f"⚠️ Missing columns for {symbol}: {missing_columns}")
- return None
-
- return data[required_columns]
-
- except Exception as e:
- print(f"❌ Yahoo Finance fetch error for {symbol}: {e}")
+ print(f"❌ FINNHUB数据获取失败: {e}")
return None
-
- def _fetch_from_finnhub(self, symbol: str, start_date: str, end_date: str) -> Optional[str]:
- """Fetch data from FINNHUB API"""
- try:
- # Check if FINNHUB API key is available
- finnhub_api_key = os.getenv('FINNHUB_API_KEY')
- if not finnhub_api_key:
- print("⚠️ FINNHUB API key not found, skipping FINNHUB data fetch")
- return None
-
- import finnhub
-
- # Initialize FINNHUB client
- finnhub_client = finnhub.Client(api_key=finnhub_api_key)
-
- # Convert dates to timestamps
- start_timestamp = int(datetime.strptime(start_date, '%Y-%m-%d').timestamp())
- end_timestamp = int(datetime.strptime(end_date, '%Y-%m-%d').timestamp())
-
- # Fetch candle data
- candle_data = finnhub_client.stock_candles(symbol, 'D', start_timestamp, end_timestamp)
-
- if candle_data['s'] != 'ok':
- print(f"⚠️ FINNHUB returned status: {candle_data['s']} for {symbol}")
- return None
-
- # Format data
- formatted_data = self._format_finnhub_data(candle_data, symbol)
- return formatted_data
-
- except ImportError:
- print("⚠️ finnhub-python package not installed, skipping FINNHUB data fetch")
- return None
- except Exception as e:
- print(f"❌ FINNHUB fetch error for {symbol}: {e}")
- return None
-
- def _format_stock_data(self, data: pd.DataFrame, symbol: str) -> str:
- """Format DataFrame stock data into string"""
- try:
- # Ensure Date column is properly formatted
- if 'Date' in data.columns:
- data['Date'] = pd.to_datetime(data['Date']).dt.strftime('%Y-%m-%d')
-
- # Round numerical columns to 2 decimal places
- numeric_columns = ['Open', 'High', 'Low', 'Close']
- for col in numeric_columns:
- if col in data.columns:
- data[col] = data[col].round(2)
-
- # Format volume as integer
- if 'Volume' in data.columns:
- data['Volume'] = data['Volume'].astype(int)
-
- # Create formatted string
- formatted_lines = [f"Stock Data for {symbol}:"]
- formatted_lines.append("Date,Open,High,Low,Close,Volume")
-
- for _, row in data.iterrows():
- line = f"{row['Date']},{row['Open']},{row['High']},{row['Low']},{row['Close']},{row['Volume']}"
- formatted_lines.append(line)
-
- # Add summary statistics
- if len(data) > 0:
- formatted_lines.append(f"\nSummary for {symbol}:")
- formatted_lines.append(f"Period: {data['Date'].iloc[0]} to {data['Date'].iloc[-1]}")
- formatted_lines.append(f"Total trading days: {len(data)}")
- formatted_lines.append(f"Average volume: {data['Volume'].mean():,.0f}")
- formatted_lines.append(f"Price range: ${data['Low'].min():.2f} - ${data['High'].max():.2f}")
-
- # Calculate basic statistics
- start_price = data['Open'].iloc[0]
- end_price = data['Close'].iloc[-1]
- price_change = end_price - start_price
- price_change_pct = (price_change / start_price) * 100
-
- formatted_lines.append(f"Period return: {price_change_pct:+.2f}% (${price_change:+.2f})")
-
- return "\n".join(formatted_lines)
-
- except Exception as e:
- print(f"❌ Error formatting stock data for {symbol}: {e}")
- return f"Error formatting data for {symbol}: {str(e)}"
-
- def _format_finnhub_data(self, candle_data: Dict, symbol: str) -> str:
- """Format FINNHUB candle data into string"""
- try:
- # Extract data arrays
- timestamps = candle_data['t']
- opens = candle_data['o']
- highs = candle_data['h']
- lows = candle_data['l']
- closes = candle_data['c']
- volumes = candle_data['v']
-
- # Create formatted string
- formatted_lines = [f"Stock Data for {symbol} (FINNHUB):"]
- formatted_lines.append("Date,Open,High,Low,Close,Volume")
-
- for i in range(len(timestamps)):
- date = datetime.fromtimestamp(timestamps[i]).strftime('%Y-%m-%d')
- line = f"{date},{opens[i]:.2f},{highs[i]:.2f},{lows[i]:.2f},{closes[i]:.2f},{int(volumes[i])}"
- formatted_lines.append(line)
-
- # Add summary
- if len(timestamps) > 0:
- start_date = datetime.fromtimestamp(timestamps[0]).strftime('%Y-%m-%d')
- end_date = datetime.fromtimestamp(timestamps[-1]).strftime('%Y-%m-%d')
-
- formatted_lines.append(f"\nSummary for {symbol}:")
- formatted_lines.append(f"Period: {start_date} to {end_date}")
- formatted_lines.append(f"Total trading days: {len(timestamps)}")
- formatted_lines.append(f"Average volume: {sum(volumes)/len(volumes):,.0f}")
- formatted_lines.append(f"Price range: ${min(lows):.2f} - ${max(highs):.2f}")
-
- # Calculate return
- price_change = closes[-1] - opens[0]
- price_change_pct = (price_change / opens[0]) * 100
- formatted_lines.append(f"Period return: {price_change_pct:+.2f}% (${price_change:+.2f})")
-
- return "\n".join(formatted_lines)
-
- except Exception as e:
- print(f"❌ Error formatting FINNHUB data for {symbol}: {e}")
- return f"Error formatting FINNHUB data for {symbol}: {str(e)}"
-
- def get_stock_with_indicators(self, symbol: str, start_date: str, end_date: str,
- indicators: list = None) -> str:
- """
- Get stock data with technical indicators
-
- Args:
- symbol: Stock symbol
- start_date: Start date (YYYY-MM-DD)
- end_date: End date (YYYY-MM-DD)
- indicators: List of indicators to calculate ['sma_20', 'rsi', 'macd']
-
- Returns:
- Formatted stock data with indicators
- """
- try:
- # Get basic stock data
- basic_data = self.get_stock_data(symbol, start_date, end_date)
-
- if basic_data.startswith("❌"):
- return basic_data
-
- # If no indicators requested, return basic data
- if not indicators:
- return basic_data
-
- # Fetch DataFrame for indicator calculation
- data_df = self._fetch_from_yfinance(symbol, start_date, end_date)
- if data_df is None or data_df.empty:
- return basic_data
-
- # Calculate indicators
- indicator_data = self._calculate_indicators(data_df, indicators)
-
- # Combine basic data with indicators
- combined_data = basic_data + "\n\nTechnical Indicators:\n" + indicator_data
-
- return combined_data
-
- except Exception as e:
- error_msg = f"❌ Error getting stock data with indicators for {symbol}: {e}"
- print(error_msg)
- return error_msg
-
- def _calculate_indicators(self, data: pd.DataFrame, indicators: list) -> str:
- """Calculate technical indicators"""
- try:
- indicator_lines = []
-
- for indicator in indicators:
- if indicator == 'sma_20':
- data['SMA_20'] = data['Close'].rolling(window=20).mean()
- latest_sma = data['SMA_20'].iloc[-1]
- indicator_lines.append(f"SMA(20): ${latest_sma:.2f}")
-
- elif indicator == 'rsi':
- # Simple RSI calculation
- delta = data['Close'].diff()
- gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
- loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
- rs = gain / loss
- rsi = 100 - (100 / (1 + rs))
- latest_rsi = rsi.iloc[-1]
- indicator_lines.append(f"RSI(14): {latest_rsi:.2f}")
-
- elif indicator == 'macd':
- # Simple MACD calculation
- ema_12 = data['Close'].ewm(span=12).mean()
- ema_26 = data['Close'].ewm(span=26).mean()
- macd_line = ema_12 - ema_26
- signal_line = macd_line.ewm(span=9).mean()
- latest_macd = macd_line.iloc[-1]
- latest_signal = signal_line.iloc[-1]
- indicator_lines.append(f"MACD: {latest_macd:.4f}, Signal: {latest_signal:.4f}")
-
- return "\n".join(indicator_lines)
-
- except Exception as e:
- print(f"❌ Error calculating indicators: {e}")
- return f"Error calculating indicators: {str(e)}"
-
-
-# Global provider instance
-_global_provider = None
+
+ def _generate_fallback_data(self, symbol: str, start_date: str, end_date: str, error_msg: str) -> str:
+ """生成备用数据"""
+ return f"""# {symbol} 美股数据获取失败
+
+## ❌ 错误信息
+{error_msg}
+
+## 📊 模拟数据(仅供演示)
+- 股票代码: {symbol}
+- 数据期间: {start_date} 至 {end_date}
+- 最新价格: ${random.uniform(100, 300):.2f}
+- 模拟涨跌: {random.uniform(-5, 5):+.2f}%
+
+## ⚠️ 重要提示
+由于API限制或网络问题无法获取实时数据。
+建议稍后重试或检查网络连接。
+
+生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+"""
+
+
+# 全局实例
+_us_data_provider = None
def get_optimized_us_data_provider() -> OptimizedUSDataProvider:
+ """获取全局美股数据提供器实例"""
+ global _us_data_provider
+ if _us_data_provider is None:
+ _us_data_provider = OptimizedUSDataProvider()
+ return _us_data_provider
+
+
+def get_us_stock_data_cached(symbol: str, start_date: str, end_date: str,
+ force_refresh: bool = False) -> str:
"""
- Get global optimized US data provider instance
+ 获取美股数据的便捷函数
+
+ Args:
+ symbol: 股票代码
+ start_date: 开始日期 (YYYY-MM-DD)
+ end_date: 结束日期 (YYYY-MM-DD)
+ force_refresh: 是否强制刷新缓存
Returns:
- OptimizedUSDataProvider instance
+ 格式化的股票数据字符串
"""
- global _global_provider
- if _global_provider is None:
- _global_provider = OptimizedUSDataProvider()
- return _global_provider
-
-
-# Convenience functions
-def get_optimized_stock_data(symbol: str, start_date: str, end_date: str,
- force_refresh: bool = False) -> str:
- """Get optimized stock data (convenience function)"""
provider = get_optimized_us_data_provider()
return provider.get_stock_data(symbol, start_date, end_date, force_refresh)
-
-
-def get_stock_with_indicators(symbol: str, start_date: str, end_date: str,
- indicators: list = None) -> str:
- """Get stock data with technical indicators (convenience function)"""
- provider = get_optimized_us_data_provider()
- return provider.get_stock_with_indicators(symbol, start_date, end_date, indicators)
-
-
-if __name__ == "__main__":
- # Test the optimized data provider
- print("🧪 Testing Optimized US Data Provider...")
-
- # Initialize provider
- provider = OptimizedUSDataProvider()
-
- # Test data fetch
- data = provider.get_stock_data("AAPL", "2024-01-01", "2024-01-31")
- print("Sample data:")
- print(data[:500] + "..." if len(data) > 500 else data)
-
- # Test with indicators
- data_with_indicators = provider.get_stock_with_indicators(
- "AAPL", "2024-01-01", "2024-01-31",
- indicators=['sma_20', 'rsi', 'macd']
- )
- print("\nData with indicators:")
- print(data_with_indicators[-500:] if len(data_with_indicators) > 500 else data_with_indicators)
-
- print("✅ Optimized data provider test completed!")