# --- Do not remove these libs --- from statistics import median from freqtrade.strategy import IStrategy from technical.util import resample_to_interval, resampled_merge from pandas import DataFrame import talib.abstract as ta from technical import qtpylib ### Now you can use logger.info('asfd') to log # freqtrade plot-dataframe --strategy EMA_Pattern --datadir user_data/data/binance -c ./user_data/Chan/EMA_Pattern.json --timerange=20250309- # freqtrade backtesting -c ./user_data/Chan/config/EMA_Pattern.json --strategy EMA_Pattern --strategy-path ./user_data/Chan/strategies --timerange=20251030- # freqtrade download-data -c ./user_data/Chan/config/EMA_Pattern.json -t 1m 3m 5m 15m 30m 1h --pairs BTC/USDT:USDT --timerange=20250405- # freqtrade download-data -c ./user_data/Chan/config/EMA_Pattern.json -t 1m 1h 1d 1M --pairs BTC/USDT --timerange=20170101- # freqtrade hyperopt --hyperopt-loss SharpeHyperOptLossDaily --spaces roi --strategy EMA_Pattern --strategy-path ./user_data/Chan/strategies -c ./user_data/Chan/config/EMA_Pattern.json -e 200 --timerange=20250201-20250901 # freqtrade edge -c ./user_data/Chan/config/EMA_Pattern.json --strategy EMA_Pattern --strategy-path ./user_data/Chan/strategies --timerange 20250721-20250901 # freqtrade plot-dataframe -c ./user_data/Chan/config/EMA_Pattern.json --strategy EMA_Pattern --strategy-path ./user_data/Chan/strategies --timerange 20250721-20250901 class EMA_Pattern(IStrategy): time1h = 1440 can_short: bool = True timeframe: str = "1m" process_only_new_candles: bool = False # ROI 与止损可根据需要在配置中覆盖 minimal_roi = { "60": 0.005, "30": 0.01, "0": 0.02, } stoploss: float = -0.30 # 需要的历史K线数量(包含EMA等指标预热) startup_candle_count: int = 200 def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: if dataframe is None or dataframe.empty: return dataframe dataframe = self.add_indicators(dataframe) return dataframe def add_indicators(self, dataframe: DataFrame) -> DataFrame: macd = ta.MACD(dataframe, timeperiod=12, fastperiod=12, slowperiod=26, signalperiod=9) dataframe['macd'] = macd['macd'] dataframe['macdsignal'] = macd['macdsignal'] dataframe['macdhist'] = macd['macdhist'] dataframe['ema6'] = ta.EMA(dataframe, timeperiod=6) dataframe['ema12'] = ta.EMA(dataframe, timeperiod=12) dataframe['ema24'] = ta.EMA(dataframe, timeperiod=24) dataframe['ema52'] = ta.EMA(dataframe, timeperiod=52) dataframe['adx'] = ta.ADX(dataframe, timeperiod=14) dataframe['strong_trend'] = dataframe['adx'] > 25 dataframe['UP_Pattern'] = (dataframe['ema6'] > dataframe['ema12']) & (dataframe['ema12'] > dataframe['ema24']) & (dataframe['ema24'] > dataframe['ema52']) dataframe['DOWN_Pattern'] = (dataframe['ema6'] < dataframe['ema12']) & (dataframe['ema12'] < dataframe['ema24']) & (dataframe['ema24'] < dataframe['ema52']) dataframe['UP_Confirm'] = (dataframe['ema6'] > dataframe['ema6'].shift(1)) & (dataframe['ema12'] > dataframe['ema12'].shift(1)) & (dataframe['ema24'] > dataframe['ema24'].shift(1)) & (dataframe['ema52'] > dataframe['ema52'].shift(1)) dataframe['DOWN_Confirm'] = (dataframe['ema6'] < dataframe['ema6'].shift(1)) & (dataframe['ema12'] < dataframe['ema12'].shift(1)) & (dataframe['ema24'] < dataframe['ema24'].shift(1)) & (dataframe['ema52'] < dataframe['ema52'].shift(1)) dataframe['EMA52_Cross_EMA24_UP'] = (dataframe['ema52'] < dataframe['ema24']) & (dataframe['ema52'].shift(1) > dataframe['ema24'].shift(1)) dataframe['EMA52_Cross_EMA24_DOWN'] = (dataframe['ema52'] > dataframe['ema24']) & (dataframe['ema52'].shift(1) < dataframe['ema24'].shift(1)) dataframe['Price_Above_EMA52'] = (dataframe['close'] > dataframe['ema52']) dataframe['Price_Below_EMA52'] = (dataframe['close'] < dataframe['ema52']) dataframe['MACD_Above_Zero'] = (dataframe['macd'] > 0) & (dataframe['macdsignal'] > 0) dataframe['MACD_Below_Zero'] = (dataframe['macd'] < 0) & (dataframe['macdsignal'] < 0) dataframe['BUY_END'] = dataframe['close'] < dataframe['ema52'] dataframe['SELL_END'] = dataframe['close'] > dataframe['ema52'] return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: if dataframe is None or dataframe.empty: return dataframe dataframe.loc[ ( (dataframe['UP_Pattern']) & (dataframe['UP_Confirm']) & (dataframe['Price_Above_EMA52']) & (dataframe['MACD_Above_Zero']) & (dataframe['EMA52_Cross_EMA24_UP']) & (dataframe['strong_trend']) ), ["enter_long", "enter_tag"], ] = (1, "ema_up_trend") dataframe.loc[ ( (dataframe['DOWN_Pattern']) & (dataframe['DOWN_Confirm']) & (dataframe['Price_Below_EMA52']) & (dataframe['MACD_Below_Zero']) & (dataframe['EMA52_Cross_EMA24_DOWN']) & (dataframe['strong_trend']) ), ["enter_short", "enter_tag"], ] = (1, "ema_down_trend") return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: if dataframe is None or dataframe.empty: return dataframe dataframe.loc[ ( (dataframe['BUY_END']) | (dataframe['DOWN_Pattern']) | (dataframe['EMA52_Cross_EMA24_DOWN']) ), ["exit_long", "exit_tag"], ] = (1, "ema_long_exit") dataframe.loc[ ( (dataframe['SELL_END']) | (dataframe['UP_Pattern']) | (dataframe['EMA52_Cross_EMA24_UP']) ), ["exit_short", "exit_tag"], ] = (1, "ema_short_exit") return dataframe def get_ticker_indicator(self): return int(self.timeframe[:-1])