예제 #1
0
def test_stoploss_from_open():
    open_price_ranges = [
        [0.01, 1.00, 30],
        [1, 100, 30],
        [100, 10000, 30],
    ]
    current_profit_range = [-0.99, 2, 30]
    desired_stop_range = [-0.50, 0.50, 30]

    for open_range in open_price_ranges:
        for open_price in np.linspace(*open_range):
            for desired_stop in np.linspace(*desired_stop_range):

                # -1 is not a valid current_profit, should return 1
                assert stoploss_from_open(desired_stop, -1) == 1

                for current_profit in np.linspace(*current_profit_range):
                    current_price = open_price * (1 + current_profit)
                    expected_stop_price = open_price * (1 + desired_stop)

                    stoploss = stoploss_from_open(desired_stop, current_profit)

                    assert stoploss >= 0
                    assert stoploss <= 1

                    stop_price = current_price * (1 - stoploss)

                    # there is no correct answer if the expected stop price is above
                    # the current price
                    if expected_stop_price > current_price:
                        assert stoploss == 0
                    else:
                        assert isclose(stop_price, expected_stop_price, rel_tol=0.00001)
    def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
                        current_rate: float, current_profit: float, **kwargs) -> float:

        # hard stoploss profit
        HSL = self.pHSL.value
        PF_1 = self.pPF_1.value
        SL_1 = self.pSL_1.value
        PF_2 = self.pPF_2.value
        SL_2 = self.pSL_2.value

        # For profits between PF_1 and PF_2 the stoploss (sl_profit) used is linearly interpolated
        # between the values of SL_1 and SL_2. For all profits above PL_2 the sl_profit value 
        # rises linearly with current profit, for profits below PF_1 the hard stoploss profit is used.

        if (current_profit > PF_2):
            sl_profit = SL_2 + (current_profit - PF_2)
        elif (current_profit > PF_1):
            sl_profit = SL_1 + ((current_profit - PF_1)*(SL_2 - SL_1)/(PF_2 - PF_1))
        else:
            sl_profit = HSL

        if (current_profit > PF_1):
            return stoploss_from_open(sl_profit, current_profit)
        else:
            return stoploss_from_open(HSL, current_profit)
        return stoploss_from_open(HSL, current_profit)
예제 #3
0
def test_stoploss_from_open():
    open_price_ranges = [
        [0.01, 1.00, 30],
        [1, 100, 30],
        [100, 10000, 30],
    ]
    # profit range for long is [-1, inf] while for shorts is [-inf, 1]
    current_profit_range_dict = {'long': [-0.99, 2, 30], 'short': [-2.0, 0.99, 30]}
    desired_stop_range = [-0.50, 0.50, 30]

    for side, current_profit_range in current_profit_range_dict.items():
        for open_range in open_price_ranges:
            for open_price in np.linspace(*open_range):
                for desired_stop in np.linspace(*desired_stop_range):

                    if side == 'long':
                        # -1 is not a valid current_profit, should return 1
                        assert stoploss_from_open(desired_stop, -1) == 1
                    else:
                        # 1 is not a valid current_profit for shorts, should return 1
                        assert stoploss_from_open(desired_stop, 1, True) == 1

                    for current_profit in np.linspace(*current_profit_range):
                        if side == 'long':
                            current_price = open_price * (1 + current_profit)
                            expected_stop_price = open_price * (1 + desired_stop)
                            stoploss = stoploss_from_open(desired_stop, current_profit)
                            stop_price = current_price * (1 - stoploss)
                        else:
                            current_price = open_price * (1 - current_profit)
                            expected_stop_price = open_price * (1 - desired_stop)
                            stoploss = stoploss_from_open(desired_stop, current_profit, True)
                            stop_price = current_price * (1 + stoploss)

                        assert stoploss >= 0
                        # Technically the formula can yield values greater than 1 for shorts
                        # eventhough it doesn't make sense because the position would be liquidated
                        if side == 'long':
                            assert stoploss <= 1

                        # there is no correct answer if the expected stop price is above
                        # the current price
                        if ((side == 'long' and expected_stop_price > current_price)
                                or (side == 'short' and expected_stop_price < current_price)):
                            assert stoploss == 0
                        else:
                            assert isclose(stop_price, expected_stop_price, rel_tol=0.00001)
