In this code no matter how much low learning rate i do my accuracy saturates at 0.4340 I tried lr=0.001 and 0.00001:
Epoch 1/200
79/79 [==============================] - 13s 130ms/step - loss: 1.0979 - accuracy: 0.3753
Epoch 2/200
79/79 [==============================] - 11s 135ms/step - loss: 1.0956 - accuracy: 0.4281
Epoch 3/200
79/79 [==============================] - 9s 113ms/step - loss: 1.0930 - accuracy: 0.4332
Epoch 4/200
79/79 [==============================] - 10s 131ms/step - loss: 1.0906 - accuracy: 0.4340
Epoch 5/200
79/79 [==============================] - 10s 132ms/step - loss: 1.0880 - accuracy: 0.4340
Epoch 6/200
79/79 [==============================] - 10s 129ms/step - loss: 1.0853 - accuracy: 0.4340

Code:
import yfinance as yf
import pandas as pd
import numpy as np

nifty_df = yf.download('^NSEI', start='2009-01-01', end='2021-12-31')

# Clean the data
nifty_df = nifty_df.dropna()

# Calculate various percent differences
nifty_df['PctOpenClose'] = (nifty_df['Close'] - nifty_df['Open']) / nifty_df['Open'] * 100
nifty_df['PctHighLow'] = (nifty_df['High'] - nifty_df['Low']) / nifty_df['Low'] * 100
nifty_df['PctChange'] = nifty_df['Close'].pct_change() * 100

# Remove the first row with NaN in 'PctChange'
nifty_df = nifty_df.iloc[1:]

# Export cleaned dataset
nifty_df.to_csv('nifty_cleaned.csv')

def create_labels(df, col_name, threshold=0.5):
    labels = []
    for index, row in df.iterrows():
        future_price = row[col_name]
        if future_price >= threshold:
            labels.append(2)  # Buy
        elif future_price <= -threshold:
            labels.append(0)  # Sell
        else:
            labels.append(1)  # Hold

    return labels

nifty_df['Labels'] = create_labels(nifty_df, 'PctChange')

import matplotlib.pyplot as plt
import seaborn as sns

sns.countplot(nifty_df['Labels'])

plt.title('Count of Buy, Hold, and Sell')
plt.xlabel('Trade Decisions')
plt.ylabel('Count')
plt.show()

from sklearn.ensemble import ExtraTreesClassifier

X = nifty_df.drop(['Labels'], axis=1)
y = nifty_df['Labels']

# Fit the ExtraTreesClassifier
et_clf = ExtraTreesClassifier()
et_clf.fit(X, y)

# Visualize feature importances
feature_importances = pd.Series(et_clf.feature_importances_, index=X.columns)
feature_importances.nlargest(10).plot(kind='barh')
plt.show()


important_features = feature_importances.nlargest(8).index.tolist()
X_filtered = X[important_features]
X_filtered

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()
scaled_X = scaler.fit_transform(X_filtered)

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(scaled_X, y, test_size=0.2, random_state=42)

from keras.models import Sequential
from keras.layers import LSTM, Dense, Dropout

look_back = 20

def create_dataset(X, y, look_back=100):
    dataX, dataY = [], []
    for i in range(len(X)-look_back-1):
        dataX.append(X[i:(i+look_back), :])
        dataY.append(y[i + look_back])
    return np.array(dataX), np.array(dataY)

X_train_lstm, y_train_lstm = create_dataset(X_train, y_train, look_back)
X_test_lstm, y_test_lstm = create_dataset(X_test, y_test, look_back)


from keras.models import Sequential
from keras.layers import LSTM, Dense

model = Sequential()
model.add(LSTM(100, activation='relu', return_sequences=True, input_shape=(look_back, 8)))
model.add(Dropout(0.2))
model.add(LSTM(100, activation='relu', return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(100, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(3, activation='softmax'))

from keras.optimizers import Adam
optimizer = Adam(clipvalue=1.0)
model.compile(optimizer=Adam(learning_rate=0.00001), loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# print("Unique labels in y_train_lstm:", np.unique(y_train_lstm))
model.fit(X_train_lstm, y_train_lstm, epochs=200, verbose=1)

from sklearn.metrics import confusion_matrix, precision_score, recall_score, f1_score, accuracy_score

y_pred = model.predict(X_test_lstm)

y_pred_labels = np.argmax(y_pred, axis=1) - 1

print("Confusion Matrix:")
print(confusion_matrix(y_test_lstm, y_pred_labels))

print("\n Evaluation Metrics:")
print("Accuracy: ", accuracy_score(y_test_lstm, y_pred_labels))
print("Precision: ", precision_score(y_test_lstm, y_pred_labels, average='macro'))
print("Recall: ", recall_score(y_test_lstm, y_pred_labels, average='macro'))
print("F1-Score: ", f1_score(y_test_lstm, y_pred_labels, average='macro'))

model.save('nifty_lstm_model.h5') 

# Import the necessary libraries
from keras.models import load_model

# Load the trained model
trained_model = load_model('nifty_lstm_model.h5')

# Load the new dataset for prediction
new_data = pd.read_csv('new_data.csv')

# Preprocess the new dataset
preprocessed_new_data = preprocess_data(new_data)  # Assumes the same preprocessing is applied as before

# Predict
predicted_labels = trained_model.predict(preprocessed_new_data)