From bac4ced382a7083ebb47cec5b3a5ccc38bc67839 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 31 May 2022 14:35:04 +0200 Subject: [PATCH] Ensure follower predictions are persistent and uniquely stored --- freqtrade/freqai/data_drawer.py | 29 +++++++++- freqtrade/freqai/freqai_interface.py | 2 +- freqtrade/templates/FreqaiExampleStrategy.py | 58 ++++++++++++++++---- 3 files changed, 77 insertions(+), 12 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 346dbaaf1..c3b932ed1 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -26,16 +26,20 @@ class FreqaiDataDrawer: This object remains persistent throughout live/dry, unlike FreqaiDataKitchen, which is reinstantiated for each coin. """ - def __init__(self, full_path: Path, pair_whitelist, follow_mode: bool = False): + def __init__(self, full_path: Path, config: dict, follow_mode: bool = False): + self.config = config # dictionary holding all pair metadata necessary to load in from disk self.pair_dict: Dict[str, Any] = {} # dictionary holding all actively inferenced models in memory given a model filename self.model_dictionary: Dict[str, Any] = {} self.model_return_values: Dict[str, Any] = {} self.pair_data_dict: Dict[str, Any] = {} + self.follower_dict: Dict[str, Any] = {} self.full_path = full_path self.follow_mode = follow_mode + if follow_mode: + self.create_follower_dict() self.load_drawer_from_disk() self.training_queue: Dict[str, int] = {} # self.create_training_queue(pair_whitelist) @@ -57,6 +61,29 @@ class FreqaiDataDrawer: with open(self.full_path / str('pair_dictionary.json'), "w") as fp: json.dump(self.pair_dict, fp, default=self.np_encoder) + def save_follower_dict_to_dist(self): + follower_name = self.config.get('bot_name', 'follower1') + with open(self.full_path / str('follower_dictionary-' + + follower_name + '.json'), "w") as fp: + json.dump(self.follower_dict, fp, default=self.np_encoder) + + def create_follower_dict(self): + follower_name = self.config.get('bot_name', 'follower1') + whitelist_pairs = self.config.get('exchange', {}).get('pair_whitelist') + + exists = Path(self.full_path / str('follower_dictionary-' + + follower_name + '.json')).resolve().exists() + + if exists: + logger.info('Found an existing follower dictionary') + + for pair in whitelist_pairs: + self.follower_dict[pair] = {} + + with open(self.full_path / str('follower_dictionary-' + + follower_name + '.json'), "w") as fp: + json.dump(self.follower_dict, fp, default=self.np_encoder) + def np_encoder(self, object): if isinstance(object, np.generic): return object.item() diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 85d9a526c..19aa9ea3c 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -56,7 +56,7 @@ class IFreqaiModel(ABC): self.set_full_path() self.follow_mode = self.freqai_info.get('follow_mode', False) self.data_drawer = FreqaiDataDrawer(Path(self.full_path), - self.config['exchange']['pair_whitelist'], + self.config, self.follow_mode) self.lock = threading.Lock() self.follow_mode = self.freqai_info.get('follow_mode', False) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index ecda10919..daf59fe12 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -242,22 +242,33 @@ class FreqaiExampleStrategy(IStrategy): if trade_candle.empty: return None trade_candle = trade_candle.squeeze() - pair_dict = self.model.bridge.data_drawer.pair_dict + + follow_mode = self.config.get('freqai', {}).get('follow_mode', False) + + if not follow_mode: + pair_dict = self.model.bridge.data_drawer.pair_dict + else: + pair_dict = self.model.bridge.data_drawer.follower_dict + entry_tag = trade.enter_tag if 'prediction' + entry_tag not in pair_dict[pair]: with self.model.bridge.lock: - self.model.bridge.data_drawer.pair_dict[pair][ - 'prediction' + entry_tag] = abs(trade_candle['prediction']) - self.model.bridge.data_drawer.save_drawer_to_disk() + pair_dict[pair]['prediction' + entry_tag] = abs(trade_candle['prediction']) + if not follow_mode: + self.model.bridge.data_drawer.save_drawer_to_disk() + else: + self.model.bridge.data_drawer.save_follower_dict_to_dist() else: if pair_dict[pair]['prediction' + entry_tag] > 0: roi_price = abs(trade_candle['prediction']) else: with self.model.bridge.lock: - self.model.bridge.data_drawer.pair_dict[pair][ - 'prediction' + entry_tag] = abs(trade_candle['prediction']) - self.model.bridge.data_drawer.save_drawer_to_disk() + pair_dict[pair]['prediction' + entry_tag] = abs(trade_candle['prediction']) + if not follow_mode: + self.model.bridge.data_drawer.save_drawer_to_disk() + else: + self.model.bridge.data_drawer.save_follower_dict_to_dist() roi_price = abs(trade_candle['prediction']) roi_time = self.max_roi_time_long.value @@ -269,17 +280,44 @@ class FreqaiExampleStrategy(IStrategy): else: roi_decay += self.linear_roi_offset.value - if current_profit > roi_price: + if current_profit > roi_decay: return 'roi_custom_win' + if current_profit < -roi_decay: + return 'roi_custom_loss' + def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, rate: float, time_in_force: str, exit_reason: str, current_time, **kwargs) -> bool: entry_tag = trade.enter_tag + follow_mode = self.config.get('freqai', {}).get('follow_mode', False) + if not follow_mode: + pair_dict = self.model.bridge.data_drawer.pair_dict + else: + pair_dict = self.model.bridge.data_drawer.follower_dict with self.model.bridge.lock: - self.model.bridge.data_drawer.pair_dict[pair]['prediction' + entry_tag] = 0 - self.model.bridge.data_drawer.save_drawer_to_disk() + pair_dict[pair]['prediction' + entry_tag] = 0 + if not follow_mode: + self.model.bridge.data_drawer.save_drawer_to_disk() + else: + self.model.bridge.data_drawer.save_follower_dict_to_dist() + + return True + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, + time_in_force: str, current_time, entry_tag, + side: str, **kwargs) -> bool: + + df, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = df.iloc[-1].squeeze() + + if side == 'long': + if last_candle['close'] > (last_candle['close'] * (1 + 0.0025)): + return False + else: + if last_candle['close'] < (last_candle['close'] * (1 - 0.0025)): + return False return True