The model training finished properly, but while trying to 'Use' the model, i got error . Here is the complete code and the error i got :

import pandas as pd
import numpy as np
import yfinance as yf
import matplotlib.pyplot as plt
import datetime
import sys
import os

from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.model_selection import train_test_split, GridSearchCV, StratifiedKFold
from sklearn.metrics import (
    classification_report, roc_auc_score, roc_curve, precision_recall_curve,
    average_precision_score, confusion_matrix, f1_score
)
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC

import xgboost as xgb

from imblearn.over_sampling import SMOTE

# Keep the imports unchanged, as per your request
# ************************************************
import tensorflow as tf
from tensorflow import keras

from keras.layers import Dense
from keras.optimizers import Adam
from keras.models import Sequential
# ************************************************

# For progress bar
from tqdm import tqdm

# For audible alerts
import time
import threading


import json

class NumpyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, (np.integer, np.int32, np.int64)):
            return int(obj)
        elif isinstance(obj, (np.float32, np.float64)):
            return float(obj)
        elif isinstance(obj, (np.ndarray,)):
            return obj.tolist()
        elif callable(obj):  # Handle function objects
            return str(obj)
        else:
            return super(NumpyEncoder, self).default(obj)

def beep():
    duration = 0.2  # seconds
    freq = 440  # Hz
    if sys.platform == 'win32':
        import winsound
        winsound.Beep(freq, int(duration * 1000))
    else:
        # Beep not available on all systems, alternative is to print bell character
        print('\a', end='')

def play_sound_async():
    threading.Thread(target=beep).start()

def transform_stock_name(name):
    # Remove the prefix 'NSE:' or 'BSE:' and add appropriate suffix
    if 'NSE:' in name:
        name = name.split('NSE:')[1]
        if '-' in name:
            name = name.split('-')[0]
        name += '.NS'
    elif 'BSE:' in name:
        name = name.split('BSE:')[1]
        name += '.BO'
    else:
        # Assume it's a ticker symbol and append '.NS' (adjust as needed)
        name += '.NS'
    return name

def fetch_stock_data(stock_list, start_date, end_date):
    stock_data = {}
    print("Fetching stock data...")
    for stock in tqdm(stock_list):
        try:
            df = yf.download(stock, start=start_date, end=end_date)
            if not df.empty:
                stock_data[stock] = df
            else:
                print(f"No data for {stock}")
        except Exception as e:
            print(f"Error downloading {stock}: {e}")
    return stock_data

def calculate_indicators(df):
    df = df.copy()
    # Simple Moving Averages
    df['SMA_5'] = df['Close'].rolling(window=5).mean()
    df['SMA_10'] = df['Close'].rolling(window=10).mean()
    df['SMA_20'] = df['Close'].rolling(window=20).mean()
    # Exponential Moving Averages
    df['EMA_5'] = df['Close'].ewm(span=5, adjust=False).mean()
    df['EMA_10'] = df['Close'].ewm(span=10, adjust=False).mean()
    # Relative Strength Index (RSI)
    delta = df['Close'].diff()
    gain = (delta.where(delta > 0, 0)).fillna(0)
    loss = (-delta.where(delta < 0, 0)).fillna(0)
    average_gain = gain.rolling(window=14).mean()
    average_loss = loss.rolling(window=14).mean()
    rs = average_gain / average_loss
    df['RSI'] = 100 - (100 / (1 + rs))
    # Bollinger Bands
    df['BB_Middle'] = df['Close'].rolling(window=20).mean()
    df['BB_Std'] = df['Close'].rolling(window=20).std()
    df['BB_Upper'] = df['BB_Middle'] + (df['BB_Std'] * 2)
    df['BB_Lower'] = df['BB_Middle'] - (df['BB_Std'] * 2)
    # MACD
    ema_12 = df['Close'].ewm(span=12, adjust=False).mean()
    ema_26 = df['Close'].ewm(span=26, adjust=False).mean()
    df['MACD'] = ema_12 - ema_26
    df['MACD_Signal'] = df['MACD'].ewm(span=9, adjust=False).mean()
    # Stochastic Oscillator
    low_min = df['Low'].rolling(window=14).min()
    high_max = df['High'].rolling(window=14).max()
    df['Stochastic'] = ((df['Close'] - low_min) / (high_max - low_min)) * 100
    # Fill any remaining NaN values
    df.fillna(method='bfill', inplace=True)
    return df

