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)
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)
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
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
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
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)
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