# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement # isort: skip_file # --- Do not remove these libs --- import numpy as np # noqa import pandas as pd # noqa from pandas import DataFrame from freqtrade.strategy.interface import IStrategy # -------------------------------- # Add your lib to import here import talib.abstract as ta import freqtrade.vendor.qtpylib.indicators as qtpylib from datetime import datetime from freqtrade.persistence import Trade import logging logger = logging.getLogger(__name__) class FixedRiskRewardLoss(IStrategy): INTERFACE_VERSION = 3 '\n This strategy uses custom_stoploss() to enforce a fixed risk/reward ratio\n by first calculating a dynamic initial stoploss via ATR - last negative peak\n\n After that, we caculate that initial risk and multiply it with an risk_reward_ratio\n Once this is reached, stoploss is set to it and exit signal is enabled\n\n Also there is a break even ratio. Once this is reached, the stoploss is adjusted to minimize\n losses by setting it to the entry rate + fees.\n ' custom_info = {'risk_reward_ratio': 3.5, 'set_to_break_even_at_profit': 1} use_custom_stoploss = True stoploss = -0.9 def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> float: """ custom_stoploss using a risk/reward ratio """ result = break_even_sl = takeprofit_sl = -1 custom_info_pair = self.custom_info.get(pair) if custom_info_pair is not None: # using current_time/open_date directly via custom_info_pair[trade.open_daten] # would only work in backtesting/hyperopt. # in live/dry-run, we have to search for nearest row before it open_date_mask = custom_info_pair.index.unique().get_loc(trade.open_date_utc, method='ffill') open_df = custom_info_pair.iloc[open_date_mask] # trade might be open too long for us to find opening candle if len(open_df) != 1: return -1 # won't update current stoploss initial_sl_abs = open_df['stoploss_rate'] # calculate initial stoploss at open_date initial_sl = initial_sl_abs / current_rate - 1 # calculate take profit treshold # by using the initial risk and multiplying it risk_distance = trade.open_rate - initial_sl_abs reward_distance = risk_distance * self.custom_info['risk_reward_ratio'] # take_profit tries to lock in profit once price gets over # risk/reward ratio treshold take_profit_price_abs = trade.open_rate + reward_distance # take_profit gets triggerd at this profit take_profit_pct = take_profit_price_abs / trade.open_rate - 1 # break_even tries to set sl at open_rate+fees (0 loss) break_even_profit_distance = risk_distance * self.custom_info['set_to_break_even_at_profit'] # break_even gets triggerd at this profit break_even_profit_pct = (break_even_profit_distance + current_rate) / current_rate - 1 result = initial_sl if current_profit >= break_even_profit_pct: break_even_sl = trade.open_rate * (1 + trade.fee_open + trade.fee_close) / current_rate - 1 result = break_even_sl if current_profit >= take_profit_pct: takeprofit_sl = take_profit_price_abs / current_rate - 1 result = takeprofit_sl return result def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe['atr'] = ta.ATR(dataframe) dataframe['stoploss_rate'] = dataframe['close'] - dataframe['atr'] * 2 self.custom_info[metadata['pair']] = dataframe[['date', 'stoploss_rate']].copy().set_index('date') # all "normal" indicators: # e.g. # dataframe['rsi'] = ta.RSI(dataframe) return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Placeholder Strategy: entrys when SAR is smaller then candle before Based on TA indicators, populates the entry signal for the given dataframe :param dataframe: DataFrame :return: DataFrame with entry column """ # Allways entrys dataframe.loc[:, 'enter_long'] = 1 return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Placeholder Strategy: does nothing Based on TA indicators, populates the exit signal for the given dataframe :param dataframe: DataFrame :return: DataFrame with entry column """ # Never exits dataframe.loc[:, 'exit_long'] = 0 return dataframe