My Exponential Moving Average calculations are still somehow wrong?

 
Where am I going wrong...

Here is my Python code which interacts with the MetaTrader5 API.

import numpy as np
import MetaTrader5 as mt5
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import Dense
import time
from keras.utils import to_categorical
import threading

class ForexPredictor:
    def __init__(
        self,
        symbol,
        timeframe,
        pattern_length,
        balancerisk=0.03,
        risklevel=1 / 3,
        magic=1,
        num_bars=1000,
        epochs=20,
        batch_size=32,
        prediction_interval=0.001,
    ):
        self.balancerisk = balancerisk
        self.risklevel = risklevel
        self.magic = magic
        self.connected = False
        self.symbol = symbol
        self.timeframe = timeframe
        self.pattern_length = pattern_length
        self.model = None
        self.scaler = MinMaxScaler()
        self.connect_to_mt5()
        self.last_bar_time = None  # To track the last processed bar time
        self.operate()

    def connect_to_mt5(self):
        resp = mt5.initialize(
            login=REDACTED, password=REDACTED, server=REDACTED
        )
        if resp:
            self.connected = True
        return self.connected

    def calculate_ema(self, prices, period, shift=0):
        """
        Calculate the Exponential Moving Average (EMA) for a given period.

        :param prices: List or array of closing prices.
        :param period: EMA calculation period.
        :param shift: Number of bars to shift the EMA forward.
        :return: List of EMA values, shifted if required.
        """
        if not prices or len(prices) < period:
            raise ValueError("Not enough data points to calculate EMA.")
        
        # Calculate the multiplier
        multiplier = 2 / (period + 1)
    
        # Initialize the EMA with the first price
        ema_values = [prices[0]]  # Seed value is the first price
        print(ema_values)
        # Compute EMA for the rest of the prices
        for price in prices[1:]:
            ema = (price * multiplier) + (ema_values[-1] * (1 - multiplier))
            ema_values.append(ema)
        
        # Apply shift if required
        if shift > 0:
            ema_values = [None] * shift + ema_values[:-shift]  # Shift values forward
        
        ema_values = ema_values[::-1]

        return ema_values

    def get_bars(self, pos=0, quantity=1):
        """
        Retrieve multiple bars from the MT5 API and calculate 8EMA and 20EMA.
        :param pos: Position to start retrieving bars from.
        :param quantity: Number of bars to retrieve with EMA values.
        :return: DataFrame containing the requested bars with EMA values.
        """
        # Calculate how many extra bars are needed for EMA
        max_ema_period = 20  # The longest EMA period used
        extra_bars = max_ema_period - 1  # Extra bars needed for EMA calculation
        total_bars = quantity + extra_bars

        # Fetch bars from MT5
        bars = mt5.copy_rates_from_pos(self.symbol, self.timeframe, pos, total_bars)
        if bars is None or len(bars) < total_bars:
            print("Not enough data to fetch the required bars.")
            return None

        # Convert to DataFrame
        bars = pd.DataFrame(bars[::-1])  # Reverse the order
        bars["time"] = pd.to_datetime(bars["time"], unit="s")
        bars.set_index("time", inplace=True)

        # Calculate 8EMA and 20EMA using the full dataset
        close_prices = bars["close"].tolist()
        bars["8ma"] = self.calculate_ema(prices=close_prices, period=8)
        bars["20ma"] = self.calculate_ema(prices=close_prices, period=20)

        # Return only the requested number of bars
        return bars.iloc[:quantity]

    def operate(self):
        update = "None"
        print(self.get_bars(0, 3))
        return

targets = [
    {
        "symbol": "GBPUSD",
        "timeframe": mt5.TIMEFRAME_M1,
        "pattern_length": 25,
        "balancerisk": 0.03,
        "risklevel": 1 / 2,
        "magic": 1,
        "num_bars": 90000,
        "epochs": 20,
        "batch_size": 32,
        "prediction_interval": 0.001,
    }
]

# Usage:
if __name__ == "__main__":
    for pair in targets:
        threading.Thread(
            target=ForexPredictor,
            args=(
                pair["symbol"],
                pair["timeframe"],
                pair["pattern_length"],
                pair["balancerisk"],
                pair["risklevel"],
                pair["magic"],
                pair["num_bars"],
                pair["epochs"],
                pair["batch_size"],
                pair["prediction_interval"],
            ),
        ).start()


Note the calculate_ema function. and the get_bars function. I am simply getting inaccurate/wrong values.

I want the Exponential Moving Average values for the quantity of bars requested in the get_bars function. I want to access the 8MA and 20MA for the quantity of bars requested. Even if that quantity is only 1. So the function requests at least 20 bars so that this can be calculated. However the values I end up with for the 8MA and 20MA are not the same as my MT5 Moving Average indicator on Exponential mode, (on close).




Thanks in advance.