def _get_tools():
    config = load_test_config()
    AdvancedManager.create_class_list(config)
    evaluator = Evaluator()
    evaluator.set_config(config)
    evaluator.set_symbol("BTC/USDT")
    evaluator.set_time_frame(TimeFrames.ONE_HOUR)
    return evaluator, config
class EvaluatorTaskManager:
    def __init__(self, config,
                 time_frame,
                 global_price_updater,
                 symbol_evaluator,
                 exchange,
                 trading_mode,
                 real_time_ta_eval_list,
                 main_loop,
                 relevant_evaluators=None):

        if relevant_evaluators is None:
            relevant_evaluators = CONFIG_EVALUATORS_WILDCARD
        self.config = config
        self.exchange = exchange
        self.trading_mode = trading_mode
        self.symbol = symbol_evaluator.get_symbol()
        self.time_frame = time_frame
        self.global_price_updater = global_price_updater
        self.symbol_evaluator = symbol_evaluator
        self.main_loop = main_loop

        self.should_save_evaluations = CONFIG_SAVE_EVALUATION in self.config and self.config[CONFIG_SAVE_EVALUATION]

        # notify symbol evaluator
        self.symbol_evaluator.add_evaluator_task_manager(self.exchange, self.time_frame, self.trading_mode, self)

        self.matrix = self.symbol_evaluator.get_matrix(self.exchange)
        self.matrix_exporter = MatrixExporter(self.matrix, self.symbol)

        self.task_name = f"TA TASK MANAGER - {self.symbol} - {self.exchange.get_name()} - {self.time_frame}"
        self.logger = get_logger(self.task_name)

        # Create Evaluator
        self.evaluator = Evaluator()
        self.evaluator.set_config(self.config)
        self.evaluator.set_symbol(self.symbol)
        self.evaluator.set_time_frame(self.time_frame)
        self.evaluator.set_exchange(self.exchange)
        self.evaluator.set_symbol_evaluator(self.symbol_evaluator)

        # Add tasked evaluators that can notify the current task
        self.evaluator.set_social_eval(self.symbol_evaluator.get_crypto_currency_evaluator().get_social_eval_list(),
                                       self)
        self.evaluator.set_real_time_eval(real_time_ta_eval_list, self)

        # Create static evaluators
        self.evaluator.set_ta_eval_list(self.evaluator.get_creator().create_ta_eval_list(self.evaluator,
                                                                                         relevant_evaluators), self)

        # Register in refreshing task
        self.global_price_updater.register_evaluator_task_manager(self.time_frame, self)

    # handle notifications from evaluators, when notified refresh symbol evaluation matrix
    async def notify(self, notifier_name, force_TA_refresh=False, finalize=False, interruption=False):
        if self._should_consider_notification(notifier_name, interruption=interruption):
            self.logger.debug(f"** Notified by {notifier_name} **")
            if force_TA_refresh:
                await self.global_price_updater.force_refresh_data(self.time_frame, self.symbol)
            await self._refresh_eval(notifier_name, finalize=finalize)

    def _should_consider_notification(self, notifier_name, interruption=False):
        if self.get_refreshed_times() > 0:
            if interruption:
                # if notification from interruption (real_time or social evaluator,
                # ensure first that everything is initialized properly
                return_val = self.symbol_evaluator.are_all_timeframes_initialized(self.exchange)
            else:
                return True
        else:
            return_val = False
        if not return_val:
            self.logger.debug(f"Notification by {notifier_name} ignored")
        return return_val

    async def _refresh_eval(self, ignored_evaluator=None, finalize=False):
        # update eval
        await self.evaluator.update_ta_eval(ignored_evaluator)

        # update matrix
        self.refresh_matrix()

        # update strategies matrix
        await self.symbol_evaluator.update_strategies_eval(self.matrix, self.exchange, ignored_evaluator)

        if finalize:
            # calculate the final result
            await self.symbol_evaluator.finalize(self.exchange)

        # save evaluations if option is activated
        self._save_evaluations_if_necessary()

        self.logger.debug(f"MATRIX : {self.matrix.get_matrix()}")

    def refresh_matrix(self):
        self.matrix = self.symbol_evaluator.get_matrix(self.exchange)

        for ta_eval in self.evaluator.get_ta_eval_list():
            if ta_eval.get_is_active():
                ta_eval.ensure_eval_note_is_not_expired()
                self.matrix.set_eval(EvaluatorMatrixTypes.TA, ta_eval.get_name(),
                                     ta_eval.get_eval_note(), self.time_frame)
            else:
                self.matrix.set_eval(EvaluatorMatrixTypes.TA, ta_eval.get_name(),
                                     START_PENDING_EVAL_NOTE, self.time_frame)

        for social_eval in self.evaluator.get_social_eval_list():
            if social_eval.get_is_active():
                social_eval.ensure_eval_note_is_not_expired()
                self.matrix.set_eval(EvaluatorMatrixTypes.SOCIAL, social_eval.get_name(),
                                     social_eval.get_eval_note(), None)
            else:
                self.matrix.set_eval(EvaluatorMatrixTypes.SOCIAL, social_eval.get_name(),
                                     START_PENDING_EVAL_NOTE)

        for real_time_eval in self.evaluator.get_real_time_eval_list():
            if real_time_eval.get_is_active():
                real_time_eval.ensure_eval_note_is_not_expired()
                self.matrix.set_eval(EvaluatorMatrixTypes.REAL_TIME, real_time_eval.get_name(),
                                     real_time_eval.get_eval_note())
            else:
                self.matrix.set_eval(EvaluatorMatrixTypes.REAL_TIME, real_time_eval.get_name(),
                                     START_PENDING_EVAL_NOTE)

    def _save_evaluations_if_necessary(self):
        if self.should_save_evaluations and self.symbol_evaluator.are_all_timeframes_initialized(self.exchange):
            self.matrix_exporter.save()

    def get_refreshed_times(self):
        return self.global_price_updater.get_refreshed_times(self.time_frame, self.symbol)

    def get_evaluator(self):
        return self.evaluator

    def get_global_price_updater(self):
        return self.global_price_updater

    def get_exchange(self):
        return self.exchange

    def get_symbol_evaluator(self):
        return self.symbol_evaluator

    def get_symbol(self):
        return self.symbol