def prepare_dataset(stock_data):
    df_list = []
    for symbol, data in stock_data.items():
        data = data.copy()
        data['Symbol'] = symbol
        data.reset_index(inplace=True)
        df_list.append(data)
    dataset = pd.concat(df_list, ignore_index=True)
    return dataset

def define_target_variable(dataset, prediction_horizon=15, return_threshold=0.05):
    dataset = dataset.sort_values(['Symbol', 'Date'])
    dataset['Future_Close'] = dataset.groupby('Symbol')['Close'].shift(-prediction_horizon)
    dataset['Future_Return'] = (dataset['Future_Close'] - dataset['Close']) / dataset['Close']
    dataset['Target'] = np.where(dataset['Future_Return'] > return_threshold, 1, 0)
    # Drop rows with NaN values in Future_Close (the last 'n' rows for each symbol)
    dataset = dataset.dropna(subset=['Future_Close'])
    return dataset

def handle_missing_values(dataset):
    # Fill NaNs with forward/backward fill
    dataset.fillna(method='ffill', inplace=True)
    dataset.fillna(method='bfill', inplace=True)
    return dataset

def encode_categorical_variables(dataset):
    le = LabelEncoder()
    dataset['Symbol_Encoded'] = le.fit_transform(dataset['Symbol'])
    return dataset, le

def select_features(dataset):
    features = dataset.drop(columns=['Date', 'Symbol', 'Future_Close', 'Future_Return', 'Target'])
    target = dataset['Target']
    return features, target

def scale_features(features):
    scaler = StandardScaler()
    features_scaled = scaler.fit_transform(features)
    feature_names = features.columns
    return features_scaled, scaler, feature_names

def split_dataset(features, target):
    X_train, X_test, y_train, y_test = train_test_split(
        features, target, test_size=0.2, random_state=42, stratify=target
    )
    return X_train, X_test, y_train, y_test

def balance_dataset(X_train, y_train):
    smote = SMOTE(random_state=42)
    X_train_balanced, y_train_balanced = smote.fit_resample(X_train, y_train)
    return X_train_balanced, y_train_balanced

def tune_random_forest(X_train, y_train):
    param_grid = {
        'n_estimators': [100, 200],
        'max_depth': [None, 5, 10],
        'min_samples_split': [2, 5],
    }
    rf = RandomForestClassifier(random_state=42)
    grid_search = GridSearchCV(
        estimator=rf, param_grid=param_grid, cv=3, scoring='f1', n_jobs=-1
    )
    grid_search.fit(X_train, y_train)
    print("Best parameters for Random Forest:", grid_search.best_params_)
    best_rf = grid_search.best_estimator_
    return best_rf

def tune_xgboost(X_train, y_train):
    param_grid = {
        'n_estimators': [100, 200],
        'max_depth': [3, 5, 7],
        'learning_rate': [0.01, 0.1],
    }
    xgb_clf = xgb.XGBClassifier(eval_metric='logloss', use_label_encoder=False)
    grid_search = GridSearchCV(
        estimator=xgb_clf, param_grid=param_grid, cv=3, scoring='f1', n_jobs=-1
    )
    grid_search.fit(X_train, y_train)
    print("Best parameters for XGBoost:", grid_search.best_params_)
    best_xgb = grid_search.best_estimator_
    return best_xgb

