async def run_test_reactions_to_rise_after_over_sold(
            self, pre_sell_eval, started_sell_eval, max_sell_eval,
            start_rise_eval, after_rise_eval):

        sell_then_buy_data, pre_sell, start_sell, max_sell, start_rise = self.data_bank.get_rise_after_over_sold(
        )

        # not started
        await self._set_data_and_check_eval(
            DataBank.reduce_data(sell_then_buy_data, 0, pre_sell),
            pre_sell_eval, False)

        # starts selling
        await self._set_data_and_check_eval(
            DataBank.reduce_data(sell_then_buy_data, 0, start_sell),
            started_sell_eval, True)

        # max selling
        await self._set_data_and_check_eval(
            DataBank.reduce_data(sell_then_buy_data, 0, max_sell),
            max_sell_eval, True)

        # start buying
        await self._set_data_and_check_eval(
            DataBank.reduce_data(sell_then_buy_data, 0, start_rise),
            start_rise_eval, True)

        # bought
        await self._set_data_and_check_eval(sell_then_buy_data,
                                            after_rise_eval, True)
Beispiel #2
0
    def run_test_reactions_to_over_bought_then_dip(self, pre_buy_eval,
                                                   started_buy_eval,
                                                   max_buy_eval,
                                                   start_dip_eval,
                                                   max_dip_eval,
                                                   after_dip_eval):

        # not started, buying started, buying maxed, start dipping, max dip, max: back normal:
        buy_then_sell_data, pre_buy, start_buy, max_buy, start_dip, max_dip = \
            self.data_bank.get_dip_after_over_bought()

        # not started
        self._set_data_and_check_eval(DataBank.reduce_data(buy_then_sell_data, 0, pre_buy), pre_buy_eval, False)

        # starts buying
        self._set_data_and_check_eval(DataBank.reduce_data(buy_then_sell_data, 0, start_buy), started_buy_eval, False)

        # max buying
        self._set_data_and_check_eval(DataBank.reduce_data(buy_then_sell_data, 0, max_buy), max_buy_eval, False)

        # start dipping
        self._set_data_and_check_eval(DataBank.reduce_data(buy_then_sell_data, 0, start_dip), start_dip_eval, False)

        # max dip
        self._set_data_and_check_eval(DataBank.reduce_data(buy_then_sell_data, 0, max_dip), max_dip_eval, True)

        # back normal
        self._set_data_and_check_eval(buy_then_sell_data, after_dip_eval, False)
    async def run_test_reactions_to_dump(self, pre_dump_eval,
                                         slight_dump_started_eval,
                                         heavy_dump_started_eval,
                                         end_dump_eval, after_dump_eval):

        dump_data, pre_dump, start_dump, heavy_dump, end_dump = self.data_bank.get_sudden_dump(
        )

        # not dumped yet
        await self._set_data_and_check_eval(
            DataBank.reduce_data(dump_data, 0, pre_dump), pre_dump_eval, False)

        # starts dumping
        await self._set_data_and_check_eval(
            DataBank.reduce_data(dump_data, 0, start_dump),
            slight_dump_started_eval, True)

        # real dumping
        await self._set_data_and_check_eval(
            DataBank.reduce_data(dump_data, 0, heavy_dump),
            heavy_dump_started_eval, True)

        # end dumping
        await self._set_data_and_check_eval(
            DataBank.reduce_data(dump_data, 0, end_dump), end_dump_eval, True)

        # stopped dumping
        await self._set_data_and_check_eval(dump_data, after_dump_eval, True)
Beispiel #4
0
 def init(self, TA_evaluator_class, data_file=None, test_symbols=["BTC/USDT"]):
     self.evaluator = TA_evaluator_class()
     self.config = load_test_config()
     self.test_symbols = test_symbols
     self.data_bank = DataBank(self.config, data_file, test_symbols)
     self._assert_init()
     self.previous_move_stop = None
Beispiel #5
0
 async def initialize(self, data_file=None):
     self.time_frame = None
     self.evaluator = self.TA_evaluator_class()
     patch.object(self.evaluator, 'get_exchange_symbol_data', new=self._mocked_get_exchange_symbol_data)
     self.data_bank = DataBank(data_file)
     await self.data_bank.initialize()
     self._assert_init()
     self.previous_move_stop = None
