Skip to content
This repository has been archived by the owner on Jun 8, 2023. It is now read-only.

⚡️ New core trend indicator based on SSL Channel & Choppiness Index #184

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,5 @@ pyproject.yml
setup.cfg
setup.py
setup.sh
user_data/strategies/MasterMoniGoManiHyperStrategy_SSL.py
user_data/strategies/MoniGoManiHyperStrategy_SSL.py
96 changes: 88 additions & 8 deletions user_data/strategies/MasterMoniGoManiHyperStrategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import pandas as pd # noqa
import talib.abstract as ta
from numpy import timedelta64
from pandas import DataFrame
from pandas import DataFrame, Series
from scipy.interpolate import interp1d
from yaml import full_load

Expand All @@ -25,7 +25,10 @@
from freqtrade.misc import deep_merge_dicts, round_dict
from freqtrade.optimize.space import Categorical, Dimension, Integer, SKDecimal
from freqtrade.persistence import Trade
from freqtrade.strategy import IntParameter, IStrategy, merge_informative_pair, timeframe_to_minutes
from freqtrade.strategy import IntParameter, IStrategy, merge_informative_pair, timeframe_to_minutes,DecimalParameter

import freqtrade.vendor.qtpylib.indicators as qtpylib
import pandas_ta as pta

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -205,6 +208,14 @@ class MasterMoniGoManiHyperStrategy(IStrategy, ABC):
total_signals_possible[f'{space}_{trend}'] = 0
total_triggers_possible[f'{space}_{trend}'] = 0

# CoreTrend Hyperoptable parameters
trend_ssl_period = IntParameter(6, 15, default=10, space='buy', optimize=False, load=False)
trend_ssl_atr_coef = DecimalParameter(0, 1, decimals=1, default=0.3, space='buy', optimize=False, load=False)
trend_ssl_mode = IntParameter(1, 17, default=1, space='buy', optimize=False, load=False)
trend_chop_sideway = IntParameter(45, 55, default=50, space='buy', optimize=False, load=False)
trend_bb_sideway = IntParameter(5, 15, default=8, space='buy', optimize=False, load=False)