예제 #4
0
 def custom_stoploss(self, pair: str, trade: 'Trade',
                     current_time: datetime, current_rate: float,
                     current_profit: float, **kwargs) -> float:
     if current_profit > 0.90:
         return stoploss_from_open(0.85, current_profit)
     elif current_profit > 0.80:
         return stoploss_from_open(0.72, current_profit)
     elif current_profit > 0.70:
         return stoploss_from_open(0.62, current_profit)
     elif current_profit > 0.60:
         return stoploss_from_open(0.52, current_profit)
     elif current_profit > 0.50:
         return stoploss_from_open(0.42, current_profit)
     elif current_profit > 0.40:
         return stoploss_from_open(0.32, current_profit)
     elif current_profit > 0.30:
         return stoploss_from_open(0.22, current_profit)
     elif current_profit > 0.20:
         return stoploss_from_open(0.12, current_profit)
     elif current_profit > 0.10:
         return stoploss_from_open(0.05, current_profit)
     return 1
    def custom_stoploss(self, pair: str, trade: 'Trade',
                        current_time: datetime, current_rate: float,
                        current_profit: float, **kwargs) -> float:

        result = 1

        custom_info_pair = self.custom_info[pair]
        if custom_info_pair is not None:
            # using current_time/open_date directly will only work in backtesting/hyperopt.
            # in live / dry-run, we have to search for nearest row before
            tz = custom_info_pair.index.tz
            open_date = trade.open_date_utc if hasattr(
                trade, 'open_date_utc') else trade.open_date.replace(
                    tzinfo=custom_info_pair.index.tz)
            open_date_mask = custom_info_pair.index.unique().get_loc(
                open_date, method='ffill')
            open_df = custom_info_pair.iloc[open_date_mask]

            # trade might be open too long for us to find opening candle
            if (open_df is None or len(open_df) == 0):
                logger.debug("No open_df :(")
                return 1  # oh well

            # stop out if we have reached our take profit limit
            take_profit = open_df['take_profit']
            if (take_profit is not None):
                if current_rate > take_profit:
                    logger.debug("take_profit={}, current={}".format(
                        take_profit, current_rate))
                    return 0.001

            # keep trailing stoploss at -stop_pct from the open price
            stop_pct = open_df['stop_pct']
            if (stop_pct is not None):
                new_stop = stoploss_from_open(-stop_pct, current_profit)
                logger.debug(
                    "open={}, current={}, profit={}, stop_pct={}, stop={}".
                    format(current_rate / (1 + current_profit), current_rate,
                           current_profit, stop_pct,
                           current_rate * (1 - new_stop)))
                if new_stop > 0:
                    result = new_stop

        return result