def train_neural_network(X_train, y_train):
    from scikeras.wrappers import KerasClassifier

    def create_nn_model():
        model = Sequential()
        model.add(Dense(64, input_dim=X_train.shape[1], activation='relu'))
        model.add(Dense(32, activation='relu'))
        model.add(Dense(1, activation='sigmoid'))
        optimizer = Adam(learning_rate=0.001)
        model.compile(
            loss='binary_crossentropy', optimizer=optimizer, metrics=['accuracy']
        )
        return model

    nn_model = KerasClassifier(model=create_nn_model, epochs=10, batch_size=32, verbose=0)
    nn_model.fit(X_train, y_train)
    return nn_model

def train_logistic_regression(X_train, y_train):
    lr_classifier = LogisticRegression(random_state=42, max_iter=1000)
    lr_classifier.fit(X_train, y_train)
    return lr_classifier

def train_svm(X_train, y_train):
    svm_classifier = SVC(probability=True, random_state=42)
    svm_classifier.fit(X_train, y_train)
    return svm_classifier

def plot_feature_importance(model, feature_names):
    if hasattr(model, 'feature_importances_'):
        importances = model.feature_importances_
        indices = np.argsort(importances)[::-1]

        plt.figure(figsize=(12, 6))
        plt.title("Feature Importance")
        plt.bar(range(len(importances)), importances[indices], align='center')
        plt.xticks(
            range(len(importances)), [feature_names[i] for i in indices],
            rotation=90
        )
        plt.tight_layout()
        plt.show()
    else:
        print("Model does not have feature_importances_ attribute")

# Function to save models
def save_model(model, model_name):
    import joblib
    filename = f"{model_name}_model.pkl"
    joblib.dump(model, filename)
    print(f"{model_name} model saved to {filename}")

# Function to load models
def load_model(model_name):
    import joblib
    filename = f"{model_name}_model.pkl"
    if os.path.exists(filename):
        model = joblib.load(filename)
        print(f"{model_name} model loaded from {filename}")
        return model
    else:
        print(f"No saved model found for {model_name}. Please train the model first.")
        return None

def save_keras_model(model, model_name):
    filename = f"{model_name}model.h5"
    model.model_.save(filename)
    print(f"{model_name} model saved to {filename}")

def load_keras_model(model_name):
    filename = f"{model_name}model.h5"
    if os.path.exists(filename):
        from keras.models import load_model
        keras_model = load_model(filename)
        print(f"{model_name} model loaded from {filename}")
        # Wrap the loaded Keras model back into a KerasClassifier
        from scikeras.wrappers import KerasClassifier

        def create_nn_model():
            return keras_model

        nn_model = KerasClassifier(model=create_nn_model)
        nn_model.model_ = keras_model  # Set the trained model
        return nn_model
    else:
        print(f"No saved model found for {model_name}. Please train the model first.")
        return None

def save_scaler(scaler):
    import joblib
    joblib.dump(scaler, "scaler.pkl")
    print("Scaler saved to scaler.pkl")

def load_scaler():
    import joblib
    if os.path.exists("scaler.pkl"):
        scaler = joblib.load("scaler.pkl")
        print("Scaler loaded from scaler.pkl")
        return scaler
    else:
        print("No saved scaler found.")
        return None

def save_label_encoder(le):
    import joblib
    joblib.dump(le, "label_encoder.pkl")
    print("Label encoder saved to label_encoder.pkl")

def load_label_encoder():
    import joblib
    if os.path.exists("label_encoder.pkl"):
        le = joblib.load("label_encoder.pkl")
        print("Label encoder loaded from label_encoder.pkl")
        return le
    else:
        print("No saved label encoder found.")
        return None

# Function to sanitize parameters for JSON serialization
def sanitize_parameters(params):
    sanitized_params = {}
    for key, value in params.items():
        try:
            json.dumps(value)  # Check if value is JSON serializable
            sanitized_params[key] = value
        except TypeError:
            sanitized_params[key] = str(value)
    return sanitized_params

##################################################################################################

