Timeframe
1h
Direction
Long Only
Stoploss
-99.0%
Trailing Stop
No
ROI
0m: 10000.0%
Interface Version
3
Startup Candles
N/A
Indicators
0
freqtrade/freqtrade-strategies
freqtrade/freqtrade-strategies
freqtrade/freqtrade-strategies
this is an example class, implementing a PSAR based trailing stop loss you are supposed to take the `custom_stoploss()` and `populate_indicators()` parts and adapt it to your own strategy
freqtrade/freqtrade-strategies
from freqtrade.strategy import IStrategy, DecimalParameter, IntParameter, stoploss_from_open
import logging
from pandas import DataFrame
from freqtrade.resolvers import StrategyResolver
from itertools import combinations
from functools import reduce
from freqtrade.persistence import Trade
from datetime import datetime
logger = logging.getLogger(__name__)
STRATEGIES = ['SMAOffsetV2', 'MADisplaceV3']
STRAT_COMBINATIONS = reduce(lambda x, y: list(combinations(STRATEGIES, y)) + x, range(len(STRATEGIES) + 1), [])
MAX_COMBINATIONS = len(STRAT_COMBINATIONS) - 2
class Chained(IStrategy):
INTERFACE_VERSION = 3
loaded_strategies = {}
informative_timeframe = '1h'
entry_action_diff_threshold = DecimalParameter(0, 1, default=0, decimals=2, optimize=True, load=True)
entry_strategies = IntParameter(0, MAX_COMBINATIONS, default=0, optimize=True, load=True)
# trailing stoploss hyperopt parameters
# hard stoploss profit
exit_HSL = DecimalParameter(-0.2, -0.04, default=-0.08, decimals=3, optimize=True, load=True)
# profit threshold 1, trigger point, SL_1 is used
exit_PF_1 = DecimalParameter(0.008, 0.02, default=0.016, decimals=3, optimize=True, load=True)
exit_SL_1 = DecimalParameter(0.008, 0.02, default=0.011, decimals=3, optimize=True, load=True)
# profit threshold 2, SL_2 is used
exit_PF_2 = DecimalParameter(0.04, 0.1, default=0.08, decimals=3, optimize=True, load=True)
exit_SL_2 = DecimalParameter(0.02, 0.07, default=0.04, decimals=3, optimize=True, load=True)
stoploss = -0.99 # effectively disabled.
exit_profit_offset = 0.001 # it doesn't meant anything, just to guarantee there is a minimal profit.
use_exit_signal = False
ignore_roi_if_entry_signal = False
exit_profit_only = False
# Trailing stoploss
trailing_stop = False
trailing_only_offset_is_reached = False
trailing_stop_positive = 0.01
trailing_stop_positive_offset = 0.025
# Custom stoploss
use_custom_stoploss = True
# Run "populate_indicators()" only for new candle.
process_only_new_candles = True
# Number of candles the strategy requires before producing valid signals
startup_candle_count: int = 200
minimal_roi = {'0': 100.0}
entry_params = {}
exit_params = {}
protections = [{'method': 'CooldownPeriod', 'stop_duration_candles': 2}, {'method': 'StoplossGuard', 'lookback_period_candles': 100, 'trade_limit': 4, 'stop_duration_candles': 10, 'only_per_pair': True}]
def __init__(self, config: dict) -> None:
super().__init__(config)
logger.info(f'Buy stratrategies: {STRAT_COMBINATIONS[self.entry_strategies.value]}')
def informative_pairs(self):
pairs = self.dp.current_whitelist()
informative_pairs = [(pair, self.informative_timeframe) for pair in pairs]
return informative_pairs
def get_strategy(self, strategy_name):
strategy = self.loaded_strategies.get(strategy_name)
if not strategy:
config = self.config
config['strategy'] = strategy_name
strategy = StrategyResolver.load_strategy(config)
strategy.dp = self.dp
strategy.wallets = self.wallets
self.loaded_strategies[strategy_name] = strategy
return strategy
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
strategies = STRAT_COMBINATIONS[self.entry_strategies.value]
for strategy_name in strategies:
strategy = self.get_strategy(strategy_name)
strategy_indicators = strategy.advise_indicators(dataframe, metadata)
dataframe[f'strat_entry_signal_{strategy_name}'] = strategy.advise_entry(strategy_indicators, metadata)['enter_long']
dataframe['enter_long'] = (dataframe.filter(like='strat_entry_signal_').mean(axis=1) > self.entry_action_diff_threshold.value).astype(int)
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['exit_long'] = 0
return dataframe
def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> float:
"""
new custom stoploss, both hard and trailing functions. Trailing stoploss first rises at a slower
rate than the current rate until a profit threshold is reached, after which it rises at a constant
percentage as per a normal trailing stoploss. This allows more margin for pull-backs during a rise.
"""
# hard stoploss profit
HSL = self.exit_HSL.value
PF_1 = self.exit_PF_1.value
SL_1 = self.exit_SL_1.value
PF_2 = self.exit_PF_2.value
SL_2 = self.exit_SL_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:
stoploss = stoploss_from_open(sl_profit, current_profit)
else:
stoploss = stoploss_from_open(HSL, current_profit)
return stoploss or stoploss_from_open(HSL, current_profit) or 1