class EvaluatorThreadsManager:
    def __init__(self,
                 config,
                 time_frame,
                 symbol_time_frame_updater_thread,
                 symbol_evaluator,
                 exchange,
                 trading_mode,
                 real_time_ta_eval_list,
                 relevant_evaluators=None):

        if relevant_evaluators is None:
            relevant_evaluators = CONFIG_EVALUATORS_WILDCARD
        self.config = config
        self.exchange = exchange
        self.trading_mode = trading_mode
        self.symbol = symbol_evaluator.get_symbol()
        self.time_frame = time_frame
        self.symbol_time_frame_updater_thread = symbol_time_frame_updater_thread
        self.symbol_evaluator = symbol_evaluator

        self.should_save_evaluations = CONFIG_SAVE_EVALUATION in self.config and self.config[
            CONFIG_SAVE_EVALUATION]

        # notify symbol evaluator
        self.symbol_evaluator.add_evaluator_thread_manager(
            self.exchange, self.time_frame, self.trading_mode, self)

        self.matrix = self.symbol_evaluator.get_matrix(self.exchange)
        self.matrix_exporter = MatrixExporter(self.matrix, self.symbol)

        self.thread_name = f"TA THREAD MANAGER - {self.symbol} - {self.exchange.get_name()} - {self.time_frame}"
        self.logger = get_logger(self.thread_name)

        # Create Evaluator
        self.evaluator = Evaluator()
        self.evaluator.set_config(self.config)
        self.evaluator.set_symbol(self.symbol)
        self.evaluator.set_time_frame(self.time_frame)
        self.evaluator.set_exchange(self.exchange)
        self.evaluator.set_symbol_evaluator(self.symbol_evaluator)

        # Add threaded evaluators that can notify the current thread
        self.evaluator.set_social_eval(
            self.symbol_evaluator.get_crypto_currency_evaluator().
            get_social_eval_list(), self)
        self.evaluator.set_real_time_eval(real_time_ta_eval_list, self)

        # Create static evaluators
        self.evaluator.set_ta_eval_list(
            self.evaluator.get_creator().create_ta_eval_list(
                self.evaluator, relevant_evaluators), self)

        # Register in refreshing threads
        self.symbol_time_frame_updater_thread.register_evaluator_thread_manager(
            self.time_frame, self)

    # handle notifications from evaluators, when notified refresh symbol evaluation matrix
    def notify(self, notifier_name, force_TA_refresh=False):
        if self.get_refreshed_times() > 0:
            self.logger.debug(f"** Notified by {notifier_name} **")
            if force_TA_refresh:
                self.symbol_time_frame_updater_thread.force_refresh_data()
            self._refresh_eval(notifier_name)
        else:
            self.logger.debug(f"Notification by {notifier_name} ignored")

    def _refresh_eval(self, ignored_evaluator=None):
        # update eval
        self.evaluator.update_ta_eval(ignored_evaluator)

        # update matrix
        self.refresh_matrix()

        # update strategies matrix
        self.symbol_evaluator.update_strategies_eval(self.matrix,
                                                     self.exchange,
                                                     ignored_evaluator)

        # calculate the final result
        self.symbol_evaluator.finalize(self.exchange)

        # save evaluations if option is activated
        self._save_evaluations_if_necessary()

        self.logger.debug(f"MATRIX : {self.matrix.get_matrix()}")

    def refresh_matrix(self):
        self.matrix = self.symbol_evaluator.get_matrix(self.exchange)

        for ta_eval in self.evaluator.get_ta_eval_list():
            if ta_eval.get_is_active():
                ta_eval.ensure_eval_note_is_not_expired()
                self.matrix.set_eval(EvaluatorMatrixTypes.TA,
                                     ta_eval.get_name(),
                                     ta_eval.get_eval_note(), self.time_frame)
            else:
                self.matrix.set_eval(EvaluatorMatrixTypes.TA,
                                     ta_eval.get_name(),
                                     START_PENDING_EVAL_NOTE, self.time_frame)

        for social_eval in self.evaluator.get_social_eval_list():
            if social_eval.get_is_active():
                social_eval.ensure_eval_note_is_not_expired()
                self.matrix.set_eval(EvaluatorMatrixTypes.SOCIAL,
                                     social_eval.get_name(),
                                     social_eval.get_eval_note(), None)
            else:
                self.matrix.set_eval(EvaluatorMatrixTypes.SOCIAL,
                                     social_eval.get_name(),
                                     START_PENDING_EVAL_NOTE)

        for real_time_eval in self.evaluator.get_real_time_eval_list():
            if real_time_eval.get_is_active():
                real_time_eval.ensure_eval_note_is_not_expired()
                self.matrix.set_eval(EvaluatorMatrixTypes.REAL_TIME,
                                     real_time_eval.get_name(),
                                     real_time_eval.get_eval_note())
            else:
                self.matrix.set_eval(EvaluatorMatrixTypes.REAL_TIME,
                                     real_time_eval.get_name(),
                                     START_PENDING_EVAL_NOTE)

    def _save_evaluations_if_necessary(self):
        if self.should_save_evaluations and self.symbol_evaluator.are_all_timeframes_initialized(
                self.exchange):
            self.matrix_exporter.save()

    def start_threads(self):
        pass

    def stop_threads(self):
        for thread in self.evaluator.get_real_time_eval_list():
            thread.stop()

    def join_threads(self):
        for thread in self.evaluator.get_real_time_eval_list():
            thread.join()

    def get_refreshed_times(self):
        return self.symbol_time_frame_updater_thread.get_refreshed_times(
            self.time_frame)

    def get_evaluator(self):
        return self.evaluator

    def get_symbol_time_frame_updater_thread(self):
        return self.symbol_time_frame_updater_thread

    def get_exchange(self):
        return self.exchange

    def get_symbol_evaluator(self):
        return self.symbol_evaluator

    def get_symbol(self):
        return self.symbol