Beispiel #6
0
    def _move_and_set_data_and_check_eval(self, data, eval_index, expected_eval_note, check_inferior):
        if self.previous_move_stop is None:
            self.previous_move_stop = 0

        if eval_index > 0:
            # move up to next evaluation
            for i in range(30, eval_index - self.previous_move_stop - 1):
                self.evaluator.set_data(DataBank.reduce_data(data, 0, self.previous_move_stop + i))
                self.evaluator.eval_impl()

        self._set_data_and_check_eval(DataBank.reduce_data(data, 0, eval_index), expected_eval_note, check_inferior)
        self.previous_move_stop = eval_index
 async def initialize(self,
                      TA_evaluator_class,
                      data_file=None,
                      test_symbols=None):
     if test_symbols is None:
         test_symbols = ["BTC/USDT"]
     self.evaluator = TA_evaluator_class()
     self.config = load_test_config()
     self.test_symbols = test_symbols
     self.data_bank = DataBank(self.config, data_file, test_symbols)
     await self.data_bank.initialize()
     self._assert_init()
     self.previous_move_stop = None
    async def run_stress_test_without_exceptions(
            self,
            required_not_neutral_evaluation_ratio=0.75,
            reset_eval_to_none_before_each_eval=True,
            time_limit_seconds=2):
        start_time = timer()
        for symbol in self.test_symbols:
            time_framed_data_list = self.data_bank.get_all_data_for_all_available_time_frames_for_symbol(
                symbol)
            for key, current_time_frame_data in time_framed_data_list.items():
                # start with 0 data dataframe and goes onwards the end of the data
                not_neutral_evaluation_count = 0
                for current_time_in_frame in range(
                        30, len(current_time_frame_data[0])):
                    self.evaluator.set_data(
                        DataBank.reduce_data(current_time_frame_data, 0,
                                             current_time_in_frame))
                    # self.evaluator.set_data(current_time_frame_data[0:current_time_in_frame])
                    if reset_eval_to_none_before_each_eval:
                        # force None value if possible to make sure eval_note is set during eval_impl()
                        self.evaluator.eval_note = None
                    await self.evaluator.eval_impl()

                    assert self.evaluator.eval_note is not None
                    if self.evaluator.eval_note != START_PENDING_EVAL_NOTE:
                        assert not math.isnan(self.evaluator.eval_note)
                    if self.evaluator.eval_note != START_PENDING_EVAL_NOTE:
                        not_neutral_evaluation_count += 1

                assert not_neutral_evaluation_count / len(current_time_frame_data) \
                    >= required_not_neutral_evaluation_ratio
        process_time = timer() - start_time

        assert process_time <= time_limit_seconds
Beispiel #9
0
    def run_test_reactions_to_pump(self, pre_pump_eval,
                                   start_pump_started_eval,
                                   heavy_pump_started_eval,
                                   max_pump_eval,
                                   stop_pump_eval,
                                   start_dip_eval,
                                   dipped_eval):

        # not started, started, heavy pump, max pump, change trend, dipping, max: dipped:
        pump_data, pre_pump, start_dump, heavy_pump, max_pump, change_trend, dipping = self.data_bank.get_sudden_pump()

        # not pumped yet
        self._set_data_and_check_eval(DataBank.reduce_data(pump_data, 0, pre_pump), pre_pump_eval, False)

        # starts pumping
        self._set_data_and_check_eval(DataBank.reduce_data(pump_data, 0, start_dump), start_pump_started_eval, False)

        # real pumping
        self._set_data_and_check_eval(DataBank.reduce_data(pump_data, 0, heavy_pump), heavy_pump_started_eval, False)

        # max pumping
        self._set_data_and_check_eval(DataBank.reduce_data(pump_data, 0, max_pump), max_pump_eval, False)

        # trend reversing
        self._set_data_and_check_eval(DataBank.reduce_data(pump_data, 0, change_trend), stop_pump_eval, True)

        # starts dipping
        self._set_data_and_check_eval(DataBank.reduce_data(pump_data, 0, dipping), start_dip_eval, True)

        # dipped
        self._set_data_and_check_eval(pump_data, dipped_eval, True)
