DEBUG:root:ETH/USDT indicators: EMA10: 45    2417.190656
46    2416.955991
47    2416.705811
48    2416.399300
49    2416.053973
Name: EMA10, dtype: float64, RSI: 45    50.437851
46    45.219767
47    43.335597
48    40.180384
49    37.453444
Name: RSI, dtype: float64, MACD: 45    0.427556
46    0.299296
47    0.169869
48    0.021858
49   -0.135836
Name: MACD, dtype: float64
ERROR:root:Error saving signals for ETH/USDT to database: '24h_change'
Why im I seeing above error wen I run the code below

import os
import threading
import time
import django
# Set the environment variable to point to your project’s settings
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'binancebot.settings')

# Initialize Django
django.setup()

from concurrent.futures import ProcessPoolExecutor, as_completed
import ccxt
import pandas as pd
import numpy as np
import talib as ta
from django.utils import timezone
from .models import Signal
import logging
from multiprocessing import Process, Event
from loguru import logger

# Configure logging
logging.basicConfig(level=logging.DEBUG)
#logger.add("trading_bot.log", rotation="1 MB", compression="zip", retention="10 days")

class SignalGenerator:
    def __init__(self, symbol='BTC/USDT', timeframe='1m', ):
        self.symbol = symbol
        self.timeframe = timeframe
        self.exchange = ccxt.binance({
            'options': {'defaultType': 'future'}  # Configure for futures markets
        })
        logging.debug(f"Initialized SignalGenerator with symbol: {symbol}, timeframe: {timeframe}")

    def fetch_market_data(self):
        try:
            latest_bars = self.exchange.fetch_ohlcv(self.symbol, self.timeframe, limit=50) # Fetch more data
            if latest_bars:
                df = pd.DataFrame(latest_bars, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
                df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
                return df
            else:
                logging.error(f"No market data fetched for {self.symbol}.")
                return pd.DataFrame()
        except Exception as e:
            logging.error(f"Error fetching market data for {self.symbol}: {e}")
            return pd.DataFrame()

    def generate_signals(self, df):
        try:
            # Example: simple moving average crossover
            df['EMA10'] = ta.EMA(df['close'], timeperiod=10)
            df['Smoothed_EMA20'] = df['close'].rolling(window=11). mean()
            df['RSI'] = ta.RSI(df['close'], timeperiod=14)
            df['MACD'], df['MACD_signal'], _ = ta.MACD(df['close'], fastperiod=12, slowperiod=26, signalperiod=9)
            df['Upper_Band'], df['Middle_Band'], df['Lower_Band'] = ta.BBANDS(df['close'])
            df['Stochastic_K'], df['Stochastic_D'] = ta.STOCH(df['high'], df['low'], df['close'])
            
            logging.debug(f"{self.symbol} indicators: EMA10: {df['EMA10'].tail()}, RSI: {df['RSI'].tail()}, MACD: {df['MACD'].tail()}")

        # Buy Signal
            conditions_for_buy = (
                (df['EMA10'] > df['Smoothed_EMA20']) &
                (df['RSI'] < 35) & 
                (df['MACD'] > df['MACD_signal'])  
            )

        # Sell Signal
            conditions_for_sell = ( 
                (df['EMA10'] < df['Smoothed_EMA20']) &
                (df['RSI'] > 65) &
                (df['MACD'] < df['MACD_signal'])  
            )

            df['Signal'] = np.where(conditions_for_buy, 'BUY', np.where(conditions_for_sell, 'SELL', 'HOLD'))
            return df
        except Exception as e:
            logging.error(f"Error generating signals for {self.symbol}: {e}")
            return df

    def save_signals(self, df):
        try:
            last_signal = df.iloc[-1]
            # Save all generated signals to the database
            Signal.objects.update_or_create(
                timestamp=timezone.make_aware(last_signal['timestamp']),
                symbol=self.symbol,
                defaults={
                    'price': last_signal['close'],
                    'signal_type': last_signal['Signal'],
                }
            )
            logging.info(f"Signal saved for {self.symbol}: {last_signal['Signal']}, Change: {last_signal['24h_change']}%")
        except Exception as e:
            logging.error(f"Error saving signals for {self.symbol} to database: {e}")

    def run(self):
        #while not stop_event.is_set():
            df = self.fetch_market_data()
            #logging.debug(df.tail(5))  # Check the last few rows
            if not df.empty:
                df = self.generate_signals(df)
                self.save_signals(df)
            else:
                logging.error("No data fetched, cannot proceed with signal generation.")
            #stop_event.wait(1)  # Check the event every second

def worker(symbol):
    signal_generator = SignalGenerator(symbol=symbol)
    while True:
        try:
            signal_generator.run()
            time.sleep(60) # Avoid hammering the API, adjust to your timeframe
        except Exception as e:
            logging.error(f"An error occurred in worker for {symbol}: {e}")
            time.sleep(60) # Backoff time to handle API limitations
    

def main():
    
    try:
        exchange = ccxt.binance({'options': {'defaultType': 'future'}})
        markets = exchange.load_markets()

# Filter for USDT pairs
        usdt_pairs = [symbol for symbol in markets if symbol.endswith('/USDT')]
        # Fetch 24-hour price change statistics
        #tickers = exchange.fetch_tickers()

        # Collect the price change percentage for each USDT pair
        #symbols = [symbol for symbol, data in tickers.items() if symbol.endswith('/USDT')]
        # Sort symbols by absolute price change percentage
        #sorted_usdt_pairs = sorted(price_changes, key=lambda x: abs(x[1]), reverse=True)
        
        # Extract sorted symbols
        #sorted_usdt_pairs = [(symbol, change) for symbol, change in sorted_symbols]
    
        #for symbol in sorted_usdt_pairs:
            #p = Process(target=worker, args=(symbol, stop_event))
            #processes.append(p)
            #p.start()

        # Wait for the processes to complete
        #for p in processes:
            #p.join()
# Iterate over each USDT pair
        with ProcessPoolExecutor(max_workers=3) as executor:
            #executor.map(worker, usdt_pairs)
         #Make the executor ignore SIGINT in workers and let the main process handle it.
        
            futures = {executor.submit(worker, symbol) for symbol in usdt_pairs}
        #try:
            for future in as_completed(futures):
                symbol = futures[future]
                try:
                    # Make sure each task completes when testing
                    future.result(timeout=360)  # 6 minutes max per execution, customize as needed
                    #future.result()
                except Exception as e:
                    logging.error(f"Error processing symbol {symbol}: {e}")
        #for symbol in usdt_pairs:
            #try:
                #logging.info(f"Processing symbol: {symbol}")
                #signal_generator = SignalGenerator(symbol=symbol)
                #signal_generator.run()
            #except Exception as e:
                #logging.error(f"Error processing symbol {symbol}: {e}")
    except KeyboardInterrupt:
        logging.info("KeyboardInterrupt caught. Setting stop event and terminating all processes.")
        #stop_event.set()
        #for p in processes:
            #p.join()
    except Exception as e:
        logging.error("All processes have been terminated gracefully.")
        


if __name__ == "__main__":
    main()