# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement # flake8: noqa: F401 # isort: skip_file # --- Do not remove these imports --- from freqtrade.constants import Config from freqtrade.persistence import Trade from freqtrade.strategy import IStrategy, informative, IntParameter, DecimalParameter from freqtrade.optimize.space import Categorical, Dimension, Integer, SKDecimal from datetime import datetime, timedelta from pandas import DataFrame from typing import Dict, List, Optional, Union, Tuple import talib.abstract as ta from technical import qtpylib import numpy as np class ZTV16X(IStrategy): # Parameters INTERFACE_VERSION = 3 timeframe = '5m' can_short = True use_exit_signal = True exit_profit_only = False # ROI table: minimal_roi = { "0": 0.20, # 20% ROI for any trade "30": 0.10, # Reduce ROI to 10% after 30 minutes "60": 0.05, # Reduce ROI to 5% after 60 minutes "120": 0 # Exit after 120 minutes } # Stoploss: stoploss = -0.15 # Trailing stop: trailing_stop = True trailing_stop_positive = 0.012 trailing_stop_positive_offset = 0.107 trailing_only_offset_is_reached = True # Max Open Trades: max_open_trades = 7 # Hyperparameters for optimization adx_threshold = IntParameter(20, 40, default=25, space='buy', optimize=True) mfi_threshold_long = IntParameter(50, 70, default=60, space='buy', optimize=True) mfi_threshold_short = IntParameter(30, 50, default=40, space='sell', optimize=True) bollinger_std_dev = DecimalParameter(1.5, 3.0, default=2.0, space='buy', optimize=True) @property def plot_config(self): plot_config = {} plot_config['main_plot'] = {} plot_config['subplots'] = { "DI": { 'dx' : {'color': 'yellow'}, 'adx': {'color': 'orange'}, 'pdi': {'color': 'green'}, 'mdi': {'color': 'red'}, }, "AROON": { 'aup': { 'color': 'green' }, 'ado': { 'color': 'red' } }, } return plot_config def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # ADX and DI indicators dataframe['dx'] = ta.DX(dataframe) dataframe['adx'] = ta.ADX(dataframe) dataframe['pdi'] = ta.PLUS_DI(dataframe) dataframe['mdi'] = ta.MINUS_DI(dataframe) # MFI (Money Flow Index) dataframe['mfi'] = ta.MFI(dataframe) # AROON indicator dataframe[['aup', 'ado']] = ta.AROON(dataframe)[['aroonup','aroondown']] # Bollinger Bands with dynamic standard deviation dataframe[['bbl','bbm','bbu']] = qtpylib.bollinger_bands( qtpylib.typical_price(dataframe), window=8, stds=self.bollinger_std_dev.value )[['lower','mid','upper']] # ATR (Average True Range) for volatility-based position sizing dataframe['atr'] = ta.ATR(dataframe, timeperiod=14) return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Long entry conditions dataframe.loc[ ( (qtpylib.crossed_above(dataframe['close'], dataframe['bbu'])) & # Price crosses above upper Bollinger Band (dataframe['adx'] > self.adx_threshold.value) & # ADX above threshold (strong trend) (dataframe['mfi'] > self.mfi_threshold_long.value) # MFI above threshold (strong buying pressure) ), ['enter_long', 'enter_tag'] ] = (1, 'Long Bollinger enter') dataframe.loc[ ( (dataframe['dx'] > dataframe['mdi']) & # DX > MDI (dataframe['adx'] > self.adx_threshold.value) & # ADX above threshold (dataframe['pdi'] > dataframe['mdi']) & # PDI > MDI (dataframe['aup'] > dataframe['ado']) & # AROON up > AROON down (dataframe['aup'] > 50) & # AROON up > 50 (dataframe['mfi'] > self.mfi_threshold_long.value) # MFI above threshold ), ['enter_long', 'enter_tag'] ] = (1, 'Long DI enter') # Short entry conditions dataframe.loc[ ( (qtpylib.crossed_below(dataframe['close'], dataframe['bbl'])) & # Price crosses below lower Bollinger Band (dataframe['adx'] > self.adx_threshold.value) & # ADX above threshold (strong trend) (dataframe['mfi'] < self.mfi_threshold_short.value) # MFI below threshold (strong selling pressure) ), ['enter_short', 'enter_tag'] ] = (1, 'Short Bollinger enter') dataframe.loc[ ( (dataframe['dx'] > dataframe['pdi']) & # DX > PDI (dataframe['adx'] > self.adx_threshold.value) & # ADX above threshold (dataframe['mdi'] > dataframe['pdi']) & # MDI > PDI (dataframe['ado'] > dataframe['aup']) & # AROON down > AROON up (dataframe['ado'] > 50) & # AROON down > 50 (dataframe['mfi'] < self.mfi_threshold_short.value) # MFI below threshold ), ['enter_short', 'enter_tag'] ] = (1, 'Short DI enter') return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Exit long positions dataframe.loc[ ( (qtpylib.crossed_below(dataframe['close'], dataframe['bbm'])) & # Price crosses below middle Bollinger Band (dataframe['mfi'] < self.mfi_threshold_long.value) # MFI below threshold (weak buying pressure) ), 'exit_long' ] = 1 # Exit short positions dataframe.loc[ ( (qtpylib.crossed_above(dataframe['close'], dataframe['bbm'])) & # Price crosses above middle Bollinger Band (dataframe['mfi'] > self.mfi_threshold_short.value) # MFI above threshold (weak selling pressure) ), 'exit_short' ] = 1 return dataframe def leverage(self, pair: str, current_time: "datetime", current_rate: float, proposed_leverage: float, max_leverage: float, side: str, **kwargs,) -> float: return 10 # Fixed leverage of 10x def custom_stake_amount(self, pair: str, current_time, current_rate: float, proposed_stake: float, min_stake: float, max_stake: float, **kwargs) -> float: # Dynamic position sizing based on ATR (volatility) dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) last_candle = dataframe.iloc[-1].squeeze() atr = last_candle['atr'] # Adjust stake size based on volatility stake_size = max(min_stake, min(max_stake, proposed_stake * (2.0 / atr))) return stake_size