class AbstractTATest:
    __metaclass__ = ABCMeta

    def init(self,
             TA_evaluator_class,
             data_file=None,
             test_symbols=["BTC/USDT"]):
        self.evaluator = TA_evaluator_class()
        self.config = load_test_config()
        self.test_symbols = test_symbols
        self.data_bank = DataBank(self.config, data_file, test_symbols)
        self._assert_init()
        self.previous_move_stop = None

    @abstractmethod
    def init_test_with_evaluator_to_test(self):
        raise NotImplementedError(
            "init_test_with_evaluator_to_test not implemented")

    # replays a whole dataframe set and assert no exceptions are raised
    @abstractmethod
    def test_stress_test(self):
        raise NotImplementedError("stress_test not implemented")

    # checks evaluations when a dump is happening
    @abstractmethod
    def test_reactions_to_dump(self):
        raise NotImplementedError("test_reactions_to_dump not implemented")

    # checks evaluations when a pump is happening
    @abstractmethod
    def test_reactions_to_pump(self):
        raise NotImplementedError("test_reactions_to_pump not implemented")

    # checks evaluations when an asset is over-sold
    @abstractmethod
    def test_reaction_to_rise_after_over_sold(self):
        raise NotImplementedError("test_reaction_to_oversold not implemented")

    # checks evaluations when an asset is over-bought
    @abstractmethod
    def test_reaction_to_over_bought_then_dip(self):
        raise NotImplementedError(
            "test_reaction_to_over_bought_then_dip not implemented")

    # checks evaluations when an asset doing nothing
    @abstractmethod
    def test_reaction_to_flat_trend(self):
        raise NotImplementedError(
            "test_reaction_to_flat_trend not implemented")

    # runs stress test and assert that neutral evaluation ratio is under required_not_neutral_evaluation_ratio and
    # resets eval_note between each run if reset_eval_to_none_before_each_eval set to True
    def run_stress_test_without_exceptions(
            self,
            required_not_neutral_evaluation_ratio=0.75,
            reset_eval_to_none_before_each_eval=True):

        for symbol in self.test_symbols:
            time_framed_data_list = self.data_bank.get_all_data_for_all_available_time_frames_for_symbol(
                symbol)
            for key, current_time_frame_data in time_framed_data_list.items():
                # start with 0 data dataframe and goes onwards the end of the data
                not_neutral_evaluation_count = 0
                for current_time_in_frame in range(
                        len(current_time_frame_data)):

                    self.evaluator.set_data(
                        current_time_frame_data[0:current_time_in_frame])
                    if reset_eval_to_none_before_each_eval:
                        # force None value if possible to make sure eval_note is set during eval_impl()
                        self.evaluator.eval_note = None
                    self.evaluator.eval_impl()

                    assert self.evaluator.eval_note is not None
                    if self.evaluator.eval_note != START_PENDING_EVAL_NOTE:
                        assert not math.isnan(self.evaluator.eval_note)
                    if self.evaluator.eval_note != START_PENDING_EVAL_NOTE:
                        not_neutral_evaluation_count += 1
                assert not_neutral_evaluation_count/len(current_time_frame_data) \
                    >= required_not_neutral_evaluation_ratio

    # test reaction to dump
    def run_test_reactions_to_dump(self, pre_dump_eval,
                                   slight_dump_started_eval,
                                   heavy_dump_started_eval, end_dump_eval,
                                   after_dump_eval):

        dump_data, pre_dump, start_dump, heavy_dump, end_dump = self.data_bank.get_sudden_dump(
        )

        # not dumped yet
        self._set_data_and_check_eval(dump_data[0:pre_dump], pre_dump_eval,
                                      False)

        # starts dumping
        self._set_data_and_check_eval(dump_data[0:start_dump],
                                      slight_dump_started_eval, True)

        # real dumping
        self._set_data_and_check_eval(dump_data[0:heavy_dump],
                                      heavy_dump_started_eval, True)

        # end dumping
        self._set_data_and_check_eval(dump_data[0:end_dump], end_dump_eval,
                                      True)

        # stopped dumping
        self._set_data_and_check_eval(dump_data, after_dump_eval, True)

    # test reaction to pump
    def run_test_reactions_to_pump(self, pre_pump_eval,
                                   start_pump_started_eval,
                                   heavy_pump_started_eval, max_pump_eval,
                                   stop_pump_eval, start_dip_eval,
                                   dipped_eval):

        # not started, started, heavy pump, max pump, change trend, dipping, max: dipped:
        pump_data, pre_pump, start_dump, heavy_pump, max_pump, change_trend, dipping = self.data_bank.get_sudden_pump(
        )

        # not pumped yet
        self._set_data_and_check_eval(pump_data[0:pre_pump], pre_pump_eval,
                                      False)

        # starts pumping
        self._set_data_and_check_eval(pump_data[0:start_dump],
                                      start_pump_started_eval, False)

        # real pumping
        self._set_data_and_check_eval(pump_data[0:heavy_pump],
                                      heavy_pump_started_eval, False)

        # max pumping
        self._set_data_and_check_eval(pump_data[0:max_pump], max_pump_eval,
                                      False)

        # trend reversing
        self._set_data_and_check_eval(pump_data[0:change_trend],
                                      stop_pump_eval, True)

        # starts dipping
        self._set_data_and_check_eval(pump_data[0:dipping], start_dip_eval,
                                      True)

        # dipped
        self._set_data_and_check_eval(pump_data, dipped_eval, True)

    # test reaction to over-sold
    def run_test_reactions_to_rise_after_over_sold(self, pre_sell_eval,
                                                   started_sell_eval,
                                                   max_sell_eval,
                                                   start_rise_eval,
                                                   after_rise_eval):

        sell_then_buy_data, pre_sell, start_sell, max_sell, start_rise = self.data_bank.get_rise_after_over_sold(
        )

        # not started
        self._set_data_and_check_eval(sell_then_buy_data[0:pre_sell],
                                      pre_sell_eval, False)

        # starts selling
        self._set_data_and_check_eval(sell_then_buy_data[0:start_sell],
                                      started_sell_eval, True)

        # max selling
        self._set_data_and_check_eval(sell_then_buy_data[0:max_sell],
                                      max_sell_eval, True)

        # start buying
        self._set_data_and_check_eval(sell_then_buy_data[0:start_rise],
                                      start_rise_eval, True)

        # bought
        self._set_data_and_check_eval(sell_then_buy_data, after_rise_eval,
                                      True)

    # test reaction to over-bought
    def run_test_reactions_to_over_bought_then_dip(
            self, pre_buy_eval, started_buy_eval, max_buy_eval, start_dip_eval,
            max_dip_eval, after_dip_eval):

        # not started, buying started, buying maxed, start dipping, max dip, max: back normal:
        buy_then_sell_data, pre_buy, start_buy, max_buy, start_dip, max_dip = \
            self.data_bank.get_dip_after_over_bought()

        # not started
        self._set_data_and_check_eval(buy_then_sell_data[0:pre_buy],
                                      pre_buy_eval, False)

        # starts buying
        self._set_data_and_check_eval(buy_then_sell_data[0:start_buy],
                                      started_buy_eval, False)

        # max buying
        self._set_data_and_check_eval(buy_then_sell_data[0:max_buy],
                                      max_buy_eval, False)

        # start dipping
        self._set_data_and_check_eval(buy_then_sell_data[0:start_dip],
                                      start_dip_eval, False)

        # max dip
        self._set_data_and_check_eval(buy_then_sell_data[0:max_dip],
                                      max_dip_eval, True)

        # back normal
        self._set_data_and_check_eval(buy_then_sell_data, after_dip_eval,
                                      False)

    # test reaction to flat trend
    def run_test_reactions_to_flat_trend(
            self, eval_start_move_ending_up_in_a_rise, eval_reaches_flat_trend,
            eval_first_micro_up_p1, eval_first_micro_up_p2, eval_micro_down1,
            eval_micro_up1, eval_micro_down2, eval_micro_up2, eval_micro_down3,
            eval_back_normal3, eval_micro_down4, eval_back_normal4,
            eval_micro_down5, eval_back_up5, eval_micro_up6, eval_back_down6,
            eval_back_normal6, eval_micro_down7, eval_back_up7,
            eval_micro_down8, eval_back_up8, eval_micro_down9, eval_back_up9):

        # long data_frame with flat then sudden big rise and then mostly flat for 120 values
        # start move ending up in a rise, reaches flat trend, first micro up p1, first mirco up p2, micro down,
        # micro up, micro down, micro up, micro down, back normal, micro down, back normal, micro down, back up,
        # micro up, back down, back normal, micro down, back up, micro down, back up, micro down, back up
        up_then_flat_data, start_move_ending_up_in_a_rise, reaches_flat_trend, first_micro_up_p1, first_micro_up_p2, \
            micro_down1, micro_up1, micro_down2, micro_up2, micro_down3, back_normal3, micro_down4, back_normal4, \
            micro_down5, back_up5, micro_up6, back_down6, back_normal6, micro_down7, back_up7, micro_down8, back_up8, \
            micro_down9, back_up9 = self.data_bank.get_overall_flat_trend()

        # start_move_ending_up_in_a_rise
        self._set_data_and_check_eval(
            up_then_flat_data[0:start_move_ending_up_in_a_rise],
            eval_start_move_ending_up_in_a_rise, False)
        #  reaches_flat_trend
        self._move_and_set_data_and_check_eval(up_then_flat_data,
                                               reaches_flat_trend,
                                               eval_reaches_flat_trend, False)
        #  first_micro_up_p1
        self._move_and_set_data_and_check_eval(up_then_flat_data,
                                               first_micro_up_p1,
                                               eval_first_micro_up_p1, False)
        #  first_micro_up_p2
        self._move_and_set_data_and_check_eval(up_then_flat_data,
                                               first_micro_up_p2,
                                               eval_first_micro_up_p2, False)
        #  micro_down1
        self._move_and_set_data_and_check_eval(up_then_flat_data, micro_down1,
                                               eval_micro_down1, True)
        #  micro_up1
        self._move_and_set_data_and_check_eval(up_then_flat_data, micro_up1,
                                               eval_micro_up1, False)
        #  micro_down2
        self._move_and_set_data_and_check_eval(up_then_flat_data, micro_down2,
                                               eval_micro_down2, True)
        #  micro_up2
        self._move_and_set_data_and_check_eval(up_then_flat_data, micro_up2,
                                               eval_micro_up2, False)
        #  micro_down3
        self._move_and_set_data_and_check_eval(up_then_flat_data, micro_down3,
                                               eval_micro_down3, True)
        #  back_normal3
        self._move_and_set_data_and_check_eval(up_then_flat_data, back_normal3,
                                               eval_back_normal3, False)
        #  micro_down4
        self._move_and_set_data_and_check_eval(up_then_flat_data, micro_down4,
                                               eval_micro_down4, True)
        #  back_normal4
        self._move_and_set_data_and_check_eval(up_then_flat_data, back_normal4,
                                               eval_back_normal4, False)
        #  micro_down5
        self._move_and_set_data_and_check_eval(up_then_flat_data, micro_down5,
                                               eval_micro_down5, True)
        #  back_up5
        self._move_and_set_data_and_check_eval(up_then_flat_data, back_up5,
                                               eval_back_up5, False)
        #  micro_up6
        self._move_and_set_data_and_check_eval(up_then_flat_data, micro_up6,
                                               eval_micro_up6, False)
        #  back_down6
        self._move_and_set_data_and_check_eval(up_then_flat_data, back_down6,
                                               eval_back_down6, True)
        #  back_normal6
        self._move_and_set_data_and_check_eval(up_then_flat_data, back_normal6,
                                               eval_back_normal6, False)
        #  micro_down7
        self._move_and_set_data_and_check_eval(up_then_flat_data, micro_down7,
                                               eval_micro_down7, True)
        #  back_up7
        self._move_and_set_data_and_check_eval(up_then_flat_data, back_up7,
                                               eval_back_up7, False)
        #  micro_down8
        self._move_and_set_data_and_check_eval(up_then_flat_data, micro_down8,
                                               eval_micro_down8, True)
        #  back_up8
        self._move_and_set_data_and_check_eval(up_then_flat_data, back_up8,
                                               eval_back_up8, False)
        #  micro_down9
        self._move_and_set_data_and_check_eval(up_then_flat_data, micro_down9,
                                               eval_micro_down9, True)
        #  back_up9
        self._move_and_set_data_and_check_eval(up_then_flat_data, back_up9,
                                               eval_back_up9, False)

    def _move_and_set_data_and_check_eval(self, data, eval_index,
                                          expected_eval_note, check_inferior):
        if self.previous_move_stop is None:
            self.previous_move_stop = 0

        if eval_index > 0:
            # move up to next evaluation
            for i in range(eval_index - self.previous_move_stop - 1):
                self.evaluator.set_data(data[0:self.previous_move_stop + i])
                self.evaluator.eval_impl()

        self._set_data_and_check_eval(data[0:eval_index], expected_eval_note,
                                      check_inferior)
        self.previous_move_stop = eval_index

    def _set_data_and_check_eval(self, data, expected_eval_note,
                                 check_inferior):
        self.evaluator.set_data(data)
        self.evaluator.eval_impl()
        if expected_eval_note != -2:
            if check_inferior:
                assert self.evaluator.eval_note == expected_eval_note \
                    or self.evaluator.eval_note <= expected_eval_note
            else:
                assert self.evaluator.eval_note == expected_eval_note \
                    or self.evaluator.eval_note >= expected_eval_note

    def _assert_init(self):
        assert self.evaluator
        assert self.config
        assert self.data_bank
    async def run_test_reactions_to_flat_trend(
            self, eval_start_move_ending_up_in_a_rise, eval_reaches_flat_trend,
            eval_first_micro_up_p1, eval_first_micro_up_p2, eval_micro_down1,
            eval_micro_up1, eval_micro_down2, eval_micro_up2, eval_micro_down3,
            eval_back_normal3, eval_micro_down4, eval_back_normal4,
            eval_micro_down5, eval_back_up5, eval_micro_up6, eval_back_down6,
            eval_back_normal6, eval_micro_down7, eval_back_up7,
            eval_micro_down8, eval_back_up8, eval_micro_down9, eval_back_up9):

        # long data_frame with flat then sudden big rise and then mostly flat for 120 values
        # start move ending up in a rise, reaches flat trend, first micro up p1, first mirco up p2, micro down,
        # micro up, micro down, micro up, micro down, back normal, micro down, back normal, micro down, back up,
        # micro up, back down, back normal, micro down, back up, micro down, back up, micro down, back up
        up_then_flat_data, start_move_ending_up_in_a_rise, reaches_flat_trend, first_micro_up_p1, first_micro_up_p2, \
            micro_down1, micro_up1, micro_down2, micro_up2, micro_down3, back_normal3, micro_down4, back_normal4, \
            micro_down5, back_up5, micro_up6, back_down6, back_normal6, micro_down7, back_up7, micro_down8, back_up8, \
            micro_down9, back_up9 = self.data_bank.get_overall_flat_trend()

        # start_move_ending_up_in_a_rise
        await self._set_data_and_check_eval(
            DataBank.reduce_data(up_then_flat_data, 0,
                                 start_move_ending_up_in_a_rise),
            eval_start_move_ending_up_in_a_rise, False)
        #  reaches_flat_trend
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     reaches_flat_trend,
                                                     eval_reaches_flat_trend,
                                                     False)
        #  first_micro_up_p1
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     first_micro_up_p1,
                                                     eval_first_micro_up_p1,
                                                     False)
        #  first_micro_up_p2
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     first_micro_up_p2,
                                                     eval_first_micro_up_p2,
                                                     False)
        #  micro_down1
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     micro_down1,
                                                     eval_micro_down1, True)
        #  micro_up1
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     micro_up1, eval_micro_up1,
                                                     False)
        #  micro_down2
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     micro_down2,
                                                     eval_micro_down2, True)
        #  micro_up2
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     micro_up2, eval_micro_up2,
                                                     False)
        #  micro_down3
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     micro_down3,
                                                     eval_micro_down3, True)
        #  back_normal3
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     back_normal3,
                                                     eval_back_normal3, False)
        #  micro_down4
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     micro_down4,
                                                     eval_micro_down4, True)
        #  back_normal4
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     back_normal4,
                                                     eval_back_normal4, False)
        #  micro_down5
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     micro_down5,
                                                     eval_micro_down5, True)
        #  back_up5
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     back_up5, eval_back_up5,
                                                     False)
        #  micro_up6
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     micro_up6, eval_micro_up6,
                                                     False)
        #  back_down6
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     back_down6,
                                                     eval_back_down6, True)
        #  back_normal6
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     back_normal6,
                                                     eval_back_normal6, False)
        #  micro_down7
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     micro_down7,
                                                     eval_micro_down7, True)
        #  back_up7
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     back_up7, eval_back_up7,
                                                     False)
        #  micro_down8
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     micro_down8,
                                                     eval_micro_down8, True)
        #  back_up8
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     back_up8, eval_back_up8,
                                                     False)
        #  micro_down9
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     micro_down9,
                                                     eval_micro_down9, True)
        #  back_up9
        await self._move_and_set_data_and_check_eval(up_then_flat_data,
                                                     back_up9, eval_back_up9,
                                                     False)
