Timeframe
1m
Direction
Long Only
Stoploss
-0.8%
Trailing Stop
No
ROI
0m: 2.0%, 15m: 1.5%, 30m: 1.0%
Interface Version
N/A
Startup Candles
100
Indicators
4
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
from freqtrade.strategy import IStrategy
from pandas import DataFrame
import pandas as pd
import talib.abstract as ta
from datetime import datetime
import numpy as np
class NineSecondSniperV5(IStrategy):
"""
9秒狙击手策略 V5 - 核心重构版
回归核心思想:
1. SAR 转向确认趋势反转(主信号)
2. 9秒动能确认(辅助确认)
3. 严格但合理的风控
V5 修复点:
- 禁用追踪止损(分钟级震荡太大)
- 放宽 SAR 参数(更适合分钟级)
- 简化入场条件(聚焦核心信号)
- 提高止损容忍度(给趋势发展空间)
"""
timeframe = '1m'
max_open_trades = 2
stake_amount = 100
startup_candle_count = 100
# 止盈配置 - 让利润奔跑
minimal_roi = {
"0": 0.02, # 2% 初始止盈
"15": 0.015, # 15分钟降到 1.5%
"30": 0.01, # 30分钟降到 1%
}
# 固定止损 - V5 核心改进:禁用追踪止损
stoploss = -0.008 # 0.8% 固定止损 - 更宽松
trailing_stop = False # 禁用追踪止损(分钟级震荡大,容易被震出)
order_types = {
'entry': 'market',
'exit': 'market',
'stoploss': 'market',
'stoploss_on_exchange': False,
'entry_pricing': 'same',
'exit_pricing': 'same'
}
unfilledtimeout = {
'entry': 10,
'exit': 10,
'unit': 'seconds'
}
# 杠杆配置
base_leverage_config = {
'BTC/USDT:USDT': 2.0,
'ETH/USDT:USDT': 1.5,
'SOL/USDT:USDT': 1.5,
'XRP/USDT:USDT': 1.0,
'DOGE/USDT:USDT': 1.0
}
# 价格缓冲区
price_buffer_size = 9
price_buffers = {}
def informative_pairs(self) -> list:
return []
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
df = dataframe.copy()
pair = metadata['pair']
# ========== 核心:SAR 指标(调整参数更适合分钟级)==========
# acceleration 降低(反应更慢,避免频繁转向)
# maximum 提高(允许更大的趋势延续)
df['sar'] = ta.SAR(df['high'].values, df['low'].values,
acceleration=0.015, maximum=0.25)
# SAR 当前位置:价格在 SAR 上方为多头
df['above_sar'] = df['close'] > df['sar']
# SAR 转向检测:从 SAR 下方突破到上方
df['sar_reversal_up'] = df['above_sar'] & (df['above_sar'].shift(1) == False)
# ========== 辅助:EMA 趋势确认 ==========
df['ema_9'] = ta.EMA(df['close'].values, timeperiod=9)
df['ema_21'] = ta.EMA(df['close'].values, timeperiod=21)
df['ema_trend_up'] = df['ema_9'] > df['ema_21']
# ========== 辅助:RSI(避免超买)==========
df['rsi'] = ta.RSI(df['close'].values, timeperiod=14)
# ========== 核心:9秒动能 ==========
# 对比 9 根 K 线的价格变化
df['price_9sec_ago'] = df['close'].shift(9)
df['price_change_9sec'] = (df['close'] - df['price_9sec_ago']) / df['price_9sec_ago']
df['momentum_9sec_up'] = df['price_change_9sec'] > 0
# ========== 成交量确认(过滤假突破) ==========
df['volume_sma'] = ta.SMA(df['volume'].values, timeperiod=20)
df['volume_ratio'] = df['volume'] / df['volume_sma']
# ========== 价格缓冲区(波动率确认)==========
if pair not in self.price_buffers:
self.price_buffers[pair] = np.zeros(self.price_buffer_size)
buffer = self.price_buffers[pair]
for i in range(len(df)):
if i >= self.price_buffer_size:
buffer[:-1] = buffer[1:]
buffer[-1] = df['close'].iloc[i]
df['buffer_momentum'] = 0.0
if len(buffer) >= self.price_buffer_size:
df['buffer_momentum'] = (buffer[-1] - buffer[0]) / buffer[0]
return df
def leverage(self, pair: str, current_time: datetime, current_rate: float,
current_profit: float = 0.0, min_stops: float = 0.0,
max_stops: float = 0.0, current_time_rows: DataFrame = None,
**kwargs) -> float:
base_leverage = self.base_leverage_config.get(pair, 1.0)
# 保守策略
if current_profit > 0.01: # 盈利 > 1%
base_leverage *= 0.5
elif current_profit < -0.005: # 亏损 > 0.5%
base_leverage *= 0.7
return min(base_leverage, 2.0) # 最大杠杆 2x
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
df = dataframe.copy()
df['enter_long'] = 0
if len(df) < self.startup_candle_count:
return df
# ========== V5 核心:简化入场条件 ==========
entry_conditions = (
# 1. SAR 转向上(主信号 - 核心思想)
df['sar_reversal_up'] &
# 2. 9秒动向上(确认 - 核心思想)
df['momentum_9sec_up'] &
# 3. EMA 趋势向上(辅助确认)
df['ema_trend_up'] &
# 4. RSI 不超买(有上涨空间)
(df['rsi'] > 35) & (df['rsi'] < 65) &
# 5. 成交量放大(真突破)
(df['volume_ratio'] > 1.2) &
# 6. 缓冲区动量确认
(df['buffer_momentum'] > 0)
)
df.loc[entry_conditions, 'enter_long'] = 1
return df
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
df = dataframe.copy()
df['exit'] = 0
# ========== V5 核心:简化出场条件 ==========
# 让 ROI 和止损处理,只处理明确的反转信号
exit_conditions = (
# 1. SAR 压制(趋势明确反转)
(df['close'] < df['sar']) |
# 2. EMA 死叉(趋势反转)
(df['ema_9'] < df['ema_21']) |
# 3. 9秒动量向下(动能消失)
(df['price_change_9sec'] < -0.002)
)
df.loc[exit_conditions, 'exit'] = 1
return df
def custom_exit(self, pair: str, current_time: datetime, current_rate: float,
current_profit: float, **kwargs) -> bool:
# 只作为最后的保险
# 紧急止损
if current_profit < -0.015: # -1.5% 紧急止损
return True
return False