def main_machine_learning():
    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn.metrics import (precision_recall_curve, average_precision_score,
                                 roc_curve, roc_auc_score, classification_report)
    from sklearn.model_selection import cross_val_score, StratifiedKFold

    # Audible beep at the start
    play_sound_async()
    print("Program started...")

    # Provide option to Train or Use
    action = input("Do you want to 'Train' the models or 'Use' existing models? Enter 'Train' or 'Use': ").strip().lower()

    if action not in ['train', 'use']:
        print("Invalid input. Exiting the program.")
        return

    # Prompt user for input stocks and prediction horizon
    user_stock_symbols = input("Enter the stock symbols separated by commas (e.g., AAPL, GOOGL, MSFT): ")
    user_stock_list = [symbol.strip() for symbol in user_stock_symbols.split(',')]

    # Transform stock names to Yahoo Finance format
    stock_list = []
    for stock in user_stock_list:
        new_name = transform_stock_name(stock)
        stock_list.append(new_name)

    # Prompt user for prediction horizon
    prediction_horizon_input = input("Enter the prediction horizon in days (e.g., 5): ")
    try:
        prediction_horizon = int(prediction_horizon_input)
    except ValueError:
        print("Invalid prediction horizon input. Using default value of 5 days.")
        prediction_horizon = 5

    # Prompt user for return threshold
    return_threshold_input = input("Enter the return threshold as a decimal (e.g., 0.05 for 5%): ")
    try:
        return_threshold = float(return_threshold_input)
    except ValueError:
        print("Invalid return threshold input. Using default value of 0.05 (5%).")
        return_threshold = 0.05

    # Prompt user for data period
    data_period_input = input("Enter the number of years of data to use for training (e.g., 5 or 10): ")
    try:
        data_period_years = int(data_period_input)
    except ValueError:
        print("Invalid data period input. Using default value of 5 years.")
        data_period_years = 5

    end_date = datetime.datetime.now()
    start_date = end_date - datetime.timedelta(days=data_period_years*365)

    if action == 'train':
        # Fetch data
        stock_data = fetch_stock_data(stock_list, start_date.strftime('%Y-%m-%d'), end_date.strftime('%Y-%m-%d'))

        # Check if any data was fetched
        if not stock_data:
            print("No stock data fetched. Please check your stock symbols and internet connection.")
            return

        # Calculate indicators
        print("Calculating technical indicators...")
        for symbol in tqdm(stock_data):
            stock_data[symbol] = calculate_indicators(stock_data[symbol])

        # Prepare dataset
        dataset = prepare_dataset(stock_data)
        dataset = define_target_variable(dataset, prediction_horizon=prediction_horizon, return_threshold=return_threshold)
        dataset = handle_missing_values(dataset)

        # Encode categorical variables
        dataset, le = encode_categorical_variables(dataset)
        features, target = select_features(dataset)

        # Save label encoder for future use
        save_label_encoder(le)

        # Add feature names for plotting
        feature_names = features.columns

        # Scale features
        features_scaled, scaler, feature_names = scale_features(features)

        # Save scaler for future use
        save_scaler(scaler)

        # Split dataset
        X_train, X_test, y_train, y_test = split_dataset(features_scaled, target)

        # Balance training data
        X_train_balanced, y_train_balanced = balance_dataset(X_train, y_train)

        # Hyperparameter tuning and train models
        print("Training models...")
        rf_model = tune_random_forest(X_train_balanced, y_train_balanced)
        xgb_model = tune_xgboost(X_train_balanced, y_train_balanced)
        nn_model = train_neural_network(X_train_balanced, y_train_balanced)
        lr_model = train_logistic_regression(X_train_balanced, y_train_balanced)
        svm_model = train_svm(X_train_balanced, y_train_balanced)

        # Save models
        save_model(rf_model, "RandomForest")
        save_model(xgb_model, "XGBoost")
        save_keras_model(nn_model, "NeuralNetwork")
        save_model(lr_model, "LogisticRegression")
        save_model(svm_model, "SVM")

        # Evaluate models
        models = {
            'Random Forest': rf_model,
            'XGBoost': xgb_model,
            'Neural Network': nn_model,
            'Logistic Regression': lr_model,
            'SVM': svm_model
        }

        model_performance = {}  # Dictionary to store model performance

        optimal_thresholds = {}  # Dictionary to store optimal thresholds

        for model_name, model in models.items():
            print(f"\n{model_name} Model Evaluation:")

            # Predictions and Scores
            if model_name == 'Neural Network':
                y_scores = model.predict_proba(X_test)
                if y_scores.ndim == 2 and y_scores.shape[1] == 2:
                    y_scores = y_scores[:, 1]
                elif y_scores.ndim == 2 and y_scores.shape[1] == 1:
                    y_scores = y_scores.ravel()
                elif y_scores.ndim == 1:
                    pass
                else:
                    print("Unexpected y_scores shape:", y_scores.shape)
                    continue
            else:
                if hasattr(model, 'predict_proba'):
                    y_scores = model.predict_proba(X_test)[:, 1]
                else:
                    y_scores = model.decision_function(X_test)

            # Default threshold at 0.5
            y_pred_default = (y_scores >= 0.5).astype(int)
            print("Classification Report with default threshold (0.5):")
            print(classification_report(y_test, y_pred_default))

            # ROC Curve and AUC
            fpr, tpr, thresholds = roc_curve(y_test, y_scores)
            auc = roc_auc_score(y_test, y_scores)
            plt.figure()
            plt.plot(fpr, tpr, label=f'{model_name} ROC Curve (AUC = {auc:.2f})')
            plt.plot([0, 1], [0, 1], linestyle='--', label='Random Chance')
            plt.title(f'{model_name} ROC Curve')
            plt.xlabel('False Positive Rate')
            plt.ylabel('True Positive Rate')
            plt.legend()
            plt.show()

            # Find Optimal Threshold
            J = tpr - fpr  # Youden's J statistic
            ix = np.argmax(J)
            optimal_threshold = thresholds[ix]
            optimal_thresholds[model_name] = optimal_threshold  # Save for later use
            print(f"Optimal Threshold for {model_name}: {optimal_threshold:.2f}")

            # Use Optimal Threshold
            y_pred_optimal = (y_scores >= optimal_threshold).astype(int)
            print(f"Classification Report with Optimal Threshold ({optimal_threshold:.2f}):")
            print(classification_report(y_test, y_pred_optimal))

            # Precision-Recall Curve
            precision, recall, pr_thresholds = precision_recall_curve(y_test, y_scores)
            ap = average_precision_score(y_test, y_scores)
            plt.figure()
            plt.plot(recall, precision, label=f'{model_name} PR Curve (AP = {ap:.2f})')
            plt.title(f'{model_name} Precision-Recall Curve')
            plt.xlabel('Recall')
            plt.ylabel('Precision')
            plt.legend()
            plt.show()

            # Cross-validation for ROC AUC
            print(f"Performing cross-validation for {model_name}...")
            cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
            auc_scores = cross_val_score(model, X_train_balanced, y_train_balanced, cv=cv, scoring='roc_auc', n_jobs=-1)

            mean_auc = float(auc_scores.mean())
            print(f"Cross-validated AUC scores for {model_name}: {auc_scores}")
            print(f"Mean AUC: {mean_auc:.2f}")

            # Store performance metrics
            if hasattr(model, 'get_params'):
                parameters = model.get_params()
                parameters = sanitize_parameters(parameters)
            else:
                parameters = None

            model_performance[model_name] = {
                'AUC': mean_auc,
                'Optimal Threshold': float(optimal_threshold),
                'Parameters': parameters
            }

            if model_name in ['Random Forest', 'XGBoost']:
                plot_feature_importance(model, feature_names)

        # Save model performance metrics
        with open('model_performance.json', 'w') as f:
            json.dump(model_performance, f, cls=NumpyEncoder)
        print("Model performance metrics saved to model_performance.json")

        # Audible beep at the end of training
        play_sound_async()
        print("Training completed.")

    elif action == 'use':
        # Load models
        print("Loading saved models...")
        rf_model = load_model("RandomForest")
        xgb_model = load_model("XGBoost")
        nn_model = load_keras_model("NeuralNetwork")
        lr_model = load_model("LogisticRegression")
        svm_model = load_model("SVM")

        # Load scaler and label encoder
        scaler = load_scaler()
        le = load_label_encoder()

        # Load model performance metrics
        if os.path.exists('model_performance.json'):
            with open('model_performance.json', 'r') as f:
                model_performance = json.load(f)
        else:
            print("Model performance metrics not found.")
            model_performance = {}

        # Display models and their performance
        print("\nAvailable models:")
        for idx, model_name in enumerate(model_performance.keys()):
            performance = model_performance[model_name]
            print(f"{idx+1}. {model_name} - Mean AUC: {performance['AUC']:.2f}")

        # Allow user to select a model
        model_choice_input = input("Enter the number corresponding to the model you want to use: ")
        try:
            model_choice = int(model_choice_input) - 1
            selected_model_name = list(model_performance.keys())[model_choice]
            print(f"You have selected: {selected_model_name}")
        except (ValueError, IndexError):
            print("Invalid choice. Exiting the program.")
            return

        # Get the selected model and its optimal threshold
        models = {
            'Random Forest': rf_model,
            'XGBoost': xgb_model,
            'Neural Network': nn_model,
            'Logistic Regression': lr_model,
            'SVM': svm_model
        }
        best_model = models[selected_model_name]
        optimal_threshold_best_model = model_performance[selected_model_name]['Optimal Threshold']

        # Fetch recent data for prediction
        recent_end_date = datetime.datetime.now()
        recent_start_date = recent_end_date - datetime.timedelta(days=60)
        recent_stock_data = fetch_stock_data(
            stock_list, recent_start_date.strftime('%Y-%m-%d'), recent_end_date.strftime('%Y-%m-%d')
        )

        if not recent_stock_data:
            print("No recent stock data fetched. Please check your stock symbols and internet connection.")
            return

        # Prepare recent data
        recent_dataset = prepare_dataset(recent_stock_data)

        # Calculate indicators
        print("Calculating technical indicators on recent data...")
        for symbol in tqdm(recent_stock_data):
            recent_stock_data[symbol] = calculate_indicators(recent_stock_data[symbol])

        recent_dataset = handle_missing_values(recent_dataset)
        recent_dataset['Symbol_Encoded'] = le.transform(recent_dataset['Symbol'])
        recent_features = recent_dataset.drop(columns=['Date', 'Symbol'])

        # Ensure recent_features has the same columns as during training
        # Add missing columns with default values
        missing_cols = set(feature_names) - set(recent_features.columns)
        for col in missing_cols:
            recent_features[col] = 0

        # Remove any extra columns not in original features
        extra_cols = set(recent_features.columns) - set(feature_names)
        recent_features.drop(columns=extra_cols, inplace=True)

        # Reorder columns to match the original order
        recent_features = recent_features[feature_names]

        # Now transform
        recent_features_scaled = scaler.transform(recent_features)

        # Predict probabilities using the best model
        if selected_model_name == 'Neural Network':
            predictions = best_model.predict_proba(recent_features_scaled)
            if predictions.ndim == 2 and predictions.shape[1] == 2:
                predictions = predictions[:, 1]
            elif predictions.ndim == 2 and predictions.shape[1] == 1:
                predictions = predictions.ravel()
        else:
            if hasattr(best_model, 'predict_proba'):
                predictions = best_model.predict_proba(recent_features_scaled)[:,1]
            else:
                predictions = best_model.decision_function(recent_features_scaled)

        recent_dataset['Prediction_Prob'] = predictions

        # Use optimal threshold
        recent_dataset['Prediction'] = (recent_dataset['Prediction_Prob'] >= optimal_threshold_best_model).astype(int)

        # Get latest date's predictions
        idx = recent_dataset.groupby('Symbol')['Date'].idxmax()
        latest_predictions = recent_dataset.loc[idx]

        # Filter stocks predicted to be profitable
        predicted_profitable_stocks = latest_predictions[latest_predictions['Prediction'] == 1]

        print("\nStocks predicted to be profitable in the next {} days:".format(prediction_horizon))
        print(predicted_profitable_stocks[['Symbol', 'Date', 'Close', 'Prediction_Prob']])

        # Audible beep at the end of program
        play_sound_async()
        print("Program execution completed.")

    # Provide guidance on number of stocks and data periods
    print("\nGuidance on model training:")
    print("1. Training with more stocks generally improves model generalization but increases training time.")
    print("2. Using data from longer periods (e.g., 10 years) can capture more market cycles but may include outdated patterns.")
    print("3. Balance between the number of stocks, data period, and computational resources for optimal performance.")

