Files
Chan/strategies/SOL15mStrategy.py
2026-03-06 22:08:24 +08:00

125 lines
3.8 KiB
Python

"""
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