""" SOL15mStrategy - 基于15m时间框架的SOL/USDT期货策略 核心逻辑: - 15m EMA26/EMA52 交叉做多做空 - RSI过滤:做多要求RSI<65,做空要求RSI>35(避免超买超卖区入场) - 使用 trailing_stop 让利润奔跑 - 宽止损(2%),给交易足够呼吸空间 使用命令: freqtrade backtesting -c ./user_data/Chan/config/Local_Test.json --strategy SOL15mStrategy --strategy-path ./user_data/Chan/strategies --timerange=20250301- """ from datetime import datetime from typing import Optional import talib.abstract as ta from pandas import DataFrame from freqtrade.persistence import Trade from freqtrade.strategy import IStrategy class SOL15mStrategy(IStrategy): INTERFACE_VERSION: int = 3 # === 基础配置 === timeframe = "15m" can_short = True startup_candle_count: int = 200 # 止损 2% stoploss = -0.02 use_custom_stoploss = False # trailing stop: 利润达到1.5%后开始追踪,回撤0.5%止盈 trailing_stop = True trailing_stop_positive = 0.005 trailing_stop_positive_offset = 0.015 trailing_only_offset_is_reached = True # ROI: 阶梯式止盈 minimal_roi = { "0": 0.04, # 4%直接止盈 "60": 0.025, # 60分钟后 2.5% "180": 0.015, # 3小时后 1.5% "480": 0.005, # 8小时后 0.5% "720": 0, # 12小时后保本退出 } order_types = { "entry": "market", "exit": "market", "stoploss": "market", "stoploss_on_exchange": False, } def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # EMA dataframe["ema26"] = ta.EMA(dataframe, timeperiod=26) dataframe["ema52"] = ta.EMA(dataframe, timeperiod=52) dataframe["ema100"] = ta.EMA(dataframe, timeperiod=100) # RSI dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14) # MACD macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9) dataframe["macd"] = macd["macd"] dataframe["macdsignal"] = macd["macdsignal"] # EMA26上穿EMA52 dataframe["ema26_cross_up_52"] = ( (dataframe["ema26"] > dataframe["ema52"]) & (dataframe["ema26"].shift(1) <= dataframe["ema52"].shift(1)) ) # EMA26下穿EMA52 dataframe["ema26_cross_dn_52"] = ( (dataframe["ema26"] < dataframe["ema52"]) & (dataframe["ema26"].shift(1) >= dataframe["ema52"].shift(1)) ) # MACD死叉 dataframe["macd_cross_dn"] = ( (dataframe["macd"] < dataframe["macdsignal"]) & (dataframe["macd"].shift(1) >= dataframe["macdsignal"].shift(1)) ) return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # 做多: EMA26上穿EMA52 + RSI < 65 (不在超买区) dataframe.loc[ (dataframe["ema26_cross_up_52"]) & (dataframe["rsi"] < 65), ["enter_long", "enter_tag"], ] = (1, "ema26x52_long") # 做空: EMA26下穿EMA52 + RSI > 35 (不在超卖区) dataframe.loc[ (dataframe["ema26_cross_dn_52"]) & (dataframe["rsi"] > 35), ["enter_short", "enter_tag"], ] = (1, "ema26x52_short") return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # 不使用信号退出,完全由 trailing_stop + ROI + stoploss 控制 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 1.0