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', price_change_24h=0):
        self.symbol = symbol
        self.timeframe = timeframe
        self.price_change_24h = price_change_24h
        self.exchange = ccxt.binance({
            'options': {'defaultType': 'future'}  # Configure for futures markets
        })
        logging.debug(f"Initialized SignalGenerator with symbol: {symbol}, timeframe: {timeframe}, 24h change: {price_change_24h}%")

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

    def generate_signals(self, df):
        try:
            # Example: simple moving average crossover
            df['EMA11'] = ta.EMA(df['close'], timeperiod=11)
            df['Smoothed_EMA11'] = 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: EMA11: {df['EMA11'].tail()}, RSI: {df['RSI'].tail()}, MACD: {df['MACD'].tail()}")

        # Buy Signal
            conditions_for_buy = (
                (df['EMA11'] > df['Smoothed_EMA11']) &
                (df['RSI'] < 35) &
                (df['MACD'] > df['MACD_signal']) &
                #(df['close'] < df['Lower_Band']) &
                (df['Stochastic_K'] < 25)
            )

        # Sell Signal
            conditions_for_sell = (
                (df['EMA11'] < df['Smoothed_EMA11']) &
                (df['RSI'] > 55) &
                (df['MACD'] < df['MACD_signal']) &
                #(df['close'] > df['Upper_Band']) &
                (df['Stochastic_K'] > 70)
            )

            df['Signal'] = np.where(conditions_for_buy, 'BUY', np.where(conditions_for_sell, 'SELL', 'HOLD'))
            df['24h_change'] = self.price_change_24h
            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'],
                    'price_change_24h': last_signal['24h_change'],
                }
            )
            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()
            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, price_change_24h):
    signal_generator = SignalGenerator(symbol=symbol, price_change_24h=price_change_24h)
    #signal_generator.run()
    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():
    #stop_event = Event()
    #processes = []

    #def signal_handler(sig, frame):
        #logging.info("KeyboardInterrupt (SIGINT) received. Requesting shutdown.")
        #stop_event.set()  
# Fetch all market symbols from Binance Futures
    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()
        price_changes = []

        # Collect the price change percentage for each USDT pair
        for symbol, data in tickers.items():
            if symbol.endswith('/USDT'):
                price_change_percent = float(data['percentage'])  # Parse to float for accurate sorting
                price_changes.append((symbol, price_change_percent))

        # Sort symbols by absolute price change percentage
        sorted_symbols = 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 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() 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, change): symbol for symbol, change in sorted_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()

The above code is able to fetch crypto prices but it is not generating signals, why?