ticker_diagnostics.py•7.96 kB
# ticker_diagnostics.py - Diagnose failed ticker analysis
import yfinance as yf
import pandas as pd
from datetime import datetime, timedelta
def diagnose_ticker(ticker: str) -> dict:
"""Diagnose why a ticker analysis might be failing."""
print(f"\n🔍 DIAGNOSING {ticker}")
print("=" * 40)
diagnosis = {
'ticker': ticker,
'issues': [],
'data_available': False,
'sufficient_data': False,
'recent_data': False,
'recommendation': None
}
try:
# Test basic data download
print("📊 Testing data download...")
df = yf.download(ticker, period="1y", interval="1d", progress=False)
if df.empty:
diagnosis['issues'].append("No data returned from yfinance")
print("❌ No data returned - ticker may be delisted or invalid")
# Try different periods
for period in ["6mo", "3mo", "1mo"]:
df_test = yf.download(ticker, period=period, interval="1d", progress=False)
if not df_test.empty:
print(f"✅ Found data with {period} period ({len(df_test)} days)")
df = df_test
break
if df.empty:
diagnosis['recommendation'] = f"Ticker {ticker} appears to be delisted or invalid. Check for symbol changes."
return diagnosis
diagnosis['data_available'] = True
print(f"✅ Data available: {len(df)} days")
# Check data sufficiency
if len(df) < 30:
diagnosis['issues'].append(f"Insufficient data: only {len(df)} days (need 30+)")
print(f"⚠️ Insufficient data: only {len(df)} days (need 30+ for ARIMA)")
else:
diagnosis['sufficient_data'] = True
print(f"✅ Sufficient data: {len(df)} days")
# Check data recency
last_date = df.index[-1]
days_old = (datetime.now() - last_date.to_pydatetime()).days
if days_old > 7:
diagnosis['issues'].append(f"Stale data: last update {days_old} days ago")
print(f"⚠️ Stale data: last update {days_old} days ago ({last_date.strftime('%Y-%m-%d')})")
else:
diagnosis['recent_data'] = True
print(f"✅ Recent data: last update {days_old} days ago")
# Check for data quality issues
close_prices = df['Close'].dropna()
if len(close_prices) == 0:
diagnosis['issues'].append("No valid closing prices")
print("❌ No valid closing prices")
elif close_prices.isnull().sum() > len(close_prices) * 0.1:
diagnosis['issues'].append("Too many missing values")
print("⚠️ Too many missing values in price data")
else:
print("✅ Price data quality looks good")
# Test ARIMA prerequisites
print("\n📈 Testing ARIMA prerequisites...")
if len(close_prices) >= 30:
try:
from statsmodels.tsa.arima.model import ARIMA
# Test simple ARIMA
model = ARIMA(close_prices.values, order=(1, 1, 1))
fitted = model.fit()
forecast = fitted.forecast(steps=1)
print("✅ ARIMA modeling successful")
except Exception as e:
diagnosis['issues'].append(f"ARIMA modeling failed: {str(e)}")
print(f"❌ ARIMA modeling failed: {e}")
# Test XGBoost prerequisites
print("\n🤖 Testing XGBoost prerequisites...")
try:
df_test = df.copy()
for i in range(1, 4):
df_test[f'Lag_{i}'] = df_test['Close'].shift(i)
df_test = df_test.dropna()
if len(df_test) < 10:
diagnosis['issues'].append("Insufficient data for XGBoost after feature engineering")
print("❌ Insufficient data for XGBoost after feature engineering")
else:
print("✅ XGBoost prerequisites met")
except Exception as e:
diagnosis['issues'].append(f"XGBoost preprocessing failed: {str(e)}")
print(f"❌ XGBoost preprocessing failed: {e}")
# Company info check
print("\n🏢 Checking company information...")
try:
stock = yf.Ticker(ticker)
info = stock.info
if 'longName' in info:
print(f"✅ Company: {info['longName']}")
if 'quoteType' in info:
print(f"✅ Type: {info['quoteType']}")
else:
diagnosis['issues'].append("No company information available")
print("⚠️ No company information available")
except Exception as e:
diagnosis['issues'].append(f"Company info lookup failed: {str(e)}")
print(f"⚠️ Company info lookup failed: {e}")
# Generate recommendation
if not diagnosis['issues']:
diagnosis['recommendation'] = f"{ticker} should work fine - investigate specific error message"
elif "delisted" in " ".join(diagnosis['issues']).lower() or not diagnosis['data_available']:
diagnosis['recommendation'] = f"Replace {ticker} with updated ticker symbol or remove from portfolio"
elif not diagnosis['sufficient_data']:
diagnosis['recommendation'] = f"Use longer data period for {ticker} or remove from portfolio"
else:
diagnosis['recommendation'] = f"Check {ticker} data quality and error handling"
except Exception as e:
diagnosis['issues'].append(f"General error: {str(e)}")
diagnosis['recommendation'] = f"Investigate {ticker} - general download error"
print(f"❌ General error: {e}")
return diagnosis
def check_ticker_alternatives(ticker: str) -> list:
"""Suggest alternative ticker symbols for common changes."""
alternatives = {
'TWTR': ['No longer exists - Twitter delisted after Musk acquisition'],
'SQ': ['BLOCK - Square changed name and ticker to Block Inc.'],
'FB': ['META - Facebook changed ticker to Meta'],
'GOOGL': ['GOOGL (Class A)', 'GOOG (Class C)'],
'BRKB': ['BRK-B - Berkshire Hathaway Class B'],
'BRK.B': ['BRK-B - Berkshire Hathaway Class B']
}
ticker_upper = ticker.upper()
if ticker_upper in alternatives:
return alternatives[ticker_upper]
# Common patterns
suggestions = []
if '.' in ticker:
suggestions.append(ticker.replace('.', '-'))
if '-' in ticker:
suggestions.append(ticker.replace('-', '.'))
return suggestions
def diagnose_failed_tickers(failed_tickers: list):
"""Diagnose multiple failed tickers."""
print("🔍 TICKER FAILURE DIAGNOSTICS")
print("=" * 50)
results = {}
for ticker in failed_tickers:
result = diagnose_ticker(ticker)
results[ticker] = result
# Check alternatives
alternatives = check_ticker_alternatives(ticker)
if alternatives:
print(f"\n💡 Suggested alternatives for {ticker}:")
for alt in alternatives:
print(f" • {alt}")
print(f"\n📋 SUMMARY RECOMMENDATIONS:")
print("=" * 40)
for ticker, result in results.items():
print(f"\n{ticker}:")
if result['recommendation']:
print(f" 💡 {result['recommendation']}")
if result['issues']:
print(f" ⚠️ Issues: {', '.join(result['issues'])}")
return results
if __name__ == "__main__":
# Test the failed tickers
failed_tickers = ['SQ', 'TWTR']
diagnose_failed_tickers(failed_tickers)