Spaces:
Paused
Paused
Tonic commited on
fix covariate and model training issues
Browse files
app.py
CHANGED
|
@@ -3528,11 +3528,17 @@ def get_enhanced_covariate_data(symbol: str, timeframe: str = "1d", lookback_day
|
|
| 3528 |
))
|
| 3529 |
if not data.empty:
|
| 3530 |
market_data[index] = data['Close']
|
|
|
|
|
|
|
|
|
|
| 3531 |
except Exception as e:
|
| 3532 |
-
print(f"Error fetching {index}: {str(e)}")
|
| 3533 |
|
| 3534 |
if market_data:
|
| 3535 |
covariate_data['market_indices'] = pd.DataFrame(market_data)
|
|
|
|
|
|
|
|
|
|
| 3536 |
|
| 3537 |
# Collect sector data
|
| 3538 |
print("Collecting sector data...")
|
|
@@ -3545,11 +3551,17 @@ def get_enhanced_covariate_data(symbol: str, timeframe: str = "1d", lookback_day
|
|
| 3545 |
))
|
| 3546 |
if not data.empty:
|
| 3547 |
sector_data[sector] = data['Close']
|
|
|
|
|
|
|
|
|
|
| 3548 |
except Exception as e:
|
| 3549 |
-
print(f"Error fetching {sector}: {str(e)}")
|
| 3550 |
|
| 3551 |
if sector_data:
|
| 3552 |
covariate_data['sectors'] = pd.DataFrame(sector_data)
|
|
|
|
|
|
|
|
|
|
| 3553 |
|
| 3554 |
# Collect economic indicators
|
| 3555 |
print("Collecting economic indicators...")
|
|
@@ -3562,11 +3574,17 @@ def get_enhanced_covariate_data(symbol: str, timeframe: str = "1d", lookback_day
|
|
| 3562 |
))
|
| 3563 |
if not data.empty:
|
| 3564 |
economic_data[indicator] = data['Close']
|
|
|
|
|
|
|
|
|
|
| 3565 |
except Exception as e:
|
| 3566 |
-
print(f"Error fetching {indicator} ({ticker_symbol}): {str(e)}")
|
| 3567 |
|
| 3568 |
if economic_data:
|
| 3569 |
covariate_data['economic_indicators'] = pd.DataFrame(economic_data)
|
|
|
|
|
|
|
|
|
|
| 3570 |
|
| 3571 |
return covariate_data
|
| 3572 |
|
|
@@ -3711,12 +3729,13 @@ def create_enhanced_ensemble_model(df: pd.DataFrame, covariate_data: Dict,
|
|
| 3711 |
target = df['Close'].values
|
| 3712 |
|
| 3713 |
# Technical indicators as features
|
| 3714 |
-
features.append(df['RSI'].values)
|
| 3715 |
-
features.append(df['MACD'].values)
|
| 3716 |
-
features.append(df['Volatility'].values)
|
| 3717 |
|
| 3718 |
if 'BB_Upper' in df.columns:
|
| 3719 |
bb_position = (df['Close'] - df['BB_Lower']) / (df['BB_Upper'] - df['BB_Lower'])
|
|
|
|
| 3720 |
features.append(bb_position.values)
|
| 3721 |
|
| 3722 |
# Add covariate data
|
|
@@ -3725,32 +3744,44 @@ def create_enhanced_ensemble_model(df: pd.DataFrame, covariate_data: Dict,
|
|
| 3725 |
covariate_series = covariate_data['market_indices'][col]
|
| 3726 |
# Align covariate data to target length
|
| 3727 |
if len(covariate_series) == len(target):
|
| 3728 |
-
|
|
|
|
|
|
|
| 3729 |
elif len(covariate_series) > len(target):
|
| 3730 |
# Truncate to target length
|
| 3731 |
-
|
|
|
|
|
|
|
| 3732 |
else:
|
| 3733 |
# Pad with last value
|
| 3734 |
padded_values = np.pad(covariate_series.values,
|
| 3735 |
(len(target) - len(covariate_series), 0),
|
| 3736 |
mode='edge')
|
| 3737 |
-
|
|
|
|
|
|
|
| 3738 |
|
| 3739 |
if 'economic_indicators' in covariate_data:
|
| 3740 |
for col in covariate_data['economic_indicators'].columns:
|
| 3741 |
covariate_series = covariate_data['economic_indicators'][col]
|
| 3742 |
# Align covariate data to target length
|
| 3743 |
if len(covariate_series) == len(target):
|
| 3744 |
-
|
|
|
|
|
|
|
| 3745 |
elif len(covariate_series) > len(target):
|
| 3746 |
# Truncate to target length
|
| 3747 |
-
|
|
|
|
|
|
|
| 3748 |
else:
|
| 3749 |
# Pad with last value
|
| 3750 |
padded_values = np.pad(covariate_series.values,
|
| 3751 |
(len(target) - len(covariate_series), 0),
|
| 3752 |
mode='edge')
|
| 3753 |
-
|
|
|
|
|
|
|
| 3754 |
|
| 3755 |
# Create feature matrix
|
| 3756 |
X = np.column_stack(features)
|
|
@@ -3770,15 +3801,73 @@ def create_enhanced_ensemble_model(df: pd.DataFrame, covariate_data: Dict,
|
|
| 3770 |
print(f"Truncated to minimum length: {min_length}")
|
| 3771 |
|
| 3772 |
# Remove any NaN values
|
| 3773 |
-
|
| 3774 |
-
|
| 3775 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3776 |
|
| 3777 |
print(f"After NaN removal - X shape: {X.shape}, y shape: {y.shape}")
|
| 3778 |
|
| 3779 |
if len(X) < 50: # Need sufficient data
|
| 3780 |
print(f"Insufficient data after preprocessing: {len(X)} samples")
|
| 3781 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3782 |
|
| 3783 |
# Initialize models
|
| 3784 |
models = {
|
|
|
|
| 3528 |
))
|
| 3529 |
if not data.empty:
|
| 3530 |
market_data[index] = data['Close']
|
| 3531 |
+
print(f" Successfully collected {index}: {len(data)} data points")
|
| 3532 |
+
else:
|
| 3533 |
+
print(f" No data for {index}")
|
| 3534 |
except Exception as e:
|
| 3535 |
+
print(f" Error fetching {index}: {str(e)}")
|
| 3536 |
|
| 3537 |
if market_data:
|
| 3538 |
covariate_data['market_indices'] = pd.DataFrame(market_data)
|
| 3539 |
+
print(f"Market indices data shape: {covariate_data['market_indices'].shape}")
|
| 3540 |
+
else:
|
| 3541 |
+
print("No market indices data collected")
|
| 3542 |
|
| 3543 |
# Collect sector data
|
| 3544 |
print("Collecting sector data...")
|
|
|
|
| 3551 |
))
|
| 3552 |
if not data.empty:
|
| 3553 |
sector_data[sector] = data['Close']
|
| 3554 |
+
print(f" Successfully collected {sector}: {len(data)} data points")
|
| 3555 |
+
else:
|
| 3556 |
+
print(f" No data for {sector}")
|
| 3557 |
except Exception as e:
|
| 3558 |
+
print(f" Error fetching {sector}: {str(e)}")
|
| 3559 |
|
| 3560 |
if sector_data:
|
| 3561 |
covariate_data['sectors'] = pd.DataFrame(sector_data)
|
| 3562 |
+
print(f"Sector data shape: {covariate_data['sectors'].shape}")
|
| 3563 |
+
else:
|
| 3564 |
+
print("No sector data collected")
|
| 3565 |
|
| 3566 |
# Collect economic indicators
|
| 3567 |
print("Collecting economic indicators...")
|
|
|
|
| 3574 |
))
|
| 3575 |
if not data.empty:
|
| 3576 |
economic_data[indicator] = data['Close']
|
| 3577 |
+
print(f" Successfully collected {indicator} ({ticker_symbol}): {len(data)} data points")
|
| 3578 |
+
else:
|
| 3579 |
+
print(f" No data for {indicator} ({ticker_symbol})")
|
| 3580 |
except Exception as e:
|
| 3581 |
+
print(f" Error fetching {indicator} ({ticker_symbol}): {str(e)}")
|
| 3582 |
|
| 3583 |
if economic_data:
|
| 3584 |
covariate_data['economic_indicators'] = pd.DataFrame(economic_data)
|
| 3585 |
+
print(f"Economic indicators data shape: {covariate_data['economic_indicators'].shape}")
|
| 3586 |
+
else:
|
| 3587 |
+
print("No economic indicators data collected")
|
| 3588 |
|
| 3589 |
return covariate_data
|
| 3590 |
|
|
|
|
| 3729 |
target = df['Close'].values
|
| 3730 |
|
| 3731 |
# Technical indicators as features
|
| 3732 |
+
features.append(df['RSI'].fillna(50).values) # Fill NaN with neutral RSI value
|
| 3733 |
+
features.append(df['MACD'].fillna(0).values) # Fill NaN with zero
|
| 3734 |
+
features.append(df['Volatility'].fillna(df['Volatility'].mean()).values) # Fill with mean volatility
|
| 3735 |
|
| 3736 |
if 'BB_Upper' in df.columns:
|
| 3737 |
bb_position = (df['Close'] - df['BB_Lower']) / (df['BB_Upper'] - df['BB_Lower'])
|
| 3738 |
+
bb_position = bb_position.fillna(0.5) # Fill NaN with neutral position
|
| 3739 |
features.append(bb_position.values)
|
| 3740 |
|
| 3741 |
# Add covariate data
|
|
|
|
| 3744 |
covariate_series = covariate_data['market_indices'][col]
|
| 3745 |
# Align covariate data to target length
|
| 3746 |
if len(covariate_series) == len(target):
|
| 3747 |
+
# Fill NaN values with forward fill, then backward fill
|
| 3748 |
+
filled_series = covariate_series.fillna(method='ffill').fillna(method='bfill')
|
| 3749 |
+
features.append(filled_series.values)
|
| 3750 |
elif len(covariate_series) > len(target):
|
| 3751 |
# Truncate to target length
|
| 3752 |
+
truncated_series = covariate_series.tail(len(target))
|
| 3753 |
+
filled_series = truncated_series.fillna(method='ffill').fillna(method='bfill')
|
| 3754 |
+
features.append(filled_series.values)
|
| 3755 |
else:
|
| 3756 |
# Pad with last value
|
| 3757 |
padded_values = np.pad(covariate_series.values,
|
| 3758 |
(len(target) - len(covariate_series), 0),
|
| 3759 |
mode='edge')
|
| 3760 |
+
# Fill any remaining NaN values
|
| 3761 |
+
filled_values = pd.Series(padded_values).fillna(method='ffill').fillna(method='bfill').values
|
| 3762 |
+
features.append(filled_values)
|
| 3763 |
|
| 3764 |
if 'economic_indicators' in covariate_data:
|
| 3765 |
for col in covariate_data['economic_indicators'].columns:
|
| 3766 |
covariate_series = covariate_data['economic_indicators'][col]
|
| 3767 |
# Align covariate data to target length
|
| 3768 |
if len(covariate_series) == len(target):
|
| 3769 |
+
# Fill NaN values with forward fill, then backward fill
|
| 3770 |
+
filled_series = covariate_series.fillna(method='ffill').fillna(method='bfill')
|
| 3771 |
+
features.append(filled_series.values)
|
| 3772 |
elif len(covariate_series) > len(target):
|
| 3773 |
# Truncate to target length
|
| 3774 |
+
truncated_series = covariate_series.tail(len(target))
|
| 3775 |
+
filled_series = truncated_series.fillna(method='ffill').fillna(method='bfill')
|
| 3776 |
+
features.append(filled_series.values)
|
| 3777 |
else:
|
| 3778 |
# Pad with last value
|
| 3779 |
padded_values = np.pad(covariate_series.values,
|
| 3780 |
(len(target) - len(covariate_series), 0),
|
| 3781 |
mode='edge')
|
| 3782 |
+
# Fill any remaining NaN values
|
| 3783 |
+
filled_values = pd.Series(padded_values).fillna(method='ffill').fillna(method='bfill').values
|
| 3784 |
+
features.append(filled_values)
|
| 3785 |
|
| 3786 |
# Create feature matrix
|
| 3787 |
X = np.column_stack(features)
|
|
|
|
| 3801 |
print(f"Truncated to minimum length: {min_length}")
|
| 3802 |
|
| 3803 |
# Remove any NaN values
|
| 3804 |
+
print(f"Checking for NaN values in feature matrix...")
|
| 3805 |
+
nan_rows = np.isnan(X).any(axis=1)
|
| 3806 |
+
nan_count = nan_rows.sum()
|
| 3807 |
+
print(f"Found {nan_count} rows with NaN values out of {len(X)} total rows")
|
| 3808 |
+
|
| 3809 |
+
if nan_count > 0:
|
| 3810 |
+
# Check which features have NaN values
|
| 3811 |
+
for i, feature_name in enumerate(['RSI', 'MACD', 'Volatility', 'BB_Position'] +
|
| 3812 |
+
[f'Market_{j}' for j in range(len(features)-4)]):
|
| 3813 |
+
if i < X.shape[1]:
|
| 3814 |
+
nan_count_feature = np.isnan(X[:, i]).sum()
|
| 3815 |
+
if nan_count_feature > 0:
|
| 3816 |
+
print(f" Feature {feature_name}: {nan_count_feature} NaN values")
|
| 3817 |
+
|
| 3818 |
+
# Only remove rows if there are still NaN values after filling
|
| 3819 |
+
if nan_count > 0:
|
| 3820 |
+
mask = ~np.isnan(X).any(axis=1) & ~np.isnan(y)
|
| 3821 |
+
X = X[mask]
|
| 3822 |
+
y = y[mask]
|
| 3823 |
+
print(f"Removed {nan_count} rows with NaN values")
|
| 3824 |
+
else:
|
| 3825 |
+
print("No NaN values found in feature matrix")
|
| 3826 |
|
| 3827 |
print(f"After NaN removal - X shape: {X.shape}, y shape: {y.shape}")
|
| 3828 |
|
| 3829 |
if len(X) < 50: # Need sufficient data
|
| 3830 |
print(f"Insufficient data after preprocessing: {len(X)} samples")
|
| 3831 |
+
print("This might be due to:")
|
| 3832 |
+
print("1. Too many NaN values in covariate data")
|
| 3833 |
+
print("2. Insufficient historical data")
|
| 3834 |
+
print("3. Data alignment issues")
|
| 3835 |
+
print("Trying fallback with technical indicators only...")
|
| 3836 |
+
|
| 3837 |
+
# Fallback: Use only technical indicators
|
| 3838 |
+
try:
|
| 3839 |
+
fallback_features = []
|
| 3840 |
+
fallback_features.append(df['RSI'].fillna(50).values)
|
| 3841 |
+
fallback_features.append(df['MACD'].fillna(0).values)
|
| 3842 |
+
fallback_features.append(df['Volatility'].fillna(df['Volatility'].mean()).values)
|
| 3843 |
+
|
| 3844 |
+
if 'BB_Upper' in df.columns:
|
| 3845 |
+
bb_position = (df['Close'] - df['BB_Lower']) / (df['BB_Upper'] - df['BB_Lower'])
|
| 3846 |
+
bb_position = bb_position.fillna(0.5)
|
| 3847 |
+
fallback_features.append(bb_position.values)
|
| 3848 |
+
|
| 3849 |
+
X_fallback = np.column_stack(fallback_features)
|
| 3850 |
+
y_fallback = df['Close'].values
|
| 3851 |
+
|
| 3852 |
+
# Remove any remaining NaN values
|
| 3853 |
+
mask = ~np.isnan(X_fallback).any(axis=1) & ~np.isnan(y_fallback)
|
| 3854 |
+
X_fallback = X_fallback[mask]
|
| 3855 |
+
y_fallback = y_fallback[mask]
|
| 3856 |
+
|
| 3857 |
+
print(f"Fallback feature matrix shape: {X_fallback.shape}")
|
| 3858 |
+
|
| 3859 |
+
if len(X_fallback) >= 50:
|
| 3860 |
+
print("Using fallback ensemble with technical indicators only")
|
| 3861 |
+
# Use the fallback data for the rest of the function
|
| 3862 |
+
X = X_fallback
|
| 3863 |
+
y = y_fallback
|
| 3864 |
+
else:
|
| 3865 |
+
print("Fallback also failed, returning empty arrays")
|
| 3866 |
+
return np.array([]), np.array([])
|
| 3867 |
+
|
| 3868 |
+
except Exception as fallback_error:
|
| 3869 |
+
print(f"Fallback failed: {str(fallback_error)}")
|
| 3870 |
+
return np.array([]), np.array([])
|
| 3871 |
|
| 3872 |
# Initialize models
|
| 3873 |
models = {
|