Timeframe
1h
Direction
Long & Short
Stoploss
-29.1%
Trailing Stop
No
ROI
0m: 7.0%, 120m: 14.0%, 240m: 21.0%, 360m: 28.0%
Interface Version
3
Startup Candles
N/A
Indicators
5
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
# isort: skip_file
# --- Do not remove these libs ---
import math
import numpy as np # noqa
import pandas as pd # noqa
pd.options.mode.chained_assignment = None
from pandas import DataFrame
from typing import Optional, Union
from datetime import datetime
from freqtrade.persistence import Trade
import logging
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
IStrategy, IntParameter, stoploss_from_open)
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
logger = logging.getLogger(__name__)
def smi_trend(df: DataFrame, k_length=9, d_length=3, smoothing_type='EMA', smoothing=10):
ll = df['low'].rolling(window=k_length).min()
hh = df['high'].rolling(window=k_length).max()
diff = hh - ll
rdiff = df['close'] - (hh + ll) / 2
avgrel = rdiff.ewm(span=d_length).mean().ewm(span=d_length).mean()
avgdiff = diff.ewm(span=d_length).mean().ewm(span=d_length).mean()
smi = np.where(avgdiff != 0, (avgrel / (avgdiff / 2) * 100), 0)
if smoothing_type == 'SMA':
smi_ma = ta.SMA(smi, timeperiod=smoothing)
elif smoothing_type == 'EMA':
smi_ma = ta.EMA(smi, timeperiod=smoothing)
elif smoothing_type == 'WMA':
smi_ma = ta.WMA(smi, timeperiod=smoothing)
elif smoothing_type == 'DEMA':
smi_ma = ta.DEMA(smi, timeperiod=smoothing)
elif smoothing_type == 'TEMA':
smi_ma = ta.TEMA(smi, timeperiod=smoothing)
else:
raise ValueError("Choose an MA Type: 'SMA', 'EMA', 'WMA', 'DEMA', 'TEMA'")
conditions = [
(np.greater(smi, 0) & np.greater(smi, smi_ma)), # (2) Bull
(np.less(smi, 0) & np.greater(smi, smi_ma)), # (1) Possible Bullish Reversal
(np.greater(smi, 0) & np.less(smi, smi_ma)), # (-1) Possible Bearish Reversal
(np.less(smi, 0) & np.less(smi, smi_ma)) # (-2) Bear
]
smi_trend = np.select(conditions, [2, 1, -1, -2])
return smi, smi_ma, smi_trend
class SimpleFutures(IStrategy):
INTERFACE_VERSION = 3
timeframe = '1h'
can_short = True
use_custom_stoploss=False
process_only_new_candles = True
use_exit_signal = False
exit_profit_only = False
startup_candle_count: int = 0
stoploss = -0.291 # we use custom stoploss, but no lower this deadline, custom_stoploss will respect this stoploss
order_types = {
'entry': 'market',
'exit': 'market',
'stoploss': 'market',
'stoploss_on_exchange': False
}
minimal_roi = {
"360": 0.28,
"240": 0.21,
"120": 0.14,
"0": 0.07
}
#pullback_detect_method = CategoricalParameter(['stdev_outlier', 'pct_outlier', 'candle_body'], default = 'pct_outlier', space = 'buy', optimize = True)
# SMI params
smi_k_length = IntParameter(1, 99, default=9, space="buy", optimize=True)
smi_d_length = IntParameter(1, 99, default=3, space="buy", optimize=True)
ma_smoothy_type = CategoricalParameter(['SMA', 'EMA', 'WMA', 'DEMA', 'TEMA'], default = 'EMA', space = 'buy', optimize = True)
smi_smooth_length = IntParameter(1, 99, default=10, space="buy", optimize=True)
## Trailing params
# https://discordapp.com/channels/700048804539400213/852593312116375642/1053608836369502278
# it definitely makes the trailing stop less sensitive to in-candle moves and avoids getting stopped out too early
is_optimize_custom_SL = True
pHSL = DecimalParameter(-0.200, -0.040, default=-0.08, decimals=3, space='sell', load=True, optimize=is_optimize_custom_SL)
pPF_1 = DecimalParameter(0.008, 0.030, default=0.016, decimals=3, space='sell', load=True, optimize=is_optimize_custom_SL)
pSL_1 = DecimalParameter(0.008, 0.030, default=0.011, decimals=3, space='sell', load=True, optimize=is_optimize_custom_SL)
# profit threshold 2, SL_2 is used
pPF_2 = DecimalParameter(0.050, 0.200, default=0.080, decimals=3, space='sell', load=True, optimize=is_optimize_custom_SL)
pSL_2 = DecimalParameter(0.030, 0.200, default=0.040, decimals=3, space='sell', load=True, optimize=is_optimize_custom_SL)
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['smi'], dataframe['smi_ma'], dataframe['smi_trend'] = smi_trend(dataframe, self.smi_k_length.value, self.smi_d_length.value, self.ma_smoothy_type.value)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(qtpylib.crossed_above(dataframe['smi_trend'], 0))
),
['enter_long', 'enter_tag']
] = (1, 'smi_long')
dataframe.loc[
(
(qtpylib.crossed_below(dataframe['smi_trend'], 0))
),
['enter_short', 'enter_tag']
] = (1, 'smi_short')
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
return dataframe
def leverage(self, pair: str, current_time: datetime, current_rate: float,
proposed_leverage: float, max_leverage: float, entry_tag: Optional[str], side: str,
**kwargs) -> float:
return 3.0
def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
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
dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe)
current_candle = dataframe.iloc[-1].squeeze()
current_profit = trade.calc_profit_ratio(current_candle['close'])
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 self.can_short:
if (-1 + ((1 - sl_profit) / (1 - current_profit))) <= 0:
return 1
else:
if (1 - ((1 + sl_profit) / (1 + current_profit))) <= 0:
return 1
return stoploss_from_open(sl_profit, current_profit, is_short=trade.is_short) or 1