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

131 lines
4.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
SOL5mStrategy_ShortTerm - 真正的短线交易策略
核心特征:
★ 使用5分钟快速EMA交叉(EMA9/EMA21)作为信号源
★ 无延迟入场,信号出现立即入场
★ 小止损(-1%),快速止盈(+0.8%)
★ 平均持仓时间:15-60分钟
★ 交易频率:每天5-20笔
逻辑:
- 5分钟K线,EMA9/EMA21交叉入场
- RSI过滤(避免极端超买超卖)
- 成交量确认
- 快速止盈止损,不持仓过夜
使用命令:
freqtrade backtesting -c ./user_data/Chan/config/Local_Test.json \
--strategy SOL5mStrategy_ShortTerm --strategy-path ./user_data/Chan/strategies \
--timerange=20250301-
"""
import logging
from datetime import datetime
from typing import Optional
import talib.abstract as ta
from pandas import DataFrame
from freqtrade.strategy import IStrategy
logger = logging.getLogger(__name__)
class SOL5mStrategy_ShortTerm(IStrategy):
INTERFACE_VERSION: int = 3
# === 基础配置 ===
timeframe = "5m" # 使用5分钟K线
can_short = True
startup_candle_count: int = 100
# 小止损(-1%),适合短线
stoploss = -0.01
use_custom_stoploss = False
# Trailing stop:盈利0.5%后激活,回撤0.3%退出
trailing_stop = True
trailing_stop_positive = 0.003 # 回撤0.3%触发退出
trailing_stop_positive_offset = 0.005 # 盈利0.5%后才开始追踪
trailing_only_offset_is_reached = True
# ROI:快速止盈,从0.8%逐步递减
minimal_roi = {
"0": 0.008, # 0.8% 立即止盈
"15": 0.005, # 15分钟后 0.5%
"30": 0.003, # 30分钟后 0.3%
"60": 0.001, # 60分钟后 0.1%
"120": 0, # 120分钟后不设止盈(但trailing会保护)
}
order_types = {
"entry": "market",
"exit": "market",
"stoploss": "market",
"stoploss_on_exchange": False,
}
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""计算快速EMA交叉信号"""
# 快速EMA9)和慢速EMA21
dataframe["ema_fast"] = ta.EMA(dataframe, timeperiod=9)
dataframe["ema_slow"] = ta.EMA(dataframe, timeperiod=21)
# RSI用于过滤极端情况
dataframe["rsi"] = ta.EMA(dataframe, timeperiod=14)
# 成交量均线用于确认
dataframe["volume_mean"] = dataframe["volume"].rolling(window=20).mean()
# 上穿:本根 EMA9 > EMA21,上一根 EMA9 ≤ EMA21
dataframe["ema_cross_up"] = (
(dataframe["ema_fast"] > dataframe["ema_slow"])
& (dataframe["ema_fast"].shift(1) <= dataframe["ema_slow"].shift(1))
)
# 下穿:本根 EMA9 < EMA21,上一根 EMA9 ≥ EMA21
dataframe["ema_cross_down"] = (
(dataframe["ema_fast"] < dataframe["ema_slow"])
& (dataframe["ema_fast"].shift(1) >= dataframe["ema_slow"].shift(1))
)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""5分钟EMA交叉立即入场,无延迟"""
# 做多:EMA9上穿EMA21 + RSI > 45(避免极端超卖)+ 成交量确认
dataframe.loc[
(dataframe["ema_cross_up"] == True) &
(dataframe["rsi"] > 45) & # RSI过滤,避免极端超卖
(dataframe["volume"] > dataframe["volume_mean"] * 0.8), # 成交量确认(稍微宽松)
["enter_long", "enter_tag"],
] = (1, "ema9x21_long")
# 做空:EMA9下穿EMA21 + RSI < 55(避免极端超买)+ 成交量确认
dataframe.loc[
(dataframe["ema_cross_down"] == True) &
(dataframe["rsi"] < 55) & # RSI过滤,避免极端超买
(dataframe["volume"] > dataframe["volume_mean"] * 0.8), # 成交量确认
["enter_short", "enter_tag"],
] = (1, "ema9x21_short")
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""不使用信号退出,完全依赖 ROI / trailing stop / 硬止损"""
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