consider the following code , I am having error, please rectify this . The code is intended to select probable performing stocks in the indian market based on machine learning models.

nfo_stocks = [
#small_list =[
    # *************** COMPLETE NFO STOCK LIST ************* #
    "NSE:AARTIDRUGS",
    "NSE:AARTIIND",
    "NSE:AARTIPHARM","NSE:ABB",
    "NSE:ABBOTINDIA",
    "NSE:ABCAPITAL",
    "NSE:ABFRL",
    "NSE:ACC","NSE:ADANIENT",
    "NSE:ADANIPORTS","NSE:ALKEM",
    "NSE:AMBUJACEM","NSE:APOLLOHOSP","NSE:APOLLOTYRE","NSE:ASHOKLEY",

]
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'      
    return name
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



#####################################################################################################################
### Step 2: Defining the Target Variable

#### A. Choose a Prediction Objective

#We need to define what we want the model to predict. Common approaches include:

#- Classification Task: Predict whether a stock's price will increase or decrease over a certain future period.
#- Regression Task: Predict the future price of the stock or the percentage change.

#For simplicity, we'll set up a binary classification task:

#- 1 (Positive Class): The stock price will increase by more than a certain threshold in the next 'n' days.
#- 0 (Negative Class): The stock price will not increase by the threshold (could decrease or have minimal change).

#### B. Create the Target Variable

#We'll calculate the future returns and set the target based on a return threshold.





def define_target_variable(dataset, prediction_horizon=5, return_threshold=0.02):
    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


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

### Step 3: Feature Engineering

#### A. Handling Missing Values

#Check for missing values in the dataset and handle them appropriately.



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


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

#### B. Encoding Categorical Variables

#Encode the 'Symbol' column using one-hot encoding or label encoding.

from sklearn.preprocessing import LabelEncoder

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

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

#### C. Feature Selection

#Select relevant features for the model. Exclude columns like 'Date', 'Future_Close', 'Future_Return', 'Target', and any redundant information.


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


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


#### D. Scaling Features

#Scale numerical features for algorithms sensitive to feature scales.

from sklearn.preprocessing import StandardScaler

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


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

### Step 4: Splitting the Dataset

#Split the dataset into training and testing sets.

from sklearn.model_selection import train_test_split

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



######################################################################################################
### Step 5: Selecting and Training Machine Learning Models

#We'll experiment with different algorithms:

#- Random Forests
#- Gradient Boosting Machines (XGBoost)
#- Neural Networks

#### A. Random Forest Classifier

from sklearn.ensemble import RandomForestClassifier

def train_random_forest(X_train, y_train):
    rf_classifier = RandomForestClassifier(n_estimators=100, random_state=42)
    rf_classifier.fit(X_train, y_train)
    return rf_classifier


#### B. Gradient Boosting (XGBoost)

import xgboost as xgb

def train_xgboost(X_train, y_train):
    xgb_classifier = xgb.XGBClassifier(use_label_encoder=False, eval_metric='logloss')
    xgb_classifier.fit(X_train, y_train)
    return xgb_classifier


#### C. Neural Networks (Keras/TensorFlow)
#import tensorflow as tf

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

from keras.models import Sequential
from keras.layers import Dense   #Activation
from keras.optimizers import Adam
#from keras.layers import LSTM




def train_neural_network(X_train, y_train):
    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'])
    
    model.fit(X_train, y_train, epochs=10, batch_size=32, verbose=1)
    return model



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

### Step 6: Evaluating the Models

#Assess model performance using metrics like accuracy, precision, recall, F1-score, and ROC AUC.

#### A. Evaluate with Classification Report

from sklearn.metrics import classification_report

def evaluate_model(model, X_test, y_test):
    y_pred = model.predict(X_test)
    
    # For tree-based models, y_pred might need adjustment
    if hasattr(model, 'predict_proba'):
        y_pred = (y_pred > 0.5).astype(int)
    
    print("Classification Report:")
    print(classification_report(y_test, y_pred))


#### B. ROC Curve and AUC

from sklearn.metrics import roc_auc_score, roc_curve
import matplotlib.pyplot as plt

def plot_roc_curve(model, X_test, y_test):
    if hasattr(model, 'predict_proba'):
        y_scores = model.predict_proba(X_test)[:, 1]
    else:
        y_scores = model.predict(X_test)
    
    fpr, tpr, thresholds = roc_curve(y_test, y_scores)
    auc = roc_auc_score(y_test, y_scores)
    
    plt.figure()
    plt.plot(fpr, tpr, label='ROC Curve (area = {:.2f})'.format(auc))
    plt.plot([0, 1], [0, 1], linestyle='--')
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    plt.title('ROC Curve')
    plt.legend()
    plt.show()


### Step 7: Making Predictions

#Use the trained model to predict on new data.

def predict_new_data(model, scaler, le, new_data):
    # Preprocess new_data similar to training data
    new_data_processed = preprocess_new_data(new_data, scaler, le)
    predictions = model.predict(new_data_processed)
    return predictions







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

def main_machine_learning():

    global nfo_stocks
    global stock_list
    stock_list = []
    for stock in nfo_stocks:
        new_name = transform_stock_name(stock)
        stock_list.append(new_name)

    # Fetch and prepare data (reuse functions from previous steps)
    end_date = datetime.datetime.now()
    start_date = end_date - datetime.timedelta(days=5*365)  # Last 5 years

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


#    # Fetch and prepare data (reuse functions from previous steps)
#    end_date = datetime.datetime.now()
#    start_date = end_date - datetime.timedelta(days=5*365)
#    stock_data = fetch_stock_data(nifty50_symbols, start_date.strftime('%Y-%m-%d'), end_date.strftime('%Y-%m-%d'))
    
    # Calculate indicators
    for symbol in stock_data:
        stock_data[symbol] = calculate_indicators(stock_data[symbol])
    
    # Prepare dataset
    dataset = prepare_dataset(stock_data)
    dataset = define_target_variable(dataset)
    dataset = handle_missing_values(dataset)
    dataset, le = encode_categorical_variables(dataset)
    features, target = select_features(dataset)
    features_scaled, scaler = scale_features(features)
    X_train, X_test, y_train, y_test = split_dataset(features_scaled, target)
    
    # Train models
    rf_model = train_random_forest(X_train, y_train)
    xgb_model = train_xgboost(X_train, y_train)
    nn_model = train_neural_network(X_train, y_train)
    
    # Evaluate models
    print("Random Forest Model Evaluation:")
    evaluate_model(rf_model, X_test, y_test)
    plot_roc_curve(rf_model, X_test, y_test)
    
    print("XGBoost Model Evaluation:")
    evaluate_model(xgb_model, X_test, y_test)
    plot_roc_curve(xgb_model, X_test, y_test)
    
    print("Neural Network Model Evaluation:")
    y_pred_nn = (nn_model.predict(X_test) > 0.5).astype(int)
    print(classification_report(y_test, y_pred_nn))
    y_scores_nn = nn_model.predict(X_test).ravel()
    fpr, tpr, thresholds = roc_curve(y_test, y_scores_nn)
    auc = roc_auc_score(y_test, y_scores_nn)
    
    plt.figure()
    plt.plot(fpr, tpr, label='ROC Curve (area = {:.2f})'.format(auc))
    plt.plot([0, 1], [0, 1], linestyle='--')
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    plt.title('Neural Network ROC Curve')
    plt.legend()
    plt.show()
    
    # The best performing model can be used for predictions
    # For example, using xgb_model
    # predict_new_data(xgb_model, scaler, le, new_data)



if __name__ == "__main__":
    main_machine_learning()