# --- Do not remove these libs --- from statistics import median from freqtrade.strategy import IStrategy, stoploss_from_absolute import sys import os # 添加父目录到系统路径 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from ChanLun import ChanLun from ChanEnum import Chan_FX_TYPE, Chan_KLC_FX, Chan_BI_DIR, Chan_KLC_FX # -------------------------------- from technical.util import resample_to_interval, resampled_merge import talib.abstract as ta from pandas import DataFrame import pandas as pd from datetime import datetime, timedelta from freqtrade.persistence import Trade, Order from typing import Optional import logging logger = logging.getLogger(__name__) """ 使用EMA周期52 1. 检查当前price是否穿越,如果穿越时,MACD也是归零轴反转,则开仓 2. 接近某个EMA周期后反转,此时MACD归零轴反转,则开仓 1. 从大周期开始找到价格接近ema52,MACD也接近零轴的周期,需要看这个周期的长级别是否高位空,大趋势方向 2. 然后去小于这个时间周期的周期找买卖点,小级趋势方向和大趋势相反并且开始反向,小级别需要检查MACD是否归零轴反转,同时价格是否接近EMA52 """ ### Now you can use logger.info('asfd') to log # freqtrade plot-dataframe --strategy ChanLun_BTC --datadir user_data/data/binance -c ./user_data/ChanLun_SOL_30.json --timerange=20250309- # freqtrade trade -c ./user_data/Chan/config/ChanLun_EMA52.json --strategy ChanLun_EMA52 --strategy-path ./user_data/Chan/strategies # freqtrade backtesting -c ./user_data/Chan/config/ChanLun_EMA52.json --strategy ChanLun_EMA52 --strategy-path ./user_data/Chan/strategies --timerange=20260101- # freqtrade download-data -c ./user_data/Chan/config/ChanLun_EMA52.json -t 1m 1m 1h 1d 1M --pairs BTC/USDT:USDT --timerange=20250405- # freqtrade download-data -c ./user_data/Chan/config/ChanLun_EMA52.json -t 1m 1h 1d 1M --pairs BTC/USDT --timerange=20170101- # freqtrade hyperopt --hyperopt-loss SharpeHyperOptLossDaily --spaces roi --strategy ChanLun_EMA52 --strategy-path ./user_data/Chan/strategies -c ./user_data/Chan/config/ChanLun_EMA52.json -e 200 --timerange=20250201-20250901 # freqtrade edge -c ./user_data/Chan/config/ChanLun_EMA52.json --strategy ChanLun_EMA52 --strategy-path ./user_data/Chan/strategies --timerange 20250721-20250901 # freqtrade plot-dataframe -c ./user_data/Chan/config/ChanLun_EMA52.json --strategy ChanLun_EMA52 --strategy-path ./user_data/Chan/strategies --timerange 20250721-20250901 # sudo docker compose run --rm chanlun_btc backtesting -c ./user_data/Chan/config/ChanLun_EMA52.json --strategy ChanLun_EMA52 --strategy-path ./user_data/Chan/strategies --timerange=20250721- # sudo docker compose run --rm chanlun_btc download-data -c ./user_data/Chan/config/ChanLun_EMA52.json --pairs BTC/USDT:USDT -t 1m --timerange 20240101- # sudo docker compose run --rm chanlun_btc trade -c ./user_data/Chan/config/ChanLun_EMA52.json --strategy ChanLun_EMA52 --strategy-path ./user_data/Chan/strategies class ChanLun_EMA52(IStrategy): INTERFACE_VERSION: int = 3 # Minimal ROI designed for the strategy. # This attribute will be overridden if the config file contains "minimal_roi" # 30m and 1h minimal_roi = { "0": 0.15, "360": 0.2, "640": 0.1, "1200": 0 } # 5m and 15m minimal_roi_1 = { "0": 0.1, "60": 0.05, "120": 0.02, "240": 0 } # 15m and 30m minimal_roi_1 = { "0": 0.1, "240": 0.05, "480": 0.03, "600": 0 } minimal_roi_1 = { "0": 1.50, "120": 0.05, "240": 0.025, "360": 0 } can_short = True lev = 1.0 stoploss = -0.3 # 设置为很大的负值,让custom_stoploss来控制 use_custom_stoploss = False # 启用自定义止损 trailing_stop = False trailing_stop_positive = 0.03 trailing_stop_positive_offset = 0.06 trailing_only_offset_is_reached = False # 关闭分批止盈/仓位调整 position_adjustment_enable = False # startup_candle_count = 1600 big_tf = '1h' small_tf = '15m' last_time = datetime.now() chan = ChanLun() last_order = None last_trade = None pair = 'BTC/USDT:USDT' def informative_pairs(self): return [(self.pair, "1h"), (self.pair, "1d"), (self.pair, "1M"), (self.pair, "15m"), (self.pair, "1w"), ] def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: self.init_dataframes(dataframe) dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) last_price = dataframe.iloc[-1]['close'] tf_ema52_list = self.chan.check_price_ema52(last_price) print(tf_ema52_list) return dataframe def init_dataframes(self, dataframe_1m): dataframe_15m = self.dp.get_pair_dataframe(pair=self.pair, timeframe='15m') dataframe_1h = self.dp.get_pair_dataframe(pair=self.pair, timeframe='1h') dataframe_1d = self.dp.get_pair_dataframe(pair=self.pair, timeframe='1d') dataframe_1w = self.dp.get_pair_dataframe(pair=self.pair, timeframe='1w') dataframe_1M = self.dp.get_pair_dataframe(pair=self.pair, timeframe='1M') self.chan.init_dataframes(dataframe_1m, dataframe_15m,dataframe_1h, dataframe_1d, dataframe_1w, dataframe_1M) def custom_entry_price(self, pair: str, trade: Trade | None, current_time: datetime, proposed_rate: float, entry_tag: str | None, side: str, **kwargs) -> float: new_entryprice = proposed_rate if trade: if trade.is_short: new_entryprice = proposed_rate - 50 else: new_entryprice = proposed_rate + 50 return new_entryprice def custom_exit_price(self, pair: str, trade: Trade, current_time: datetime, proposed_rate: float, current_profit: float, exit_tag: str | None, **kwargs) -> float: new_exitprice = proposed_rate if trade: if trade.is_short: new_exitprice = proposed_rate + 50 else: new_exitprice = proposed_rate - 50 return new_exitprice def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, min_stake: Optional[float], max_stake: float, current_entry_rate: float, current_exit_rate: float, current_entry_profit: float, current_exit_profit: float, **kwargs) -> Optional[float]: # 关闭分批止盈,始终不调整仓位 return None def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, **kwargs): # 不做分批止盈/最终止盈处理,退出由策略信号/ROI/止损决定 return None def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ (dataframe['rsi'] < 30), 'enter_long'] = 1 return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ (dataframe['rsi'] > 70), 'exit_long'] = 1 return dataframe def leverage(self, pair: str, current_time: datetime, current_rate: float, proposed_leverage: float, max_leverage: float, entry_tag: Optional[str], side: str, **kwargs) -> float: return self.lev