from datetime import datetime, timedelta import talib.abstract as ta import pandas_ta as pta from freqtrade.persistence import Trade from freqtrade.strategy.interface import IStrategy from pandas import DataFrame from freqtrade.strategy import DecimalParameter, IntParameter from functools import reduce from technical import qtpylib from typing import Dict,Optional class E0V1EAI(IStrategy): minimal_roi = { "0": 0.03 } timeframe = '5m' process_only_new_candles = True startup_candle_count = 120 order_types = { 'entry': 'market', 'exit': 'market', 'emergency_exit': 'market', 'force_entry': 'market', 'force_exit': "market", 'stoploss': 'market', 'stoploss_on_exchange': False, 'stoploss_on_exchange_interval': 60, 'stoploss_on_exchange_market_ratio': 0.99 } stoploss = -0.25 use_custom_stoploss = True can_short = True is_optimize_32 = True buy_rsi_fast_32 = IntParameter(20, 70, default=45, space='buy', optimize=is_optimize_32) buy_rsi_32 = IntParameter(15, 50, default=35, space='buy', optimize=is_optimize_32) buy_sma15_32 = DecimalParameter(0.900, 1, default=0.961, decimals=3, space='buy', optimize=is_optimize_32) buy_cti_32 = DecimalParameter(-1, 0, default=-0.58, decimals=2, space='buy', optimize=is_optimize_32) sell_fastx = IntParameter(50, 100, default=75, space='sell', optimize=True) def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, metadata: Dict, **kwargs) -> DataFrame: dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period) dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period) dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) bollinger = qtpylib.bollinger_bands( qtpylib.typical_price(dataframe), window=period, stds=2.2 ) dataframe["bb_lowerband-period"] = bollinger["lower"] dataframe["bb_middleband-period"] = bollinger["mid"] dataframe["bb_upperband-period"] = bollinger["upper"] dataframe["%-bb_width-period"] = ( dataframe["bb_upperband-period"] - dataframe["bb_lowerband-period"] ) / dataframe["bb_middleband-period"] dataframe["%-close-bb_lower-period"] = ( dataframe["close"] / dataframe["bb_lowerband-period"] ) dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period) dataframe["%-relative_volume-period"] = ( dataframe["volume"] / dataframe["volume"].rolling(period).mean() ) return dataframe def feature_engineering_expand_basic( self, dataframe: DataFrame, metadata: Dict, **kwargs) -> DataFrame: dataframe["%-raw_volume"] = dataframe["volume"] return dataframe def feature_engineering_standard( self, dataframe: DataFrame, metadata: Dict, **kwargs) -> DataFrame: dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek dataframe["%-hour_of_day"] = dataframe["date"].dt.hour return dataframe def set_freqai_targets(self, dataframe: DataFrame, metadata: Dict, **kwargs) -> DataFrame: dataframe['&-sma_15'] = ta.SMA(dataframe, timeperiod=15) dataframe['&-cti'] = pta.cti(dataframe["close"], length=20) dataframe['&-rsi'] = ta.RSI(dataframe, timeperiod=14) dataframe['&-rsi_fast'] = ta.RSI(dataframe, timeperiod=4) dataframe['&-rsi_slow'] = ta.RSI(dataframe, timeperiod=20) stoch_fast = ta.STOCHF(dataframe, 5, 3, 0, 3, 0) dataframe['&-fastk'] = stoch_fast['fastk'] dataframe['&-close'] = dataframe['close'] return dataframe def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe = self.freqai.start(dataframe, metadata, self) dataframe['rsi_shifted'] = dataframe['&-rsi_slow'].shift(1) return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: enter_long_conditions = [ dataframe["do_predict"] == 1, (dataframe['&-rsi_slow'] < dataframe['rsi_shifted']) , (dataframe['&-rsi_fast'] < self.buy_rsi_fast_32.value) , (dataframe['&-rsi'] > self.buy_rsi_32.value) , (dataframe['&-close'] < dataframe['&-sma_15'] * self.buy_sma15_32.value) , (dataframe['&-cti'] < self.buy_cti_32.value) ] if enter_long_conditions: dataframe.loc[ reduce(lambda x, y: x & y, enter_long_conditions), ["enter_long", "enter_tag"] ] = (1, "long") enter_short_conditions = [ dataframe["do_predict"] == 1, (dataframe['&-rsi_slow'] > dataframe['rsi_shifted']) , (dataframe['&-rsi_fast'] > self.buy_rsi_fast_32.value) , (dataframe['&-rsi'] < self.buy_rsi_32.value) , (dataframe['&-close'] > dataframe['&-sma_15'] * self.buy_sma15_32.value) , (dataframe['&-cti'] > self.buy_cti_32.value) ] if enter_short_conditions: dataframe.loc[ reduce(lambda x, y: x & y, enter_short_conditions), ["enter_short", "enter_tag"] ] = (1, "short") return dataframe def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> float: dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) current_candle = dataframe.iloc[-1].squeeze() if current_profit >= 0.08: return -0.01 if current_profit > 0: if current_candle["&-fastk"] > self.sell_fastx.value: return -0.001 if current_time - timedelta(hours=4) > trade.open_date_utc: if current_profit > -0.03: return -0.005 return self.stoploss def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[(), ['exit_long', 'exit_tag']] = (0, 'long_out') return dataframe