添加新的策略

This commit is contained in:
jackyu66git
2026-03-06 22:08:24 +08:00
parent d8f2269a49
commit d2107db6c0
19 changed files with 2712 additions and 19 deletions
+664
View File
@@ -0,0 +1,664 @@
"""
缠论同级别分解策略 (Chan Same-Level Decomposition Strategy)
核心思想:按同级别分解操作,实现a+A结构的机械化操作
以5分钟级别为例:
1. a+A结构:a是5分钟走势类型(定义为A0),A分解为m段5分钟走势类型:A=A1+A2+...+Am
2. 如果a+A向上,则Ai当i为奇数时向下,i为偶数时向上
3. 中枢形成:
- A1不能跌破a的低点
- 如果A2升破a的高点而A3不跌回a的高点,可以把a+A1+A2+A3当成一个新的a'(还是5分钟级别)
- 如果A3跌破a的高点,则A1、A2、A3必然构成30分钟中枢
操作程式(机械化操作):
1. 盘整背驰情况:
- Ai与Ai+2之间比较力度(盘整背驰)
- i+2为偶数时卖出
- i+2为奇数时买入
2. 非背驰情况:
- 当i为偶数,若Ai+3不跌破Ai高点,则继续持有到Ai+k+3跌破Ai+k高点后在不创新高或盘整顶背驰的Ai+k+4卖出,其中k为偶数
- 当i为奇数,若Ai+3不升破Ai低点,则继续保持不回补直到Ai+k+3升破Ai+k低点后在不创新低或盘整底背驰的Ai+k+4回补
使用命令:
freqtrade backtesting -c ./user_data/Chan/config/Local_Test.json \
--strategy ChanSameLevelStrategy --strategy-path ./user_data/Chan/strategies \
--timerange=20250301-
"""
import logging
from datetime import datetime
from typing import Optional
import numpy as np
import pandas as pd
import talib.abstract as ta
from pandas import DataFrame
from technical.util import resample_to_interval, resampled_merge
from freqtrade.strategy import IStrategy
logger = logging.getLogger(__name__)
class ChanSameLevelStrategy(IStrategy):
INTERFACE_VERSION: int = 3
# === 基础配置 ===
# 底层使用 1m K线,resample 到 30m 进行同级别分解
can_short = True
startup_candle_count: int = 2000 # 需要足够的数据来识别走势段
# 止损和止盈(优化:改善风险回报比)
stoploss = -0.015 # 1.5% 硬止损(更紧,减少单笔亏损)
use_custom_stoploss = False
# Trailing stop(优化:更激进的保护利润)
trailing_stop = True
trailing_stop_positive = 0.006 # 回撤 0.6% 触发退出(更紧)
trailing_stop_positive_offset = 0.012 # 盈利 1.2% 后才开始追踪(降低门槛)
trailing_only_offset_is_reached = True
# ROI(优化:更合理的止盈目标,改善风险回报比)
minimal_roi = {
"0": 0.03, # 3% 立即止盈(降低目标,提高胜率)
"60": 0.02, # 60分钟后 2%
"120": 0.015, # 120分钟后 1.5%
"240": 0.01, # 240分钟后 1%
"480": 0.005, # 480分钟后 0.5%
"720": 0, # 720分钟后不设止盈
}
order_types = {
"entry": "market",
"exit": "market",
"stoploss": "market",
"stoploss_on_exchange": False,
}
# 同级别分解的级别(5分钟)
same_level_timeframe = 5
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""计算指标并识别同级别走势段"""
ticker = self.get_ticker_indicator()
# Resample 到 30m 进行同级别分解
dataframe_30m = resample_to_interval(dataframe, ticker * self.same_level_timeframe)
# 在 30m 上计算指标
dataframe_30m = self.add_indicators_30m(dataframe_30m)
# 识别同级别走势段和背驰
dataframe_30m = self.identify_same_level_segments(dataframe_30m)
# 合并回 1m dataframe
dataframe = resampled_merge(dataframe, dataframe_30m)
# 在 1m 上也计算基础指标
dataframe = self.add_indicators_1m(dataframe)
return dataframe
def add_indicators_30m(self, dataframe: DataFrame) -> DataFrame:
"""在30m级别计算指标"""
# MACD 用于识别背驰
macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
dataframe['macd'] = macd['macd']
dataframe['macdsignal'] = macd['macdsignal']
dataframe['macdhist'] = macd['macdhist']
# EMA 用于识别趋势(增加更多EMA用于趋势确认)
dataframe['ema12'] = ta.EMA(dataframe, timeperiod=12)
dataframe['ema26'] = ta.EMA(dataframe, timeperiod=26)
dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
dataframe['ema200'] = ta.EMA(dataframe, timeperiod=200) # 长期趋势
# EMA趋势方向
dataframe['ema_trend_up'] = (dataframe['ema12'] > dataframe['ema26']) & (dataframe['ema26'] > dataframe['ema50'])
dataframe['ema_trend_dn'] = (dataframe['ema12'] < dataframe['ema26']) & (dataframe['ema26'] < dataframe['ema50'])
# 市场整体趋势(基于价格和EMA200)
dataframe['price_above_ema200'] = dataframe['close'] > dataframe['ema200']
dataframe['price_below_ema200'] = dataframe['close'] < dataframe['ema200']
# 趋势强度(EMA斜率)
dataframe['ema12_slope'] = dataframe['ema12'].diff(5) / dataframe['ema12'].shift(5)
dataframe['ema26_slope'] = dataframe['ema26'].diff(5) / dataframe['ema26'].shift(5)
dataframe['strong_uptrend'] = (dataframe['ema12_slope'] > 0) & (dataframe['ema26_slope'] > 0) & (dataframe['price_above_ema200'])
dataframe['strong_downtrend'] = (dataframe['ema12_slope'] < 0) & (dataframe['ema26_slope'] < 0) & (dataframe['price_below_ema200'])
# RSI 用于确认
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
# ATR 用于波动率过滤
dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)
dataframe['atr_mean'] = dataframe['atr'].rolling(window=20).mean()
# 波动率过滤:只在波动率足够时交易
dataframe['volatility_ok'] = dataframe['atr'] > dataframe['atr_mean'] * 0.8
return dataframe
def add_indicators_1m(self, dataframe: DataFrame) -> DataFrame:
"""在1m级别计算基础指标"""
dataframe['rsi_1m'] = ta.RSI(dataframe, timeperiod=14)
dataframe['volume_mean'] = dataframe['volume'].rolling(window=20).mean()
# MACD 用于1m级别确认
macd_1m = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
dataframe['macd_1m'] = macd_1m['macd']
dataframe['macdsignal_1m'] = macd_1m['macdsignal']
dataframe['macdhist_1m'] = macd_1m['macdhist']
# MACD交叉确认
dataframe['macd_cross_up_1m'] = (
(dataframe['macd_1m'] > dataframe['macdsignal_1m']) &
(dataframe['macd_1m'].shift(1) <= dataframe['macdsignal_1m'].shift(1))
)
dataframe['macd_cross_dn_1m'] = (
(dataframe['macd_1m'] < dataframe['macdsignal_1m']) &
(dataframe['macd_1m'].shift(1) >= dataframe['macdsignal_1m'].shift(1))
)
return dataframe
def identify_same_level_segments(self, dataframe: DataFrame) -> DataFrame:
"""
识别同级别走势段(a+A结构)
实现5分钟级别的同级别分解:
1. 识别A0(即a)、A1、A2、A3等走势段
2. 判断每个段的类型(上涨/下跌):如果a+A向上,则Ai当i为奇数时向下,i为偶数时向上
3. 识别中枢形成条件
4. 计算盘整背驰(Ai与Ai+2比较力度)
5. 标记买卖点
"""
df = dataframe.copy()
# 初始化列
df['ai_index'] = -1 # Ai的索引(A0, A1, A2, ...
df['ai_type'] = 0 # 1: 上涨, -1: 下跌
df['ai_high'] = np.nan # Ai的高点
df['ai_low'] = np.nan # Ai的低点
df['ai_macd_max'] = np.nan # Ai的MACD最大值
df['ai_macd_min'] = np.nan # Ai的MACD最小值
df['zs_formed'] = False # 是否形成中枢
df['panzheng_beichi'] = False # 盘整背驰信号
df['buy_signal'] = False # 买入信号
df['sell_signal'] = False # 卖出信号
# 识别关键转折点(局部高点和低点)
window = 3 # 确认窗口
lookback = window + 1
# 高点识别(延迟确认)
df['temp_high'] = df['high'].shift(window)
df['is_pivot_high'] = (
(df['temp_high'] == df['temp_high'].rolling(window=lookback).max()) &
(df['temp_high'].notna())
)
# 低点识别(延迟确认)
df['temp_low'] = df['low'].shift(window)
df['is_pivot_low'] = (
(df['temp_low'] == df['temp_low'].rolling(window=lookback).min()) &
(df['temp_low'].notna())
)
# 逐行处理,识别走势段
ai_list = [] # 存储Ai段的信息:[(start_idx, end_idx, type, high, low, macd_max, macd_min), ...]
current_ai_start = None
current_ai_type = None # 1: 上涨, -1: 下跌
last_pivot_idx = None
last_pivot_type = None # 'high' or 'low'
for i in range(window, len(df)):
# 检查是否有新的转折点
is_new_pivot = False
pivot_type = None
if df.iloc[i]['is_pivot_high']:
is_new_pivot = True
pivot_type = 'high'
elif df.iloc[i]['is_pivot_low']:
is_new_pivot = True
pivot_type = 'low'
if is_new_pivot and last_pivot_idx is not None:
# 完成一个走势段
if current_ai_start is not None:
seg_df = df.iloc[current_ai_start:i]
if len(seg_df) >= 3: # 至少3根K线
# 使用已确认的数据计算(不包括当前转折点)
# 为了安全,只使用到 last_pivot_idx 之前的数据
confirmed_seg_df = df.iloc[current_ai_start:last_pivot_idx] if last_pivot_idx > current_ai_start else seg_df
if len(confirmed_seg_df) > 0:
high_val = confirmed_seg_df['high'].max()
low_val = confirmed_seg_df['low'].min()
macd_max = confirmed_seg_df['macd'].max()
macd_min = confirmed_seg_df['macd'].min()
else:
high_val = seg_df['high'].max()
low_val = seg_df['low'].min()
macd_max = seg_df['macd'].max()
macd_min = seg_df['macd'].min()
# 判断走势类型
if current_ai_type is None:
# 第一个段(A0),根据价格变化判断
if high_val > df.iloc[current_ai_start]['close']:
current_ai_type = 1 # 上涨
else:
current_ai_type = -1 # 下跌
else:
# 后续段:如果a+A向上,则Ai当i为奇数时向下,i为偶数时向上
# 简化处理:根据转折点类型判断
if pivot_type == 'high' and last_pivot_type == 'low':
current_ai_type = 1 # 上涨段
elif pivot_type == 'low' and last_pivot_type == 'high':
current_ai_type = -1 # 下跌段
ai_list.append({
'start': current_ai_start,
'end': i,
'type': current_ai_type,
'high': high_val,
'low': low_val,
'macd_max': macd_max,
'macd_min': macd_min
})
# 标记到dataframe(只在段结束时标记,避免未来数据)
# 使用滚动窗口:只在确认转折点后才标记前一段的信息
# 为了安全,只在段的最后几根K线标记(确认段已结束)
confirm_window = min(3, i - current_ai_start) # 确认窗口,最多3根K线
mark_start = max(current_ai_start, i - confirm_window)
df.iloc[mark_start:i, df.columns.get_loc('ai_index')] = len(ai_list) - 1
df.iloc[mark_start:i, df.columns.get_loc('ai_type')] = current_ai_type
# 高点和低点使用已确认的数据
df.iloc[mark_start:i, df.columns.get_loc('ai_high')] = high_val
df.iloc[mark_start:i, df.columns.get_loc('ai_low')] = low_val
df.iloc[mark_start:i, df.columns.get_loc('ai_macd_max')] = macd_max
df.iloc[mark_start:i, df.columns.get_loc('ai_macd_min')] = macd_min
# 开始新的走势段
current_ai_start = last_pivot_idx
last_pivot_idx = i
last_pivot_type = pivot_type
elif is_new_pivot:
# 第一个转折点
last_pivot_idx = i
last_pivot_type = pivot_type
if current_ai_start is None:
current_ai_start = 0
# 处理最后一个段
if current_ai_start is not None:
# 标记当前未完成的段
if len(df) - current_ai_start >= 3:
seg_df = df.iloc[current_ai_start:]
high_val = seg_df['high'].max()
low_val = seg_df['low'].min()
macd_max = seg_df['macd'].max()
macd_min = seg_df['macd'].min()
# 使用最后一个段的类型
if len(ai_list) > 0:
last_type = ai_list[-1]['type']
# 如果上一个段是上涨,当前应该是下跌(或相反)
current_ai_type = -last_type
else:
current_ai_type = 1 if high_val > df.iloc[current_ai_start]['close'] else -1
ai_list.append({
'start': current_ai_start,
'end': len(df),
'type': current_ai_type,
'high': high_val,
'low': low_val,
'macd_max': macd_max,
'macd_min': macd_min
})
df.iloc[current_ai_start:, df.columns.get_loc('ai_index')] = len(ai_list) - 1
df.iloc[current_ai_start:, df.columns.get_loc('ai_type')] = current_ai_type
df.iloc[current_ai_start:, df.columns.get_loc('ai_high')] = high_val
df.iloc[current_ai_start:, df.columns.get_loc('ai_low')] = low_val
df.iloc[current_ai_start:, df.columns.get_loc('ai_macd_max')] = macd_max
df.iloc[current_ai_start:, df.columns.get_loc('ai_macd_min')] = macd_min
# 识别中枢和盘整背驰
df = self.identify_zs_and_beichi(df, ai_list)
# 清理临时列
df = df.drop(columns=['temp_high', 'temp_low', 'is_pivot_high', 'is_pivot_low'])
return df
def identify_zs_and_beichi(self, dataframe: DataFrame, ai_list: list) -> DataFrame:
"""
识别中枢和盘整背驰
1. 中枢形成:如果A3跌破a的高点,则A1、A2、A3必然构成30分钟中枢
2. 盘整背驰:Ai与Ai+2之间比较力度(MACD面积或幅度)
3. 标记买卖点:
- 盘整背驰:i+2为偶数时卖出,i+2为奇数时买入
- 非背驰情况:根据Ai+3是否跌破/升破Ai的高低点决定
注意:为了避免未来数据,只在段确认结束后才标记信号
"""
df = dataframe.copy()
if len(ai_list) < 3:
return df
# 逐行处理,只在当前行可以确认历史段的信息时才标记
# 这样可以避免使用未来数据
for row_idx in range(len(df)):
# 找到当前行属于哪个段
current_ai_idx = -1
for ai_idx, ai in enumerate(ai_list):
if ai['start'] <= row_idx < ai['end']:
current_ai_idx = ai_idx
break
if current_ai_idx < 0:
continue
# 只在段的最后几根K线才处理,确保段已确认结束
current_ai = ai_list[current_ai_idx]
if row_idx < current_ai['end'] - 3: # 只在段的最后3根K线处理
continue
# 识别中枢(A1、A2、A3构成中枢)
# 只在A3段结束时才标记中枢,避免使用未来数据
if current_ai_idx >= 2: # 至少需要A0, A1, A2
a0 = ai_list[0]
a1 = ai_list[current_ai_idx - 2] if current_ai_idx >= 2 else None
a2 = ai_list[current_ai_idx - 1] if current_ai_idx >= 1 else None
a3 = ai_list[current_ai_idx]
if a1 and a2 and a3:
# 如果A3跌破a(A0)的高点,则A1、A2、A3构成中枢
if a3['low'] < a0['high']:
# 只在A3段的最后几根K线标记中枢
df.iloc[row_idx, df.columns.get_loc('zs_formed')] = True
# 盘整背驰判断:Ai与Ai+2比较力度
# 只在ai_plus_2段结束时才判断,避免使用未来数据
if current_ai_idx >= 2:
ai = ai_list[current_ai_idx - 2]
ai_plus_2 = ai_list[current_ai_idx]
# 计算力度(使用MACD面积或价格幅度)
if ai['type'] == ai_plus_2['type']: # 同方向才能比较
# 上涨段:比较MACD最大值和价格涨幅
if ai['type'] == 1: # 上涨
price_strength_ai = (ai['high'] - ai['low']) / ai['low'] if ai['low'] > 0 else 0
price_strength_ai2 = (ai_plus_2['high'] - ai_plus_2['low']) / ai_plus_2['low'] if ai_plus_2['low'] > 0 else 0
macd_strength_ai = ai['macd_max']
macd_strength_ai2 = ai_plus_2['macd_max']
# 盘整顶背驰:价格创新高或接近,但MACD力度减弱
beichi = (
(price_strength_ai2 <= price_strength_ai * 1.1) & # 价格涨幅相近或更小
(macd_strength_ai2 < macd_strength_ai * 0.9) # MACD力度明显减弱
)
else: # 下跌
price_strength_ai = (ai['high'] - ai['low']) / ai['low'] if ai['low'] > 0 else 0
price_strength_ai2 = (ai_plus_2['high'] - ai_plus_2['low']) / ai_plus_2['low'] if ai_plus_2['low'] > 0 else 0
macd_strength_ai = abs(ai['macd_min'])
macd_strength_ai2 = abs(ai_plus_2['macd_min'])
# 盘整底背驰:价格创新低或接近,但MACD力度减弱
beichi = (
(abs(price_strength_ai2) <= abs(price_strength_ai) * 1.1) & # 价格跌幅相近或更小
(macd_strength_ai2 < macd_strength_ai * 0.9) # MACD力度明显减弱
)
if beichi:
# 只在ai_plus_2段的最后几根K线标记信号
# i+2为偶数时卖出,i+2为奇数时买入
if (current_ai_idx) % 2 == 0: # 偶数,卖出
df.iloc[row_idx, df.columns.get_loc('sell_signal')] = True
df.iloc[row_idx, df.columns.get_loc('panzheng_beichi')] = True
else: # 奇数,买入
df.iloc[row_idx, df.columns.get_loc('buy_signal')] = True
df.iloc[row_idx, df.columns.get_loc('panzheng_beichi')] = True
# 非背驰情况的处理(简化版)
# 只在Ai+4段结束时才标记,避免使用未来数据
if current_ai_idx >= 4:
ai = ai_list[current_ai_idx - 4]
ai_plus_3 = ai_list[current_ai_idx - 1]
ai_plus_4 = ai_list[current_ai_idx]
if (current_ai_idx - 4) % 2 == 0: # i为偶数
# 若Ai+3不跌破Ai高点,继续持有(不标记卖出)
if ai_plus_3['low'] < ai['high']:
# Ai+3跌破Ai高点,在不创新高或盘整顶背驰的Ai+k+4卖出
if ai_plus_4['high'] <= ai_plus_3['high']: # 不创新高
df.iloc[row_idx, df.columns.get_loc('sell_signal')] = True
else: # i为奇数
# 若Ai+3不升破Ai低点,继续保持不回补
if ai_plus_3['high'] > ai['low']:
# Ai+3升破Ai低点,在不创新低或盘整底背驰的Ai+k+4回补
if ai_plus_4['low'] >= ai_plus_3['low']: # 不创新低
df.iloc[row_idx, df.columns.get_loc('buy_signal')] = True
return df
def detect_divergence(self, dataframe: DataFrame) -> DataFrame:
"""
检测背驰(使用滚动窗口,避免未来函数)
顶背驰:价格创新高,但MACD不创新高
底背驰:价格创新低,但MACD不创新低
"""
df = dataframe.copy()
# 使用滚动窗口检测背驰(只使用历史数据)
lookback = 20 # 向前看20根K线
# 顶背驰检测:当前价格是近期最高,但MACD不是近期最高
df['recent_high'] = df['high'].rolling(window=lookback).max()
df['recent_macd_max'] = df['macd'].rolling(window=lookback).max()
df['prev_recent_high'] = df['high'].rolling(window=lookback).max().shift(1)
df['prev_recent_macd_max'] = df['macd'].rolling(window=lookback).max().shift(1)
# 当前价格创新高,但MACD没有创新高(或降低)
df['divergence_top'] = (
(df['high'] >= df['recent_high']) & # 当前是近期最高
(df['high'] > df['prev_recent_high']) & # 比之前的最高更高
(df['macd'] < df['prev_recent_macd_max']) & # MACD没有创新高
(df['macd'] < 0) # MACD在零轴下方(下跌趋势中的顶背驰)
)
# 底背驰检测:当前价格是近期最低,但MACD不是近期最低
df['recent_low'] = df['low'].rolling(window=lookback).min()
df['recent_macd_min'] = df['macd'].rolling(window=lookback).min()
df['prev_recent_low'] = df['low'].rolling(window=lookback).min().shift(1)
df['prev_recent_macd_min'] = df['macd'].rolling(window=lookback).min().shift(1)
# 当前价格创新低,但MACD没有创新低(或升高)
df['divergence_bottom'] = (
(df['low'] <= df['recent_low']) & # 当前是近期最低
(df['low'] < df['prev_recent_low']) & # 比之前的最低更低
(df['macd'] > df['prev_recent_macd_min']) & # MACD没有创新低
(df['macd'] > 0) # MACD在零轴上方(上涨趋势中的底背驰)
)
return df
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
入场逻辑:基于同级别分解的a+A结构
1. 盘整背驰买入:i+2为奇数时的盘整背驰信号
2. 非背驰情况的买入:Ai+3升破Ai低点后的回补信号
"""
ticker = self.get_ticker_indicator()
resample_col = f"resample_{ticker * self.same_level_timeframe}_"
# 获取5m级别的指标
buy_signal_col = f"{resample_col}buy_signal"
panzheng_beichi_col = f"{resample_col}panzheng_beichi"
ai_type_col = f"{resample_col}ai_type"
rsi_5m_col = f"{resample_col}rsi"
# 获取30m级别的趋势指标
ema_trend_up_col = f"{resample_col}ema_trend_up"
ema_trend_dn_col = f"{resample_col}ema_trend_dn"
volatility_ok_col = f"{resample_col}volatility_ok"
strong_uptrend_col = f"{resample_col}strong_uptrend"
strong_downtrend_col = f"{resample_col}strong_downtrend"
price_above_ema200_col = f"{resample_col}price_above_ema200"
price_below_ema200_col = f"{resample_col}price_below_ema200"
# 做多条件(激进优化:在下跌趋势中禁止做多,只在强上涨趋势中做多)
# 1. 盘整背驰买入信号(i+2为奇数)
# 2. 非背驰情况的回补信号
# 3. 确认是上涨段或即将上涨
# 4. 强上涨趋势确认(必须价格在EMA200上方且EMA斜率向上)
# 5. 波动率确认
# 6. MACD确认
# 7. 禁止在下跌趋势中做多
dataframe.loc[
(
(dataframe[buy_signal_col] == True) & # 买入信号
(
(dataframe[panzheng_beichi_col] == True) | # 盘整背驰
(dataframe[ai_type_col] == 1) # 或当前是上涨段
) &
(dataframe[strong_uptrend_col] == True) & # 强上涨趋势(新增:必须强趋势)
(dataframe[price_above_ema200_col] == True) & # 价格在EMA200上方(新增)
(dataframe[volatility_ok_col] == True) & # 波动率足够
(dataframe[rsi_5m_col] < 60) & # RSI不过度超买(收紧)
(dataframe[rsi_5m_col] > 40) & # RSI在合理区间(收紧)
(dataframe['rsi_1m'] > 40) & # 1m RSI确认(收紧)
(dataframe['rsi_1m'] < 65) & # 1m RSI不过度超买(收紧)
(dataframe['macd_1m'] > dataframe['macdsignal_1m']) & # MACD向上
(dataframe['macd_1m'] > 0) & # MACD在零轴上方(新增)
(dataframe['volume'] > dataframe['volume_mean'] * 1.5) & # 成交量确认(提高阈值)
~(dataframe[strong_downtrend_col] == True) # 禁止在强下跌趋势中做多(新增)
),
["enter_long", "enter_tag"],
] = (1, "same_level_long")
# 做空条件(优化:收紧条件,提高质量)
# 1. 盘整背驰卖出信号(i+2为偶数,但这里作为做空入场)
# 2. 非背驰情况的卖出信号
# 3. 确认是下跌段或即将下跌
# 4. 强下跌趋势确认(必须价格在EMA200下方且EMA斜率向下)
# 5. 波动率确认
# 6. MACD确认
sell_signal_col = f"{resample_col}sell_signal"
dataframe.loc[
(
(dataframe[sell_signal_col] == True) & # 卖出信号
(
(dataframe[panzheng_beichi_col] == True) | # 盘整背驰(但i+2为偶数)
(dataframe[ai_type_col] == -1) # 或当前是下跌段
) &
(
(dataframe[strong_downtrend_col] == True) | # 强下跌趋势(优先)
(
(dataframe[ema_trend_dn_col] == True) & # 30m趋势向下
(dataframe[price_below_ema200_col] == True) # 且价格在EMA200下方
)
) &
(dataframe[volatility_ok_col] == True) & # 波动率足够
(dataframe[rsi_5m_col] > 40) & # RSI不过度超卖(收紧)
(dataframe[rsi_5m_col] < 65) & # RSI不过度超买(收紧)
(dataframe['rsi_1m'] < 65) & # 1m RSI确认(收紧)
(dataframe['rsi_1m'] > 35) & # 1m RSI不过度超卖(收紧)
(dataframe['macd_1m'] < dataframe['macdsignal_1m']) & # MACD向下
(dataframe['macd_1m'] < 0) & # MACD在零轴下方(新增)
(dataframe['volume'] > dataframe['volume_mean'] * 1.3) # 成交量确认(提高阈值)
),
["enter_short", "enter_tag"],
] = (1, "same_level_short")
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
出场逻辑:基于同级别分解的a+A结构
1. 盘整背驰卖出:i+2为偶数时的盘整背驰信号
2. 非背驰情况的卖出:Ai+3跌破Ai高点后的卖出信号
"""
ticker = self.get_ticker_indicator()
resample_col = f"resample_{ticker * self.same_level_timeframe}_"
# 获取5m级别的指标
sell_signal_col = f"{resample_col}sell_signal"
buy_signal_col = f"{resample_col}buy_signal"
panzheng_beichi_col = f"{resample_col}panzheng_beichi"
ai_type_col = f"{resample_col}ai_type"
rsi_5m_col = f"{resample_col}rsi"
ema_trend_up_col = f"{resample_col}ema_trend_up"
ema_trend_dn_col = f"{resample_col}ema_trend_dn"
strong_uptrend_col = f"{resample_col}strong_uptrend"
strong_downtrend_col = f"{resample_col}strong_downtrend"
# 做多出场(优化:更早退出,保护利润)
# 在趋势转弱或明确反转时退出
dataframe.loc[
(
(
(dataframe[sell_signal_col] == True) & # 明确的卖出信号
(dataframe[panzheng_beichi_col] == True) # 且是背驰信号
) |
(
(dataframe[ai_type_col] == -1) & # 转为下跌段
(dataframe[rsi_5m_col] > 55) & # RSI确认(降低阈值,更早退出)
(dataframe[ema_trend_dn_col] == True) # 且趋势确实向下
) |
(
(dataframe[strong_downtrend_col] == True) & # 强下跌趋势(新增)
(dataframe[rsi_5m_col] > 50) # RSI确认
)
),
["exit_long", "exit_tag"],
] = (1, "same_level_exit_long")
# 做空出场(优化:更早退出,保护利润)
# 在趋势转弱或明确反转时退出
dataframe.loc[
(
(
(dataframe[buy_signal_col] == True) & # 明确的买入信号
(dataframe[panzheng_beichi_col] == True) # 且是背驰信号
) |
(
(dataframe[ai_type_col] == 1) & # 转为上涨段
(dataframe[rsi_5m_col] < 45) & # RSI确认(提高阈值,更早退出)
(dataframe[ema_trend_up_col] == True) # 且趋势确实向上
) |
(
(dataframe[strong_uptrend_col] == True) & # 强上涨趋势(新增)
(dataframe[rsi_5m_col] < 50) # RSI确认
)
),
["exit_short", "exit_tag"],
] = (1, "same_level_exit_short")
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
def get_ticker_indicator(self) -> int:
"""获取 timeframe 的分钟数"""
return int(self.timeframe[:-1])