Spaces:
Paused
Paused
Tonic commited on
fix news sentiment covariate , volume prediction , yfinance fallbacks, adds advanced trading signals
Browse files
app.py
CHANGED
|
@@ -385,7 +385,7 @@ ECONOMIC_INDICATORS = {
|
|
| 385 |
|
| 386 |
def retry_yfinance_request(func, max_retries=3, initial_delay=1):
|
| 387 |
"""
|
| 388 |
-
Retry mechanism for yfinance requests with exponential backoff.
|
| 389 |
|
| 390 |
Args:
|
| 391 |
func: Function to retry
|
|
@@ -399,12 +399,36 @@ def retry_yfinance_request(func, max_retries=3, initial_delay=1):
|
|
| 399 |
try:
|
| 400 |
return func()
|
| 401 |
except Exception as e:
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 408 |
|
| 409 |
def clear_gpu_memory():
|
| 410 |
"""Clear GPU memory cache"""
|
|
@@ -1453,6 +1477,12 @@ def make_prediction_enhanced(symbol: str, timeframe: str = "1d", prediction_days
|
|
| 1453 |
df, mean_pred, covariate_data
|
| 1454 |
)
|
| 1455 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1456 |
# Predict technical indicators
|
| 1457 |
print("Predicting technical indicators...")
|
| 1458 |
technical_predictions = predict_technical_indicators(df, mean_pred, timeframe)
|
|
@@ -1549,6 +1579,12 @@ def make_prediction_enhanced(symbol: str, timeframe: str = "1d", prediction_days
|
|
| 1549 |
df, final_pred, covariate_data
|
| 1550 |
)
|
| 1551 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1552 |
# Predict technical indicators
|
| 1553 |
print("Predicting technical indicators for technical strategy...")
|
| 1554 |
technical_predictions = predict_technical_indicators(df, final_pred, timeframe)
|
|
@@ -1804,6 +1840,38 @@ def make_prediction_enhanced(symbol: str, timeframe: str = "1d", prediction_days
|
|
| 1804 |
'covariate_data_available': len(covariate_data) > 0
|
| 1805 |
}
|
| 1806 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1807 |
return trading_signals, fig
|
| 1808 |
|
| 1809 |
except Exception as e:
|
|
@@ -3552,6 +3620,7 @@ def get_enhanced_covariate_data(symbol: str, timeframe: str = "1d", lookback_day
|
|
| 3552 |
print(f" No data for {index}")
|
| 3553 |
except Exception as e:
|
| 3554 |
print(f" Error fetching {index}: {str(e)}")
|
|
|
|
| 3555 |
|
| 3556 |
if market_data:
|
| 3557 |
covariate_data['market_indices'] = pd.DataFrame(market_data)
|
|
@@ -3575,6 +3644,7 @@ def get_enhanced_covariate_data(symbol: str, timeframe: str = "1d", lookback_day
|
|
| 3575 |
print(f" No data for {sector}")
|
| 3576 |
except Exception as e:
|
| 3577 |
print(f" Error fetching {sector}: {str(e)}")
|
|
|
|
| 3578 |
|
| 3579 |
if sector_data:
|
| 3580 |
covariate_data['sectors'] = pd.DataFrame(sector_data)
|
|
@@ -3598,6 +3668,7 @@ def get_enhanced_covariate_data(symbol: str, timeframe: str = "1d", lookback_day
|
|
| 3598 |
print(f" No data for {indicator} ({ticker_symbol})")
|
| 3599 |
except Exception as e:
|
| 3600 |
print(f" Error fetching {indicator} ({ticker_symbol}): {str(e)}")
|
|
|
|
| 3601 |
|
| 3602 |
if economic_data:
|
| 3603 |
covariate_data['economic_indicators'] = pd.DataFrame(economic_data)
|
|
@@ -3605,10 +3676,15 @@ def get_enhanced_covariate_data(symbol: str, timeframe: str = "1d", lookback_day
|
|
| 3605 |
else:
|
| 3606 |
print("No economic indicators data collected")
|
| 3607 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3608 |
return covariate_data
|
| 3609 |
|
| 3610 |
except Exception as e:
|
| 3611 |
print(f"Error collecting covariate data: {str(e)}")
|
|
|
|
| 3612 |
return {}
|
| 3613 |
|
| 3614 |
def calculate_market_sentiment(symbol: str, lookback_days: int = 30) -> Dict[str, float]:
|
|
@@ -3631,7 +3707,7 @@ def calculate_market_sentiment(symbol: str, lookback_days: int = 30) -> Dict[str
|
|
| 3631 |
# Get news sentiment (simplified approach using yfinance news)
|
| 3632 |
try:
|
| 3633 |
ticker = yf.Ticker(symbol)
|
| 3634 |
-
news = ticker.news
|
| 3635 |
|
| 3636 |
if news:
|
| 3637 |
for article in news[:10]: # Analyze last 10 news articles
|
|
@@ -3644,6 +3720,7 @@ def calculate_market_sentiment(symbol: str, lookback_days: int = 30) -> Dict[str
|
|
| 3644 |
sentiment_scores.append(blob.sentiment.polarity)
|
| 3645 |
except Exception as e:
|
| 3646 |
print(f"Error fetching news sentiment: {str(e)}")
|
|
|
|
| 3647 |
|
| 3648 |
# Calculate average sentiment
|
| 3649 |
if sentiment_scores:
|
|
@@ -3661,7 +3738,13 @@ def calculate_market_sentiment(symbol: str, lookback_days: int = 30) -> Dict[str
|
|
| 3661 |
|
| 3662 |
except Exception as e:
|
| 3663 |
print(f"Error calculating sentiment: {str(e)}")
|
| 3664 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3665 |
|
| 3666 |
def calculate_advanced_uncertainty(quantiles: np.ndarray, historical_volatility: float,
|
| 3667 |
market_conditions: Dict = None, confidence_level: float = 0.9) -> Dict[str, np.ndarray]:
|
|
@@ -4261,11 +4344,11 @@ def get_market_info_from_yfinance(symbol: str) -> Dict:
|
|
| 4261 |
try:
|
| 4262 |
ticker = yf.Ticker(symbol)
|
| 4263 |
|
| 4264 |
-
# Get basic info
|
| 4265 |
-
info = ticker.info
|
| 4266 |
|
| 4267 |
-
# Get current market data
|
| 4268 |
-
hist = ticker.history(period="1d")
|
| 4269 |
|
| 4270 |
# Get additional market data
|
| 4271 |
market_data = {}
|
|
@@ -4281,25 +4364,28 @@ def get_market_info_from_yfinance(symbol: str) -> Dict:
|
|
| 4281 |
'change_percent': ((hist['Close'].iloc[-1] - hist['Open'].iloc[-1]) / hist['Open'].iloc[-1]) * 100
|
| 4282 |
})
|
| 4283 |
|
| 4284 |
-
# Get news if available
|
| 4285 |
try:
|
| 4286 |
-
news = ticker.news
|
| 4287 |
market_data['news_count'] = len(news) if news else 0
|
| 4288 |
-
except:
|
|
|
|
| 4289 |
market_data['news_count'] = 0
|
| 4290 |
|
| 4291 |
-
# Get recommendations if available
|
| 4292 |
try:
|
| 4293 |
-
recommendations = ticker.recommendations
|
| 4294 |
market_data['recommendations'] = recommendations.tail(5).to_dict('records') if not recommendations.empty else []
|
| 4295 |
-
except:
|
|
|
|
| 4296 |
market_data['recommendations'] = []
|
| 4297 |
|
| 4298 |
-
# Get earnings info if available
|
| 4299 |
try:
|
| 4300 |
-
earnings = ticker.earnings
|
| 4301 |
market_data['earnings'] = earnings.tail(4).to_dict('records') if not earnings.empty else []
|
| 4302 |
-
except:
|
|
|
|
| 4303 |
market_data['earnings'] = []
|
| 4304 |
|
| 4305 |
# Combine all data
|
|
@@ -4313,6 +4399,7 @@ def get_market_info_from_yfinance(symbol: str) -> Dict:
|
|
| 4313 |
return result
|
| 4314 |
|
| 4315 |
except Exception as e:
|
|
|
|
| 4316 |
return {
|
| 4317 |
'symbol': symbol,
|
| 4318 |
'error': str(e),
|
|
|
|
| 385 |
|
| 386 |
def retry_yfinance_request(func, max_retries=3, initial_delay=1):
|
| 387 |
"""
|
| 388 |
+
Retry mechanism for yfinance requests with exponential backoff up to 8 seconds.
|
| 389 |
|
| 390 |
Args:
|
| 391 |
func: Function to retry
|
|
|
|
| 399 |
try:
|
| 400 |
return func()
|
| 401 |
except Exception as e:
|
| 402 |
+
error_str = str(e).lower()
|
| 403 |
+
|
| 404 |
+
# Check if this is the last attempt
|
| 405 |
+
if attempt == max_retries - 1:
|
| 406 |
+
print(f"Final attempt failed after {max_retries} retries: {str(e)}")
|
| 407 |
+
raise e
|
| 408 |
+
|
| 409 |
+
# Determine delay based on error type and attempt number
|
| 410 |
+
if "401" in error_str or "unauthorized" in error_str:
|
| 411 |
+
# Authentication errors - longer delay
|
| 412 |
+
delay = min(8.0, initial_delay * (2 ** attempt) + random.uniform(0, 2))
|
| 413 |
+
print(f"Authentication error (attempt {attempt + 1}/{max_retries}), retrying in {delay:.2f}s: {str(e)}")
|
| 414 |
+
elif "429" in error_str or "rate limit" in error_str or "too many requests" in error_str:
|
| 415 |
+
# Rate limiting - longer delay
|
| 416 |
+
delay = min(8.0, initial_delay * (2 ** attempt) + random.uniform(1, 3))
|
| 417 |
+
print(f"Rate limit error (attempt {attempt + 1}/{max_retries}), retrying in {delay:.2f}s: {str(e)}")
|
| 418 |
+
elif "500" in error_str or "502" in error_str or "503" in error_str or "504" in error_str:
|
| 419 |
+
# Server errors - moderate delay
|
| 420 |
+
delay = min(8.0, initial_delay * (2 ** attempt) + random.uniform(0.5, 1.5))
|
| 421 |
+
print(f"Server error (attempt {attempt + 1}/{max_retries}), retrying in {delay:.2f}s: {str(e)}")
|
| 422 |
+
elif "timeout" in error_str or "connection" in error_str:
|
| 423 |
+
# Network errors - shorter delay
|
| 424 |
+
delay = min(8.0, initial_delay * (2 ** attempt) + random.uniform(0, 1))
|
| 425 |
+
print(f"Network error (attempt {attempt + 1}/{max_retries}), retrying in {delay:.2f}s: {str(e)}")
|
| 426 |
+
else:
|
| 427 |
+
# Generic errors - standard exponential backoff
|
| 428 |
+
delay = min(8.0, initial_delay * (2 ** attempt) + random.uniform(0, 1))
|
| 429 |
+
print(f"Generic error (attempt {attempt + 1}/{max_retries}), retrying in {delay:.2f}s: {str(e)}")
|
| 430 |
+
|
| 431 |
+
time.sleep(delay)
|
| 432 |
|
| 433 |
def clear_gpu_memory():
|
| 434 |
"""Clear GPU memory cache"""
|
|
|
|
| 1477 |
df, mean_pred, covariate_data
|
| 1478 |
)
|
| 1479 |
|
| 1480 |
+
# Ensure volume prediction is properly handled
|
| 1481 |
+
if volume_pred is None or len(volume_pred) == 0:
|
| 1482 |
+
print("Warning: Volume prediction failed, using fallback")
|
| 1483 |
+
volume_pred = np.full(len(mean_pred), df['Volume'].iloc[-1])
|
| 1484 |
+
volume_uncertainty = np.full(len(mean_pred), df['Volume'].iloc[-1] * 0.2)
|
| 1485 |
+
|
| 1486 |
# Predict technical indicators
|
| 1487 |
print("Predicting technical indicators...")
|
| 1488 |
technical_predictions = predict_technical_indicators(df, mean_pred, timeframe)
|
|
|
|
| 1579 |
df, final_pred, covariate_data
|
| 1580 |
)
|
| 1581 |
|
| 1582 |
+
# Ensure volume prediction is properly handled
|
| 1583 |
+
if volume_pred is None or len(volume_pred) == 0:
|
| 1584 |
+
print("Warning: Volume prediction failed in technical strategy, using fallback")
|
| 1585 |
+
volume_pred = np.full(len(final_pred), df['Volume'].iloc[-1])
|
| 1586 |
+
volume_uncertainty = np.full(len(final_pred), df['Volume'].iloc[-1] * 0.2)
|
| 1587 |
+
|
| 1588 |
# Predict technical indicators
|
| 1589 |
print("Predicting technical indicators for technical strategy...")
|
| 1590 |
technical_predictions = predict_technical_indicators(df, final_pred, timeframe)
|
|
|
|
| 1840 |
'covariate_data_available': len(covariate_data) > 0
|
| 1841 |
}
|
| 1842 |
|
| 1843 |
+
# Add stress testing results if enabled
|
| 1844 |
+
stress_test_results = {}
|
| 1845 |
+
if use_stress_testing:
|
| 1846 |
+
try:
|
| 1847 |
+
print("Performing stress testing...")
|
| 1848 |
+
stress_test_results = stress_test_scenarios(df, final_pred)
|
| 1849 |
+
trading_signals['stress_test_results'] = stress_test_results
|
| 1850 |
+
except Exception as stress_error:
|
| 1851 |
+
print(f"Stress testing failed: {str(stress_error)}")
|
| 1852 |
+
trading_signals['stress_test_results'] = {"error": str(stress_error)}
|
| 1853 |
+
|
| 1854 |
+
# Add advanced trading signals
|
| 1855 |
+
try:
|
| 1856 |
+
print("Generating advanced trading signals...")
|
| 1857 |
+
advanced_signals = advanced_trading_signals(df, regime_info)
|
| 1858 |
+
trading_signals['advanced_signals'] = advanced_signals
|
| 1859 |
+
except Exception as advanced_error:
|
| 1860 |
+
print(f"Advanced trading signals failed: {str(advanced_error)}")
|
| 1861 |
+
trading_signals['advanced_signals'] = {"error": str(advanced_error)}
|
| 1862 |
+
|
| 1863 |
+
# Add basic trading signals
|
| 1864 |
+
try:
|
| 1865 |
+
basic_signals = calculate_trading_signals(df)
|
| 1866 |
+
trading_signals.update(basic_signals)
|
| 1867 |
+
trading_signals['symbol'] = symbol
|
| 1868 |
+
trading_signals['timeframe'] = timeframe
|
| 1869 |
+
trading_signals['strategy_used'] = strategy
|
| 1870 |
+
trading_signals['ensemble_used'] = use_ensemble
|
| 1871 |
+
except Exception as basic_error:
|
| 1872 |
+
print(f"Basic trading signals failed: {str(basic_error)}")
|
| 1873 |
+
trading_signals['error'] = str(basic_error)
|
| 1874 |
+
|
| 1875 |
return trading_signals, fig
|
| 1876 |
|
| 1877 |
except Exception as e:
|
|
|
|
| 3620 |
print(f" No data for {index}")
|
| 3621 |
except Exception as e:
|
| 3622 |
print(f" Error fetching {index}: {str(e)}")
|
| 3623 |
+
# Continue with other indices even if one fails
|
| 3624 |
|
| 3625 |
if market_data:
|
| 3626 |
covariate_data['market_indices'] = pd.DataFrame(market_data)
|
|
|
|
| 3644 |
print(f" No data for {sector}")
|
| 3645 |
except Exception as e:
|
| 3646 |
print(f" Error fetching {sector}: {str(e)}")
|
| 3647 |
+
# Continue with other sectors even if one fails
|
| 3648 |
|
| 3649 |
if sector_data:
|
| 3650 |
covariate_data['sectors'] = pd.DataFrame(sector_data)
|
|
|
|
| 3668 |
print(f" No data for {indicator} ({ticker_symbol})")
|
| 3669 |
except Exception as e:
|
| 3670 |
print(f" Error fetching {indicator} ({ticker_symbol}): {str(e)}")
|
| 3671 |
+
# Continue with other indicators even if one fails
|
| 3672 |
|
| 3673 |
if economic_data:
|
| 3674 |
covariate_data['economic_indicators'] = pd.DataFrame(economic_data)
|
|
|
|
| 3676 |
else:
|
| 3677 |
print("No economic indicators data collected")
|
| 3678 |
|
| 3679 |
+
# Return whatever data we were able to collect
|
| 3680 |
+
if not covariate_data:
|
| 3681 |
+
print("Warning: No covariate data collected, returning empty dict")
|
| 3682 |
+
|
| 3683 |
return covariate_data
|
| 3684 |
|
| 3685 |
except Exception as e:
|
| 3686 |
print(f"Error collecting covariate data: {str(e)}")
|
| 3687 |
+
# Return empty dict instead of failing completely
|
| 3688 |
return {}
|
| 3689 |
|
| 3690 |
def calculate_market_sentiment(symbol: str, lookback_days: int = 30) -> Dict[str, float]:
|
|
|
|
| 3707 |
# Get news sentiment (simplified approach using yfinance news)
|
| 3708 |
try:
|
| 3709 |
ticker = yf.Ticker(symbol)
|
| 3710 |
+
news = retry_yfinance_request(lambda: ticker.news)
|
| 3711 |
|
| 3712 |
if news:
|
| 3713 |
for article in news[:10]: # Analyze last 10 news articles
|
|
|
|
| 3720 |
sentiment_scores.append(blob.sentiment.polarity)
|
| 3721 |
except Exception as e:
|
| 3722 |
print(f"Error fetching news sentiment: {str(e)}")
|
| 3723 |
+
# Don't fail completely, just log the error
|
| 3724 |
|
| 3725 |
# Calculate average sentiment
|
| 3726 |
if sentiment_scores:
|
|
|
|
| 3738 |
|
| 3739 |
except Exception as e:
|
| 3740 |
print(f"Error calculating sentiment: {str(e)}")
|
| 3741 |
+
# Return neutral sentiment on error
|
| 3742 |
+
return {
|
| 3743 |
+
'sentiment_score': 0.0,
|
| 3744 |
+
'sentiment_confidence': 0.0,
|
| 3745 |
+
'sentiment_samples': 0,
|
| 3746 |
+
'error': str(e)
|
| 3747 |
+
}
|
| 3748 |
|
| 3749 |
def calculate_advanced_uncertainty(quantiles: np.ndarray, historical_volatility: float,
|
| 3750 |
market_conditions: Dict = None, confidence_level: float = 0.9) -> Dict[str, np.ndarray]:
|
|
|
|
| 4344 |
try:
|
| 4345 |
ticker = yf.Ticker(symbol)
|
| 4346 |
|
| 4347 |
+
# Get basic info with retry
|
| 4348 |
+
info = retry_yfinance_request(lambda: ticker.info)
|
| 4349 |
|
| 4350 |
+
# Get current market data with retry
|
| 4351 |
+
hist = retry_yfinance_request(lambda: ticker.history(period="1d"))
|
| 4352 |
|
| 4353 |
# Get additional market data
|
| 4354 |
market_data = {}
|
|
|
|
| 4364 |
'change_percent': ((hist['Close'].iloc[-1] - hist['Open'].iloc[-1]) / hist['Open'].iloc[-1]) * 100
|
| 4365 |
})
|
| 4366 |
|
| 4367 |
+
# Get news if available with retry
|
| 4368 |
try:
|
| 4369 |
+
news = retry_yfinance_request(lambda: ticker.news)
|
| 4370 |
market_data['news_count'] = len(news) if news else 0
|
| 4371 |
+
except Exception as e:
|
| 4372 |
+
print(f"Error fetching news for {symbol}: {str(e)}")
|
| 4373 |
market_data['news_count'] = 0
|
| 4374 |
|
| 4375 |
+
# Get recommendations if available with retry
|
| 4376 |
try:
|
| 4377 |
+
recommendations = retry_yfinance_request(lambda: ticker.recommendations)
|
| 4378 |
market_data['recommendations'] = recommendations.tail(5).to_dict('records') if not recommendations.empty else []
|
| 4379 |
+
except Exception as e:
|
| 4380 |
+
print(f"Error fetching recommendations for {symbol}: {str(e)}")
|
| 4381 |
market_data['recommendations'] = []
|
| 4382 |
|
| 4383 |
+
# Get earnings info if available with retry
|
| 4384 |
try:
|
| 4385 |
+
earnings = retry_yfinance_request(lambda: ticker.earnings)
|
| 4386 |
market_data['earnings'] = earnings.tail(4).to_dict('records') if not earnings.empty else []
|
| 4387 |
+
except Exception as e:
|
| 4388 |
+
print(f"Error fetching earnings for {symbol}: {str(e)}")
|
| 4389 |
market_data['earnings'] = []
|
| 4390 |
|
| 4391 |
# Combine all data
|
|
|
|
| 4399 |
return result
|
| 4400 |
|
| 4401 |
except Exception as e:
|
| 4402 |
+
print(f"Error fetching market info for {symbol}: {str(e)}")
|
| 4403 |
return {
|
| 4404 |
'symbol': symbol,
|
| 4405 |
'error': str(e),
|