class EvaluatorThreadsManager:
    def __init__(self, config,
                 time_frame,
                 symbol_time_frame_updater_thread,
                 symbol_evaluator,
                 exchange,
                 real_time_ta_eval_list,
                 relevant_evaluators=CONFIG_EVALUATORS_WILDCARD):
        self.config = config
        self.exchange = exchange
        self.symbol = symbol_evaluator.get_symbol()
        self.time_frame = time_frame
        self.symbol_time_frame_updater_thread = symbol_time_frame_updater_thread
        self.symbol_evaluator = symbol_evaluator

        # notify symbol evaluator
        self.symbol_evaluator.add_evaluator_thread_manager(self.exchange, self.time_frame, self)

        self.matrix = self.symbol_evaluator.get_matrix(self.exchange)

        self.thread_name = "TA THREAD MANAGER - {0} - {1} - {2}".format(self.symbol,
                                                                        self.exchange.get_name(),
                                                                        self.time_frame)
        self.logger = logging.getLogger(self.thread_name)

        # Create Evaluator
        self.evaluator = Evaluator()
        self.evaluator.set_config(self.config)
        self.evaluator.set_symbol(self.symbol)
        self.evaluator.set_time_frame(self.time_frame)
        self.evaluator.set_exchange(self.exchange)
        self.evaluator.set_symbol_evaluator(self.symbol_evaluator)

        # Add threaded evaluators that can notify the current thread
        self.evaluator.set_social_eval(self.symbol_evaluator.get_crypto_currency_evaluator().get_social_eval_list(),
                                       self)
        self.evaluator.set_real_time_eval(real_time_ta_eval_list, self)

        # Create static evaluators
        self.evaluator.set_ta_eval_list(self.evaluator.get_creator().create_ta_eval_list(self.evaluator,
                                                                                         relevant_evaluators), self)

        # Register in refreshing threads
        self.symbol_time_frame_updater_thread.register_evaluator_thread_manager(self.time_frame, self)

    def get_refreshed_times(self):
        return self.symbol_time_frame_updater_thread.get_refreshed_times(self.time_frame)

    def get_evaluator(self):
        return self.evaluator

    def notify(self, notifier_name):
        if self.get_refreshed_times() > 0:
            self.logger.debug("** Notified by {0} **".format(notifier_name))
            self._refresh_eval(notifier_name)
        else:
            self.logger.debug("Notification by {0} ignored".format(notifier_name))

    def _refresh_eval(self, ignored_evaluator=None):
        # update eval
        self.evaluator.update_ta_eval(ignored_evaluator)

        # update matrix
        self.refresh_matrix()

        # update strategies matrix
        self.symbol_evaluator.update_strategies_eval(self.matrix, self.exchange, ignored_evaluator)

        # calculate the final result
        self.symbol_evaluator.finalize(self.exchange)
        self.logger.debug("MATRIX : {0}".format(self.matrix.get_matrix()))

    def refresh_matrix(self):
        self.matrix = self.symbol_evaluator.get_matrix(self.exchange)

        for ta_eval in self.evaluator.get_ta_eval_list():
            if ta_eval.get_is_active():
                ta_eval.ensure_eval_note_is_not_expired()
                self.matrix.set_eval(EvaluatorMatrixTypes.TA, ta_eval.get_name(),
                                     ta_eval.get_eval_note(), self.time_frame)
            else:
                self.matrix.set_eval(EvaluatorMatrixTypes.TA, ta_eval.get_name(),
                                     START_PENDING_EVAL_NOTE, self.time_frame)

        for social_eval in self.evaluator.get_social_eval_list():
            if social_eval.get_is_active():
                social_eval.ensure_eval_note_is_not_expired()
                self.matrix.set_eval(EvaluatorMatrixTypes.SOCIAL, social_eval.get_name(),
                                     social_eval.get_eval_note(), None)
            else:
                self.matrix.set_eval(EvaluatorMatrixTypes.SOCIAL, social_eval.get_name(),
                                     START_PENDING_EVAL_NOTE)

        for real_time_eval in self.evaluator.get_real_time_eval_list():
            if real_time_eval.get_is_active():
                real_time_eval.ensure_eval_note_is_not_expired()
                self.matrix.set_eval(EvaluatorMatrixTypes.REAL_TIME, real_time_eval.get_name(),
                                     real_time_eval.get_eval_note())
            else:
                self.matrix.set_eval(EvaluatorMatrixTypes.REAL_TIME, real_time_eval.get_name(),
                                     START_PENDING_EVAL_NOTE)

    def start_threads(self):
        pass

    def stop_threads(self):
        for thread in self.evaluator.get_real_time_eval_list():
            thread.stop()

    def join_threads(self):
        for thread in self.evaluator.get_real_time_eval_list():
            thread.join()

    def get_symbol_time_frame_updater_thread(self):
        return self.symbol_time_frame_updater_thread

    def get_exchange(self):
        return self.exchange

    def get_symbol_evaluator(self):
        return self.symbol_evaluator