####################################################################################

# Starting point for PyQt5 GUI (Note: Full GUI implementation is extensive and requires significant code)
def main_with_gui():
    from PyQt5 import QtWidgets
    import sys

    class StockPredictorApp(QtWidgets.QWidget):
        def init(self):
            super().init()
            self.__init__ui()

        def __init__ui(self):
            self.setWindowTitle('Stock Predictor')
            self.setGeometry(100, 100, 400, 300)

            # Create UI elements
            self.label = QtWidgets.QLabel('Welcome to the Stock Predictor App', self)
            self.label.move(50, 20)

            self.train_button = QtWidgets.QPushButton('Train Models', self)
            self.train_button.move(50, 60)
            self.train_button.clicked.connect(self.train_models)

            self.use_button = QtWidgets.QPushButton('Use Models', self)
            self.use_button.move(200, 60)
            self.use_button.clicked.connect(self.use_models)

            self.show()

        def train_models(self):
            # Here you would call the training function
            QtWidgets.QMessageBox.information(self, 'Train Models', 'Training started...')
            main_machine_learning()  # Or your specific training function

        def use_models(self):
            # Here you would call the prediction function
            QtWidgets.QMessageBox.information(self, 'Use Models', 'Using existing models...')
            main_machine_learning()  # Or your specific prediction function

    app = QtWidgets.QApplication(sys.argv)
    ex = StockPredictorApp()
    sys.exit(app.exec())