Beispiel #12
0
class AbstractTATest:
    """
    Reference class for technical analysis black box testing. Defines tests to implement in order to assess a TA
    evaluator's behaviour.
    """
    __metaclass__ = ABCMeta
    ENOUGH_DATA_STARTING_POINT = 30

    # no __init__ constructor for pytest to be able to collect this class
    async def initialize(self, data_file=None):
        self.time_frame = None
        self.evaluator = self.TA_evaluator_class(
            test_utils_config.load_test_tentacles_config())
        patch.object(self.evaluator,
                     'get_exchange_symbol_data',
                     new=self._mocked_get_exchange_symbol_data)
        self.data_bank = DataBank(data_file)
        await self.data_bank.initialize()
        self._assert_init()
        self.previous_move_stop = None

    # replays a whole dataframe set and assert no exceptions are raised
    @staticmethod
    @abstractmethod
    def test_stress_test(evaluator_tester):
        raise NotImplementedError("stress_test not implemented")

    # checks evaluations when a dump is happening
    @staticmethod
    @abstractmethod
    def test_reactions_to_dump(evaluator_tester):
        raise NotImplementedError("test_reactions_to_dump not implemented")

    # checks evaluations when a pump is happening
    @staticmethod
    @abstractmethod
    def test_reactions_to_pump(evaluator_tester):
        raise NotImplementedError("test_reactions_to_pump not implemented")

    # checks evaluations when an asset is over-sold
    @staticmethod
    @abstractmethod
    def test_reaction_to_rise_after_over_sold(evaluator_tester):
        raise NotImplementedError("test_reaction_to_oversold not implemented")

    # checks evaluations when an asset is over-bought
    @staticmethod
    @abstractmethod
    def test_reaction_to_over_bought_then_dip(evaluator_tester):
        raise NotImplementedError(
            "test_reaction_to_over_bought_then_dip not implemented")

    # checks evaluations when an asset doing nothing
    @staticmethod
    @abstractmethod
    def test_reaction_to_flat_trend(evaluator_tester):
        raise NotImplementedError(
            "test_reaction_to_flat_trend not implemented")

    # runs stress test and assert that neutral evaluation ratio is under required_not_neutral_evaluation_ratio and
    # resets eval_note between each run if reset_eval_to_none_before_each_eval set to True. Also ensure the execution
    # time is bellow or equal to the given limit
    async def run_stress_test_without_exceptions(
            self,
            required_not_neutral_evaluation_ratio=0.75,
            reset_eval_to_none_before_each_eval=True,
            time_limit_seconds=15,
            skip_long_time_frames=False):
        try:
            await self.initialize()
            start_time = timer()
            with patch.object(self.evaluator, 'get_exchange_symbol_data', new=self._mocked_get_exchange_symbol_data), \
                    patch.object(self.evaluator, 'evaluation_completed', new=AsyncMock()):
                for symbol in self.data_bank.data_importer.symbols:
                    self.data_bank.default_symbol = symbol
                    self.data_bank.standard_mode(
                        self.ENOUGH_DATA_STARTING_POINT)
                    for time_frame, current_time_frame_data in self.data_bank.origin_ohlcv_by_symbol[
                            symbol].items():
                        if TimeFramesMinutes[time_frame] > TimeFramesMinutes[TimeFrames.THREE_DAYS] and \
                                skip_long_time_frames:
                            continue
                        self.time_frame = time_frame
                        # start with 0 data data frame and goes onwards until the end of the data
                        not_neutral_evaluation_count = 0
                        total_candles_count = len(current_time_frame_data)
                        start_point = self.ENOUGH_DATA_STARTING_POINT + 1
                        if total_candles_count > start_point:
                            for _ in range(start_point, total_candles_count):
                                if reset_eval_to_none_before_each_eval:
                                    # force None value if possible to make sure eval_note is set during eval_impl()
                                    self.evaluator.eval_note = None
                                await self._increment_bank_data_and_call_evaluator(
                                )

                                assert self.evaluator.eval_note is not None
                                if self.evaluator.eval_note != START_PENDING_EVAL_NOTE:
                                    assert not isnan(self.evaluator.eval_note)
                                if self.evaluator.eval_note != START_PENDING_EVAL_NOTE:
                                    not_neutral_evaluation_count += 1

                            assert not_neutral_evaluation_count / (total_candles_count - start_point) >= \
                                required_not_neutral_evaluation_ratio
            process_time = timer() - start_time
            assert process_time <= time_limit_seconds
        finally:
            await self.data_bank.stop()

    # test reaction to dump
    async def run_test_reactions_to_dump(self, pre_dump_eval,
                                         slight_dump_started_eval,
                                         heavy_dump_started_eval,
                                         end_dump_eval, after_dump_eval):
        try:
            await self.initialize()

            self.time_frame, pre_dump, start_dump, heavy_dump, end_dump, stopped_dump = \
                self.data_bank.sudden_dump_mode()

            with patch.object(self.evaluator, 'get_exchange_symbol_data', new=self._mocked_get_exchange_symbol_data), \
                    patch.object(self.evaluator, 'evaluation_completed', new=AsyncMock()):
                # not dumped yet
                await self._set_data_and_check_eval(pre_dump, pre_dump_eval,
                                                    False)

                # starts dumping
                await self._set_data_and_check_eval(start_dump,
                                                    slight_dump_started_eval,
                                                    True)

                # real dumping
                await self._set_data_and_check_eval(heavy_dump,
                                                    heavy_dump_started_eval,
                                                    True)

                # end dumping
                await self._set_data_and_check_eval(end_dump, end_dump_eval,
                                                    True)

                # stopped dumping
                await self._set_data_and_check_eval(stopped_dump,
                                                    after_dump_eval, True)
        finally:
            await self.data_bank.stop()

    # test reaction to pump
    async def run_test_reactions_to_pump(self, pre_pump_eval,
                                         start_pump_started_eval,
                                         heavy_pump_started_eval,
                                         max_pump_eval, stop_pump_eval,
                                         start_dip_eval, dipped_eval):
        try:
            await self.initialize()

            # not started, started, heavy pump, max pump, change trend, dipping, max: dipped:
            self.time_frame, pre_pump, start_dump, heavy_pump, max_pump, change_trend, dipping, dipped = \
                self.data_bank.sudden_pump_mode()

            with patch.object(self.evaluator, 'get_exchange_symbol_data', new=self._mocked_get_exchange_symbol_data), \
                    patch.object(self.evaluator, 'evaluation_completed', new=AsyncMock()):
                # not pumped yet
                await self._set_data_and_check_eval(pre_pump, pre_pump_eval,
                                                    False)

                # starts pumping
                await self._set_data_and_check_eval(start_dump,
                                                    start_pump_started_eval,
                                                    False)

                # real pumping
                await self._set_data_and_check_eval(heavy_pump,
                                                    heavy_pump_started_eval,
                                                    False)

                # max pumping
                await self._set_data_and_check_eval(max_pump, max_pump_eval,
                                                    False)

                # trend reversing
                await self._set_data_and_check_eval(change_trend,
                                                    stop_pump_eval, True)

                # starts dipping
                await self._set_data_and_check_eval(dipping, start_dip_eval,
                                                    True)

                # dipped
                await self._set_data_and_check_eval(dipped, dipped_eval, True)
        finally:
            await self.data_bank.stop()

    # test reaction to over-sold
    async def run_test_reactions_to_rise_after_over_sold(
            self, pre_sell_eval, started_sell_eval, max_sell_eval,
            start_rise_eval, after_rise_eval):
        try:
            await self.initialize()

            self.time_frame, pre_sell, start_sell, max_sell, start_rise, bought = \
                self.data_bank.rise_after_over_sold_mode()

            with patch.object(self.evaluator, 'get_exchange_symbol_data', new=self._mocked_get_exchange_symbol_data), \
                    patch.object(self.evaluator, 'evaluation_completed', new=AsyncMock()):
                # not started
                await self._set_data_and_check_eval(pre_sell, pre_sell_eval,
                                                    False)

                # starts selling
                await self._set_data_and_check_eval(start_sell,
                                                    started_sell_eval, True)

                # max selling
                await self._set_data_and_check_eval(max_sell, max_sell_eval,
                                                    True)

                # start buying
                await self._set_data_and_check_eval(start_rise,
                                                    start_rise_eval, True)

                # bought
                await self._set_data_and_check_eval(bought, after_rise_eval,
                                                    True)
        finally:
            await self.data_bank.stop()

    # test reaction to over-bought
    async def run_test_reactions_to_over_bought_then_dip(
            self, pre_buy_eval, started_buy_eval, max_buy_eval, start_dip_eval,
            max_dip_eval, after_dip_eval):
        try:
            await self.initialize()

            with patch.object(self.evaluator, 'get_exchange_symbol_data', new=self._mocked_get_exchange_symbol_data), \
                    patch.object(self.evaluator, 'evaluation_completed', new=AsyncMock()):
                # not started, buying started, buying maxed, start dipping, max dip, max: back normal:
                self.time_frame, pre_buy, start_buy, max_buy, start_dip, max_dip, normal = \
                    self.data_bank.dip_after_over_bought_mode()

                # not started
                await self._set_data_and_check_eval(pre_buy, pre_buy_eval,
                                                    False)

                # starts buying
                await self._set_data_and_check_eval(start_buy,
                                                    started_buy_eval, False)

                # max buying
                await self._set_data_and_check_eval(max_buy, max_buy_eval,
                                                    False)

                # start dipping
                await self._set_data_and_check_eval(start_dip, start_dip_eval,
                                                    False)

                # max dip
                await self._set_data_and_check_eval(max_dip, max_dip_eval,
                                                    True)

                # back normal
                await self._set_data_and_check_eval(normal, after_dip_eval,
                                                    False)
        finally:
            await self.data_bank.stop()

    # test reaction to flat trend
    async def run_test_reactions_to_flat_trend(
            self, eval_start_move_ending_up_in_a_rise, eval_reaches_flat_trend,
            eval_first_micro_up_p1, eval_first_micro_up_p2, eval_micro_down1,
            eval_micro_up1, eval_micro_down2, eval_micro_up2, eval_micro_down3,
            eval_back_normal3, eval_micro_down4, eval_back_normal4,
            eval_micro_down5, eval_back_up5, eval_micro_up6, eval_back_down6,
            eval_back_normal6, eval_micro_down7, eval_back_up7,
            eval_micro_down8, eval_back_up8, eval_micro_down9, eval_back_up9):
        try:
            await self.initialize()

            # long data_frame with flat then sudden big rise and then mostly flat for 120 values
            # start move ending up in a rise, reaches flat trend, first micro up p1, first mirco up p2, micro down,
            # micro up, micro down, micro up, micro down, back normal, micro down, back normal, micro down, back up,
            # micro up, back down, back normal, micro down, back up, micro down, back up, micro down, back up
            self.time_frame, start_move_ending_up_in_a_rise, reaches_flat_trend, first_micro_up_p1, \
                first_micro_up_p2, micro_down1, micro_up1, micro_down2, micro_up2, micro_down3, back_normal3, \
                micro_down4, back_normal4, micro_down5, back_up5, micro_up6, back_down6, back_normal6, micro_down7, \
                back_up7, micro_down8, back_up8, micro_down9, back_up9 = self.data_bank.overall_flat_trend_mode()

            with patch.object(self.evaluator, 'get_exchange_symbol_data', new=self._mocked_get_exchange_symbol_data), \
                    patch.object(self.evaluator, 'evaluation_completed', new=AsyncMock()):
                # start_move_ending_up_in_a_rise
                await self._set_data_and_check_eval(
                    start_move_ending_up_in_a_rise,
                    eval_start_move_ending_up_in_a_rise, False)
                #  reaches_flat_trend
                await self._move_and_set_data_and_check_eval(
                    reaches_flat_trend, eval_reaches_flat_trend, False)
                #  first_micro_up_p1
                await self._move_and_set_data_and_check_eval(
                    first_micro_up_p1, eval_first_micro_up_p1, False)
                #  first_micro_up_p2
                await self._move_and_set_data_and_check_eval(
                    first_micro_up_p2, eval_first_micro_up_p2, False)
                #  micro_down1
                await self._move_and_set_data_and_check_eval(
                    micro_down1, eval_micro_down1, True)
                #  micro_up1
                await self._move_and_set_data_and_check_eval(
                    micro_up1, eval_micro_up1, False)
                #  micro_down2
                await self._move_and_set_data_and_check_eval(
                    micro_down2, eval_micro_down2, True)
                #  micro_up2
                await self._move_and_set_data_and_check_eval(
                    micro_up2, eval_micro_up2, False)
                #  micro_down3
                await self._move_and_set_data_and_check_eval(
                    micro_down3, eval_micro_down3, True)
                #  back_normal3
                await self._move_and_set_data_and_check_eval(
                    back_normal3, eval_back_normal3, False)
                #  micro_down4
                await self._move_and_set_data_and_check_eval(
                    micro_down4, eval_micro_down4, True)
                #  back_normal4
                await self._move_and_set_data_and_check_eval(
                    back_normal4, eval_back_normal4, False)
                #  micro_down5
                await self._move_and_set_data_and_check_eval(
                    micro_down5, eval_micro_down5, True)
                #  back_up5
                await self._move_and_set_data_and_check_eval(
                    back_up5, eval_back_up5, False)
                #  micro_up6
                await self._move_and_set_data_and_check_eval(
                    micro_up6, eval_micro_up6, False)
                #  back_down6
                await self._move_and_set_data_and_check_eval(
                    back_down6, eval_back_down6, True)
                #  back_normal6
                await self._move_and_set_data_and_check_eval(
                    back_normal6, eval_back_normal6, False)
                #  micro_down7
                await self._move_and_set_data_and_check_eval(
                    micro_down7, eval_micro_down7, True)
                #  back_up7
                await self._move_and_set_data_and_check_eval(
                    back_up7, eval_back_up7, False)
                #  micro_down8
                await self._move_and_set_data_and_check_eval(
                    micro_down8, eval_micro_down8, True)
                #  back_up8
                await self._move_and_set_data_and_check_eval(
                    back_up8, eval_back_up8, False)
                #  micro_down9
                await self._move_and_set_data_and_check_eval(
                    micro_down9, eval_micro_down9, True)
                #  back_up9
                await self._move_and_set_data_and_check_eval(
                    back_up9, eval_back_up9, False)
        finally:
            await self.data_bank.stop()

    def _mocked_get_exchange_symbol_data(self, exchange, exchange_id, symbol):
        return self.data_bank.symbol_data

    async def _call_evaluator(self):
        last_candle = self.data_bank.get_last_candle_for_default_symbol(
            self.time_frame)
        await self.evaluator.evaluator_ohlcv_callback(
            self.data_bank.exchange_name, "0a", "Bitcoin",
            self.data_bank.default_symbol, self.time_frame.value, last_candle)

    async def _set_bank_data_and_call_evaluator(self, end_index):
        self.data_bank.set_data_for_default_symbol(self.time_frame, end_index)
        await self._call_evaluator()

    async def _increment_bank_data_and_call_evaluator(self):
        self.data_bank.increment_data_for_default_symbol(self.time_frame)
        await self._call_evaluator()

    async def _move_and_set_data_and_check_eval(self, eval_index,
                                                expected_eval_note,
                                                check_inferior):
        if self.previous_move_stop is None:
            self.previous_move_stop = 0

        if eval_index > 0:
            # move up to next evaluation
            for i in range(30, eval_index - self.previous_move_stop - 1):
                await self._set_bank_data_and_call_evaluator(
                    self.previous_move_stop + i)

        await self._set_data_and_check_eval(eval_index, expected_eval_note,
                                            check_inferior)
        self.previous_move_stop = eval_index

    async def _set_data_and_check_eval(self, end_index, expected_eval_note,
                                       check_inferior):
        await self._set_bank_data_and_call_evaluator(end_index)
        if expected_eval_note != -2:
            if check_inferior:
                assert self.evaluator.eval_note == expected_eval_note or self.evaluator.eval_note <= expected_eval_note
            else:
                assert self.evaluator.eval_note == expected_eval_note or self.evaluator.eval_note >= expected_eval_note

    def _assert_init(self):
        assert self.evaluator
        assert self.data_bank