Timeframe
3m
Direction
Long Only
Stoploss
-99.0%
Trailing Stop
No
ROI
0m: 10.0%, 423m: 3.0%, 751m: 1.0%
Interface Version
N/A
Startup Candles
N/A
Indicators
2
freqtrade/freqtrade-strategies
This strategy uses custom_stoploss() to enforce a fixed risk/reward ratio by first calculating a dynamic initial stoploss via ATR - last negative peak
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
freqtrade/freqtrade-strategies
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
# --- Do not remove these libs ---
import numpy as np # noqa
import pandas as pd # noqa
pd.options.mode.chained_assignment = None # default='warn'
from pandas import DataFrame
from freqtrade.strategy import IStrategy, merge_informative_pair, informative
from freqtrade.strategy import CategoricalParameter, DecimalParameter, IntParameter, stoploss_from_open
# --------------------------------
# Add your lib to import here
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
from freqtrade.persistence import Trade
import math
from technical.indicators import TKE
import math
import logging
from functools import reduce
from datetime import datetime, timedelta, timezone
from timeit import default_timer as timer
from datetime import timedelta
import time
logger = logging.getLogger(__name__)
def SSLChannels_ATR(dataframe, length=7):
"""
SSL Channels with ATR: https://www.tradingview.com/script/SKHqWzql-SSL-ATR-channel/
Credit to @JimmyNixx for python
"""
df = dataframe.copy()
df['ATR'] = ta.ATR(df, timeperiod=14)
df['smaHigh'] = df['high'].rolling(length).mean() + df['ATR']
df['smaLow'] = df['low'].rolling(length).mean() - df['ATR']
df['hlv'] = np.where(df['close'] > df['smaHigh'], 1, np.where(df['close'] < df['smaLow'], -1, np.NAN))
df['hlv'] = df['hlv'].ffill()
df['sslDown'] = np.where(df['hlv'] < 0, df['smaHigh'], df['smaLow'])
df['sslUp'] = np.where(df['hlv'] < 0, df['smaLow'], df['smaHigh'])
return df['sslDown'], df['sslUp']
def funcNadarayaWatsonEnvelope(dtloc, source='close', bandwidth=8, window=500, mult=3):
"""
// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// Nadaraya-Watson Envelope [LUX]
https://www.tradingview.com/script/Iko0E2kL-Nadaraya-Watson-Envelope-LUX/
:return: up and down
translated for freqtrade: viksal1982 viktors.s@gmail.com
df.shape[0]
"""
dtNWE = dtloc.copy()
dtNWE['nwe_up'] = np.nan
dtNWE['nwe_down'] = np.nan
wn = np.zeros((window, window))
for i in range(window):
for j in range(window):
wn[i, j] = math.exp(-(math.pow(i - j, 2) / (bandwidth * bandwidth * 2)))
sumSCW = wn.sum(axis=1)
def calc_nwa(dfr, init=0):
global calc_src_value
if init == 1:
calc_src_value = list()
return
calc_src_value.append(dfr[source])
mae = 0.0
y2_val = 0.0
y2_val_up = np.nan
y2_val_down = np.nan
if len(calc_src_value) > window:
calc_src_value.pop(0)
if len(calc_src_value) >= window:
src = np.array(calc_src_value)
sumSC = src * wn
sumSCS = sumSC.sum(axis=1)
y2 = sumSCS / sumSCW
sum_e = np.absolute(src - y2)
mae = sum_e.sum() / window * mult
y2_val = y2[-1]
y2_val_up = y2_val + mae
y2_val_down = y2_val - mae
return y2_val_up, y2_val_down
calc_nwa(None, init=1)
dtNWE[['nwe_up', 'nwe_down']] = dtNWE.apply(calc_nwa, axis=1, result_type='expand')
return dtNWE[['nwe_up', 'nwe_down']]
class NWEv6_new(IStrategy):
window_buy = IntParameter(60, 1000, default=300, space='buy', optimize=True)
bandwidth_buy = IntParameter(2, 15, default=9, space='buy', optimize=True)
mult_buy = DecimalParameter(0.5, 20.0, default=4, space='buy', optimize=True)
marginselldw = DecimalParameter(1.0049, 1.0200, default=1.0038, space='buy', decimals=4, optimize=True, load=True)
# hard stoploss profit
pHSL = DecimalParameter(-0.100, -0.040, default=-0.05, decimals=3, space='sell', load=True)
# profit threshold 1, trigger point, SL_1 is used
pPF_1 = DecimalParameter(0.008, 0.020, default=0.016, decimals=3, space='sell', load=True)
pSL_1 = DecimalParameter(0.008, 0.020, default=0.011, decimals=3, space='sell', load=True)
# profit threshold 2, SL_2 is used
pPF_2 = DecimalParameter(0.040, 0.100, default=0.080, decimals=3, space='sell', load=True)
pSL_2 = DecimalParameter(0.020, 0.070, default=0.040, decimals=3, space='sell', load=True)
# Optimal timeframe for the strategy.
timeframe = '3m'
inf_timeframe = '5m'
# These values can be overridden in the "ask_strategy" section in the config.
use_custom_stoploss = True
use_exit_signal = True
exit_profit_only = False
ignore_roi_if_entry_signal = False
# Number of candles the strategy requires before producing valid signals
startup_candle_count: int = 300
minimal_roi = {
"0": 0.10,
"423": 0.03,
"751": 0.01
}
stoploss = -0.99
trailing_stop = False
trailing_stop_positive = 0.005
trailing_stop_positive_offset = 0.019
trailing_only_offset_is_reached = True
process_only_new_candles = False
@property
def protections(self):
return [
{
"method": "CooldownPeriod",
"stop_duration": 120
},
{
"method": "StoplossGuard",
"lookback_period": 90,
"trade_limit": 2,
"stop_duration": 120,
"only_per_pair": False
},
{
"method": "StoplossGuard",
"lookback_period": 90,
"trade_limit": 1,
"stop_duration": 120,
"only_per_pair": True
},
]
# Optional order type mapping.
order_types = {
'entry': 'limit',
'exit': 'limit',
'stoploss': 'market',
'stoploss_on_exchange': False
}
# Optional order time in force.
order_time_in_force = {
'entry': 'gtc',
'exit': 'gtc'
}
plot_config = {
# Main plot indicators (Moving averages, ...)
'main_plot': {
'nwe_up': {'color': 'red'},
'nwe_down': {'color': "rgba(155,150,200,2.4)"},
'ema_100': {'color': 'blue'},
'entry_line': {'color': 'green'},
},
'subplots': {
"TREND/PCT": {
'btctrend': {'color': 'green'},
'highpct': {'color': 'red'},
'lowpct': {'color': 'blue'}
}
}
}
## Custom Trailing stoploss ( credit to Perkmeister for this custom stoploss to help the strategy ride a green candle )
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
# Only for hyperopt invalid return
if (sl_profit >= current_profit):
return -0.99
return stoploss_from_open(sl_profit, current_profit)
@informative('3m', 'BTC/{stake}', fmt='{base}_{column}_{timeframe}')
def populate_indicators_3m_btc(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
ssldown, sslup = SSLChannels_ATR(dataframe, 25)
dataframe['trend'] = np.where(sslup > ssldown, 1, -1)
return dataframe
@informative('5m')
def populate_indicators_5m(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['ema_100'] = ta.EMA(dataframe, timeperiod=100)
dataframe[['nwe_up', 'nwe_down']] = funcNadarayaWatsonEnvelope(dataframe, source='close',
bandwidth=self.bandwidth_buy.value,
window=self.window_buy.value,
mult=self.mult_buy.value)
dataframe["highpct"] = dataframe['nwe_down'] * dataframe['nwe_up'].pct_change(periods=24)
dataframe["lowpct"] = dataframe['nwe_down'] * dataframe['nwe_down'].pct_change(periods=6)
dataframe['entry_line'] = dataframe['nwe_down'] / self.marginselldw.value
dataframe['Newentry_line'] = dataframe['nwe_down'] * dataframe["lowpct"]
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
conditions = []
con2 = (
(dataframe['btc_trend_3m'] == 1) &
(qtpylib.crossed_below(dataframe['highpct_5m'], dataframe['lowpct_5m'])) &
(dataframe['ema_100_5m'] > dataframe['close_5m']) &
(dataframe['nwe_up_5m'] <= (abs(dataframe['highpct_5m']) * 100)) &
(dataframe['volume_5m'] > 0)
)
con3 = (
(dataframe['close_5m'].shift() < dataframe['entry_line_5m'].shift()) &
(dataframe['close_5m'].shift(2) < dataframe['entry_line_5m'].shift(2)) &
(dataframe['close_5m'] > dataframe['entry_line_5m']) &
(dataframe['ema_100_5m'] > dataframe['close_5m']) &
# (dataframe['ema_100_5m'] > dataframe['nwe_up_5m'] ) &
(dataframe['volume_5m'] > 0) # Make sure Volume is not 0
)
conditions.append(con2)
conditions.append(con3)
dataframe.loc[con2, 'enter_tag'] = " con2 "
dataframe.loc[con3, 'enter_tag'] = " con3 "
if conditions:
dataframe.loc[
reduce(lambda x, y: x | y, conditions),
'enter_long'
] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
conditions = []
con1 = (
(dataframe['close_5m'].shift() > dataframe['nwe_up_5m'].shift()) &
(dataframe['close_5m'] < dataframe['nwe_up_5m'])
)
conditions.append(con1)
# conditions.append(con2)
if conditions:
dataframe.loc[
reduce(lambda x, y: x | y, conditions),
'exit_long'
] = 1
return dataframe