class EvaluatorThreadsManager:
    def __init__(self, config,
                 symbol,
                 time_frame,
                 symbol_evaluator,
                 exchange,
                 real_time_ta_eval_list):
        self.config = config
        self.symbol = symbol
        self.time_frame = time_frame
        self.symbol_evaluator = symbol_evaluator

        # notify symbol evaluator
        self.symbol_evaluator.add_evaluator_thread(self)

        self.matrix = self.symbol_evaluator.get_matrix()

        # Exchange
        self.exchange = exchange
        # TODO : self.exchange.update_balance(self.symbol)

        self.thread_name = "TA THREAD - {0} - {1} - {2}".format(self.symbol,
                                                                self.exchange.__class__.__name__,
                                                                self.time_frame)
        self.logger = logging.getLogger(self.thread_name)

        # Create Evaluator
        self.evaluator = Evaluator()
        self.evaluator.set_config(self.config)
        self.evaluator.set_symbol(self.symbol)
        self.evaluator.set_time_frame(self.time_frame)
        self.evaluator.set_exchange(self.exchange)
        self.evaluator.set_symbol_evaluator(self.symbol_evaluator)

        # Add threaded evaluators that can notify the current thread
        self.evaluator.set_social_eval(self.symbol_evaluator.get_social_eval_list(), self)
        self.evaluator.set_real_time_eval(real_time_ta_eval_list, self)
        self.evaluator.set_ta_eval_list(self.evaluator.get_creator().create_ta_eval_list(self.evaluator))

        # Create refreshing threads
        self.data_refresher = TimeFrameUpdateDataThread(self)

    def notify(self, notifier_name):
        if self.data_refresher.get_refreshed_times() > 0:
            self.logger.debug("** Notified by {0} **".format(notifier_name))
            self.refresh_eval(notifier_name)
        else:
            self.logger.debug("Notification by {0} ignored".format(notifier_name))

    def refresh_eval(self, ignored_evaluator=None):
        # update eval
        self.evaluator.update_ta_eval(ignored_evaluator)

        # update matrix
        self.refresh_matrix()

        # update strategies matrix
        self.symbol_evaluator.update_strategies_eval(self.matrix, ignored_evaluator)

        # calculate the final result
        self.symbol_evaluator.finalize(self.exchange, self.symbol)
        self.logger.debug("MATRIX : {0}".format(self.matrix.get_matrix()))

    def refresh_matrix(self):
        self.matrix = self.symbol_evaluator.get_matrix()

        for ta_eval in self.evaluator.get_ta_eval_list():
            self.matrix.set_eval(EvaluatorMatrixTypes.TA, ta_eval.get_name(),
                                 ta_eval.get_eval_note(), self.time_frame)

        for social_eval in self.evaluator.get_social_eval_list():
            self.matrix.set_eval(EvaluatorMatrixTypes.SOCIAL, social_eval.get_name(),
                                 social_eval.get_eval_note())

        for real_time_eval in self.evaluator.get_real_time_eval_list():
            self.matrix.set_eval(EvaluatorMatrixTypes.REAL_TIME, real_time_eval.get_name(),
                                 real_time_eval.get_eval_note())

    def start_threads(self):
        self.data_refresher.start()

    def stop_threads(self):
        for thread in self.evaluator.get_real_time_eval_list():
            thread.stop()
        self.data_refresher.stop()

    def join_threads(self):
        for thread in self.evaluator.get_real_time_eval_list():
            thread.join()
        self.data_refresher.join()

    def get_data_refresher(self):
        return self.data_refresher