예제 #6
0
    def custom_stoploss(self, pair: str, trade: 'Trade',
                        current_time: datetime, current_rate: float,
                        current_profit: float, **kwargs) -> float:
        params = self.custom_stop

        trade_dur = int(
            (current_time.timestamp() - trade.open_date_utc.timestamp()) // 60)
        min_profit = trade.calc_profit_ratio(trade.min_rate)
        max_profit = trade.calc_profit_ratio(trade.max_rate)
        profit_diff = current_profit - min_profit
        current_stoploss = trade.stop_loss

        decay_stoploss = cta.linear_growth(params['decay-start'],
                                           params['decay-end'],
                                           params['decay-delay'],
                                           params['decay-time'], trade_dur)

        # enable stoploss in positive profits after threshold to trail as specifed distance
        if params['pos-trail'] == True:
            if current_profit > params['pos-threshold']:
                return current_profit - params['pos-trail-dist']

        if self.config['runmode'].value in ('live', 'dry_run'):
            dataframe, last_updated = self.dp.get_analyzed_dataframe(
                pair=pair, timeframe=self.timeframe)
            roc = dataframe['roc'].iat[-1]
            atr = dataframe['atr'].iat[-1]
            rmi_slow = dataframe['rmi-slow'].iat[-1]
        # If in backtest or hyperopt, get the indicator values out of the trades dict (Thanks @JoeSchr!)
        else:
            roc = self.custom_trade_info[
                trade.pair]['roc'].loc[current_time]['roc']
            atr = self.custom_trade_info[
                trade.pair]['atr'].loc[current_time]['atr']
            rmi_slow = self.custom_trade_info[
                trade.pair]['rmi-slow'].loc[current_time]['rmi-slow']

        if current_profit < params['cur-threshold']:
            # Dynamic bailout based on rate of change
            if (roc / 100) <= params['roc-bail']:
                if params['bail-how'] == 'atr':
                    return ((current_rate - atr) / current_rate) - 1
                elif params['bail-how'] == 'immediate':
                    return 0.001
                else:
                    return min(
                        max(stoploss_from_open(decay_stoploss, current_profit),
                            0.001), current_stoploss)

        # if we might be on a rebound, move the stoploss to the low point or keep it where it was
        if (current_profit >
                min_profit) or roc > 0 or rmi_slow >= params['rmi-trend']:
            if profit_diff > params['cur-min-diff'] and current_profit < 0:
                return stoploss_from_open(min_profit, current_profit)
            return 1

        if current_profit < 0:
            return min(
                max(stoploss_from_open(decay_stoploss, current_profit), 0.001),
                current_stoploss)

        return 1
예제 #7
0
    def custom_stoploss(self, pair: str, trade: 'Trade',
                        current_time: datetime, current_rate: float,
                        current_profit: float, **kwargs) -> float:
        is_bull_market = True

        if self.custom_info and self.MARKET_CAP_REFERENCE_PAIR in self.custom_info and trade:
            # using current_time directly (like below) will only work in backtesting.
            # so check "runmode" to make sure that it's only used in backtesting/hyperopt
            if self.dp and self.dp.runmode.value in ('backtest', 'hyperopt'):
                sar = self.custom_info[self.MARKET_CAP_REFERENCE_PAIR][
                    'sar_1w'].loc[current_time]['sar_1w']
                tema = self.custom_info[self.MARKET_CAP_REFERENCE_PAIR][
                    'tema_1w'].loc[current_time]['tema_1w']
            # in live / dry-run, it'll be really the current time
            else:
                # but we can just use the last entry from an already analyzed dataframe instead
                dataframe, last_updated = self.dp.get_analyzed_dataframe(
                    pair=self.MARKET_CAP_REFERENCE_PAIR,
                    timeframe=self.timeframe)
                # WARNING
                # only use .iat[-1] in live mode, not in backtesting/hyperopt
                # otherwise you will look into the future
                # see: https://www.freqtrade.io/en/latest/strategy-customization/#common-mistakes-when-developing-strategies
                sar = dataframe['sar_1w'].iat[-1]
                tema = dataframe['tema_1w'].iat[-1]

            if tema is not None and sar is not None:
                is_bull_market = tema > sar

        # evaluate highest to lowest, so that highest possible stop is used
        if current_profit > 5.00:
            return -0.2
        elif current_profit > 4.00:
            return stoploss_from_open(3.50, current_profit)
        elif current_profit > 3.50:
            return stoploss_from_open(3.00, current_profit)
        elif current_profit > 3.00:
            return stoploss_from_open(2.50, current_profit)
        elif current_profit > 2.50:
            return stoploss_from_open(2.00, current_profit)
        elif current_profit > 2.00:
            return stoploss_from_open(1.50, current_profit)
        elif current_profit > 1.50:
            return stoploss_from_open(1.25, current_profit)
        elif current_profit > 1.25:
            return stoploss_from_open(1.00, current_profit)
        elif current_profit > 1.00:
            return stoploss_from_open(0.75, current_profit)
        elif current_profit > 0.75:
            return stoploss_from_open(0.50, current_profit)
        elif current_profit > 0.50 and is_bull_market:
            return stoploss_from_open(0.25, current_profit)
        elif current_profit > 0.25 and is_bull_market:
            return stoploss_from_open(0.05, current_profit)
        elif -0.05 < current_profit < 0.05 and not is_bull_market:
            if current_time - timedelta(hours=24 * 7) > trade.open_date_utc:
                return -0.0125
            elif current_time - timedelta(hours=24 * 5) > trade.open_date_utc:
                return -0.025
            elif current_time - timedelta(hours=24 * 3) > trade.open_date_utc:
                return -0.05

        # return maximum stoploss value, keeping current stoploss price unchanged
        return -1