I'm trying to create a minimum time delay between each position in a basket of positions, but keep getting this error:

During the algorithm initialization, the following exception has occurred: 'ForexCFDAlgorithm' object has no attribute 'TimeBasedPositionEntry'  at Initialize    self.TimeBasedPositionEntry)   at Python.Runtime.PythonException.ThrowLastAsClrException() at src\runtime\PythonException.cs:line 52   at Python.Runtime.PyObject.Invoke(PyTuple args in main.py: line 28 'ForexCFDAlgorithm' object has no attribute 'TimeBasedPositionEntry'

Here's the algo code in its entirety:

from AlgorithmImports import *


 

class ForexCFDAlgorithm(QCAlgorithm):

    def Initialize(self):

        # Initialization settings

        self.SetStartDate(2020, 1, 1)

        self.SetCash(100000)


 

        # Add Forex symbol

        self.symbol = self.AddForex("EURUSD", Resolution.Daily).Symbol

       

        # Indicators

        self.monthly_ema = self.EMA(self.symbol, 10, Resolution.Daily)

        self.last_monthly_ema_update = self.Time.month

        self.daily_ema = self.EMA(self.symbol, 10, Resolution.Daily)

        self.atr = self.ATR(self.symbol, 100, Resolution.Daily)

       

        # State variables

        self.is_long_term_bullish = False

        self.batch_positions = []

        self.batch_stop_loss = 0

        self.batch_entry_prices = []

        self.last_position_time = self.Time

        self.trailing_stop = 0


 

        # Schedule function for every 120 minutes

        self.Schedule.On(self.DateRules.EveryDay(self.symbol),

                         self.TimeRules.Every(timedelta(minutes=120)),

                         self.TimeBasedPositionEntry)


 

def UpdateMonthlyEMA(self, data):

    current_month = self.Time.month

    if self.last_monthly_ema_update != current_month:

        self.monthly_ema.Update(data[self.symbol])

        self.last_monthly_ema_update = current_month


 

def OnData(self, data):

    # Ensure data for the symbol is available

    if not self.symbol in data:

        return

    self.UpdateMonthlyEMA(data)


 

    # Check for monthly trend and update long term direction

    if self.monthly_ema.IsReady:

        self.is_long_term_bullish = data[self.symbol].Close > self.monthly_ema.Current.Value


 

    # Execute strategy based on daily data

    if self.daily_ema.IsReady and self.atr.IsReady:

        self.ExecuteStrategy(data)



 

    def ExecuteStrategy(self, data):

        # Entry logic based on long-term trend and daily EMA

        if not self.atr.IsReady or not self.daily_ema.IsReady:

            return  # Ensure that the ATR and EMA indicators are ready


 

        # Check for long-term bullish trend and a positive crossover on daily EMA

        if self.is_long_term_bullish and data[self.symbol].Close > self.daily_ema.Current.Value:

            # Check if it's time to enter a new batch position

            if len(self.batch_positions) < 5 and (self.Time - self.last_position_time) >= timedelta(minutes=120):

                self.EnterPosition('Long')

   

        # Check for long-term bearish trend and a negative crossover on daily EMA

        elif not self.is_long_term_bullish and data[self.symbol].Close < self.daily_ema.Current.Value:

            # Check if it's time to enter a new batch position

            if len(self.batch_positions) < 5 and (self.Time - self.last_position_time) >= timedelta(minutes=120):

                self.EnterPosition('Short')


 

        # Update trailing stop and manage the batch

        self.UpdateTrailingStopAndManageBatch()


 

    def OnData(self, data):

        # Ensure data for the symbol is available

        if not self.symbol in data:

            return


 

        # Check for monthly trend and update long term direction

        if self.monthly_ema.IsReady:

            self.is_long_term_bullish = data[self.symbol].Close > self.monthly_ema.Current.Value


 

        # Execute strategy based on daily data

        if self.daily_ema.IsReady and self.atr.IsReady:

            self.ExecuteStrategy(data)


 

    def ExecuteTrailingStopLoss(self):

        # Assuming the trailing stop is based on the ATR

        atr_value = self.atr.Current.Value

        trailing_stop_distance = 3 * atr_value  # Example multiplier


 

        # Update trailing stop for each position

        for price, size in self.batch_entry_prices:

            if self.Portfolio[self.symbol].IsLong:

                # For long positions

                self.trailing_stop = max(self.trailing_stop, price - trailing_stop_distance)

            else:

                # For short positions

                self.trailing_stop = min(self.trailing_stop, price + trailing_stop_distance)


 

        # Check if the current price has hit the trailing stop

        current_price = self.Securities[self.symbol].Price

        if (self.Portfolio[self.symbol].IsLong and current_price <= self.trailing_stop) or \

        (self.Portfolio[self.symbol].IsShort and current_price >= self.trailing_stop):

            self.Liquidate(self.symbol)

            self.batch_positions.clear()

            self.batch_entry_prices.clear()


 

    def EnterPosition(self, direction):

        # ... [Existing position size and stop-loss calculation]


 

        # Enter the trade

        if direction == 'Long':

            self.Buy(self.symbol, lot_size)

        else:

            self.Sell(self.symbol, lot_size)


 

        # Add this position to batch tracking

        self.batch_positions.append(self.symbol)

        self.batch_entry_prices.append((self.Securities[self.symbol].Price, lot_size))


 

    def TimeBasedPositionEntry(self):

        # Check if it's time to consider a new position

        if self.Time - self.last_position_time >= timedelta(minutes=120):

            # Check the strategy conditions

            if self.is_long_term_bullish and self.Securities[self.symbol].Price > self.daily_ema.Current.Value:

                self.EnterPosition('Long')

            elif not self.is_long_term_bullish and self.Securities[self.symbol].Price < self.daily_ema.Current.Value:

                self.EnterPosition('Short')