class HyperOpt:
@staticmethod
def generate_roi_table(params: Dict) -> Dict[int, float]:
Expand Down Expand Up @@ -382,17 +393,17 @@ def populate_frequi_plots(weighted_signal_plots: dict) -> dict:
framework_plots = {
# Main Plots - Trend Indicator (SAR)
'main_plot': {
'sar': {'color': '#2c05f6'}
#'sar': {'color': '#2c05f6'}
},
# Sub Plots - Each dict defines one additional plot
'subplots': {
# Sub Plots - Trend Detection
'MoniGoMani Core Trend': {
'mgm_trend': {'color': '#7fba3c'}
},
'Hilbert Transform (Trend vs Cycle)': {
'ht_trendmode': {'color': '#6f1a7b'}
},
#'Hilbert Transform (Trend vs Cycle)': {
# 'ht_trendmode': {'color': '#6f1a7b'}
#},
# Sub Plots - Final Buy + Sell Signals
'Buy + Sell Signals Firing': {
'buy': {'color': '#09d528'},
Expand Down Expand Up @@ -425,6 +436,10 @@ def _populate_core_trend(self, dataframe: DataFrame, metadata: dict) -> DataFram
:return: a Dataframe with all core trend indicators for MoniGoMani
"""

"""
# ----------------------------
# Current Core Trend Detection
# ----------------------------
# Momentum Indicators
# -------------------
# Hilbert Transform - Trend vs Cycle
Expand All @@ -439,6 +454,34 @@ def _populate_core_trend(self, dataframe: DataFrame, metadata: dict) -> DataFram
dataframe.loc[(dataframe['ht_trendmode'] == 0) | (dataframe['sar'] == dataframe['close']), 'trend'] = 'sideways'
dataframe.loc[(dataframe['ht_trendmode'] == 1) & (dataframe['sar'] < dataframe['close']), 'trend'] = 'upwards'

# ------------------------
# New Core Trend Detection
# ------------------------
"""
# Upwards / Downwards movement detection
# --------------------------------------
# SSL Channels
df_ssl = ssl_channels_atr(dataframe, period=self.trend_ssl_period.value,
coef=self.trend_ssl_atr_coef.value, mode=self.trend_ssl_mode.value)
dataframe = pd.concat([dataframe, df_ssl], axis=1)

ssl_atr = f'SSLATR_{self.trend_ssl_mode.value}_{self.trend_ssl_period.value}_{self.trend_ssl_atr_coef.value}'
dataframe['trend'] = np.where(dataframe[f'{ssl_atr}_up'] < dataframe[f'{ssl_atr}_down'], 'downwards', 'upwards')

# Sideways movement detection
# ---------------------------
# Choppiness Index
dataframe['chop'] = pta.chop(dataframe["high"], dataframe["low"], dataframe["close"])

# Bollinger Bands
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)

dataframe['trend'] = np.where(
(dataframe['chop'] > self.trend_chop_sideway.value) &
((((bollinger['upper'] - bollinger['lower']) / bollinger['upper']) * 100) < self.trend_bb_sideway.value),
'sideways', dataframe['trend']
)

# Add DataFrame column for visualization in FreqUI when Dry/Live RunMode is detected
if self.is_dry_live_run_detected is True:
dataframe.loc[(dataframe['trend'] == 'downwards'), 'mgm_trend'] = -1
Expand Down Expand Up @@ -526,7 +569,7 @@ def _populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFram

# Merge core trend to informative data frame
informative = merge_informative_pair(
informative, core_trend[['date', 'ht_trendmode', 'sar', 'trend']].copy(),
informative, core_trend[['date', 'trend']].copy(),
self.informative_timeframe, self.core_trend_timeframe, ffill=True)
skip_columns = [f'{s}_{self.core_trend_timeframe}' for s in
['date', 'open', 'high', 'low', 'close', 'volume']]
Expand Down Expand Up @@ -560,7 +603,7 @@ def _populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFram

# Merge core trend to main data frame
dataframe = merge_informative_pair(
dataframe, core_trend[['date', 'ht_trendmode', 'sar', 'trend', 'mgm_trend']].copy(),
dataframe, core_trend[['date', 'trend', 'mgm_trend']].copy(),
self.timeframe, self.core_trend_timeframe, ffill=True)
skip_columns = [f'{s}_{self.core_trend_timeframe}' for s in
['date', 'open', 'high', 'low', 'close', 'volume']]
Expand Down Expand Up @@ -1421,3 +1464,40 @@ def init_hyperopt_epoch(self) -> None:
separator_window = (self.separator / 1) - (1 / self.separator)
self.separator_candle_weight_reducer = separator_window / self.get_param_value(
'sell___unclogger_trend_lookback_candles_window')


def ssl_channels_atr(dataframe, period: int = 7, coef: int = 1, mode: int = 1):
"""
Customized SSL Channel function with ATR Coefficient
"""
ssl_atr = f'SSLATR_{mode}_{period}_{coef}'
df = dataframe.copy()

# Moving Average modes
ma_modes = {1: 'dema', 2: 'fwma', 3: 'hma', 4: 'linreg', 5: 'midpoint', 6: 'pwma', 7: 'rma', 8: 'sinwma', 9: 'sma',
10: 'swma', 11: 't3', 12: 'tema', 13: 'trima', 14: 'vidya', 15: 'wma', 16: 'zlma'}

# Select the currently used Moving Average mode
ma_mode = 'ema'
for mode_key, ma_mode_value in ma_modes.items():
if mode_key == mode:
ma_mode = ma_mode_value
break

# Populate indicator data
# -----------------------
# ATR
df['atr'] = ta.ATR(df, timeperiod=int(period))
# Moving Average High/Low
df['maHigh'] = pta.ma(ma_mode, dataframe['high'], length=period) + (df['atr'] * coef)
df['maLow'] = pta.ma(ma_mode, dataframe['low'], length=period) - (df['atr'] * coef)
# HLV
df['hlv'] = np.where(df['close'] > df['maHigh'], 1, np.where(df['close'] < df['maLow'], -1, np.NAN))
df['hlv'] = df['hlv'].ffill()
# SSL Down/Up
df[f'{ssl_atr}_down'] = np.where(df['hlv'] < 0, df['maHigh'], df['maLow'])
df[f'{ssl_atr}_up'] = np.where(df['hlv'] < 0, df['maLow'], df['maHigh'])

return pd.concat([df[f'{ssl_atr}_down'], df[f'{ssl_atr}_up']], axis=1)
# ---------------------------------------------------