####################################################################################

if __name__ == "__main__":
    # To run with GUI, uncomment the following line and comment out main_machine_learning()
    # main_with_gui()
    main_machine_learning()

 











got this error :
Program started...
Do you want to 'Train' the models or 'Use' existing models? Enter 'Train' or 'Use': USE
Enter the stock symbols separated by commas (e.g., AAPL, GOOGL, MSFT): NSE:HAL
Enter the prediction horizon in days (e.g., 5): 15
Enter the return threshold as a decimal (e.g., 0.05 for 5%): 0.05
Enter the number of years of data to use for training (e.g., 5 or 10): 5
Loading saved models...
RandomForest model loaded from RandomForest_model.pkl
XGBoost model loaded from XGBoost_model.pkl
NeuralNetwork model loaded from NeuralNetworkmodel.h5
LogisticRegression model loaded from LogisticRegression_model.pkl
SVM model loaded from SVM_model.pkl
Scaler loaded from scaler.pkl
Label encoder loaded from label_encoder.pkl

Available models:
1. Random Forest - Mean AUC: 0.96
2. XGBoost - Mean AUC: 0.95
3. Neural Network - Mean AUC: 0.63
4. Logistic Regression - Mean AUC: 0.56
5. SVM - Mean AUC: 0.65
Enter the number corresponding to the model you want to use: 1
You have selected: Random Forest
Fetching stock data...
[*********************100%%**********************]  1 of 1 completed                                                                                                 | 0/1 [00:00<?, ?it/s]
100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00,  1.70it/s]
Calculating technical indicators on recent data...
100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 75.61it/s]
Traceback (most recent call last):
  File "c:\Users\swarn\python_codes\python_try\hugging\predictive_17.py", line 833, in <module>
    main_machine_learning()
  File "c:\Users\swarn\python_codes\python_try\hugging\predictive_17.py", line 732, in main_machine_learning
    missing_cols = set(feature_names) - set(recent_features.columns)
                       ^^^^^^^^^^^^^
UnboundLocalError: cannot access local variable 'feature_names' where it is not associated with a value