4h波段过滤入场信号
This commit is contained in:
parent
3f25ff41ce
commit
e3202e9ce6
@ -9,6 +9,7 @@
|
||||
"fiat_display_currency": "USD",
|
||||
"dry_run": true,
|
||||
"timeframe": "3m",
|
||||
"additional_timeframes": ["4h"],
|
||||
"dry_run_wallet": 2000,
|
||||
"cancel_open_orders_on_exit": true,
|
||||
"stoploss": -0.14,
|
||||
|
||||
@ -174,83 +174,98 @@ class FreqaiPrimer(IStrategy):
|
||||
|
||||
def is_bearish_market(self, dataframe: DataFrame, metadata: dict, timeframe: str = "4h") -> pd.Series:
|
||||
"""
|
||||
判断是否为熊市信号(使用已有的 4h 指标)
|
||||
返回一个与 dataframe 等长的布尔 Series
|
||||
判断 4h 时间框架是否为熊市,返回布尔 Series
|
||||
条件:
|
||||
a. 价格远低于布林带中轨
|
||||
b. STOCHRSI 超过90
|
||||
c. 看跌蜡烛图形态(看跌吞没、乌云盖顶、射击之星,或 STOCHRSI 最近10周期均值>85)
|
||||
d. 成交量显著下降
|
||||
"""
|
||||
pair = metadata.get('pair', 'Unknown')
|
||||
logger.debug(f"[{pair}] 开始计算 is_bearish_market")
|
||||
logger.debug(f"[{pair}] 开始计算 4h 熊市信号")
|
||||
|
||||
# 防御性检查
|
||||
required_columns = ['close_4h', 'high_4h', 'low_4h', 'open_4h', 'stochrsi_k_4h', 'stochrsi_d_4h', 'bb_middle_4h']
|
||||
required_columns = ['close_4h', 'high_4h', 'low_4h', 'open_4h', 'stochrsi_k_4h', 'stochrsi_d_4h', 'bb_middle_4h', 'volume_z_score_4h']
|
||||
missing = [col for col in required_columns if col not in dataframe.columns]
|
||||
if missing:
|
||||
logger.error(f"[{pair}] 缺少必要列:{missing},返回全 False")
|
||||
return pd.Series([False] * len(dataframe), index=dataframe.index)
|
||||
|
||||
# 条件1:价格低于布林带中轨
|
||||
cond1 = dataframe['close_4h'] < dataframe['bb_middle_4h']
|
||||
# 条件 a:价格远低于布林带中轨(低于中轨 1% 以上)
|
||||
cond_a = dataframe['close_4h'] < dataframe['bb_middle_4h'] * 0.99
|
||||
|
||||
# 条件2:STOCHRSI 超买后反转
|
||||
stochrsi_k = dataframe['stochrsi_k_4h']
|
||||
stochrsi_d = dataframe['stochrsi_d_4h']
|
||||
cond2 = (stochrsi_k > 80) & (stochrsi_k < stochrsi_d)
|
||||
# 条件 b:STOCHRSI 超过90
|
||||
cond_b = dataframe['stochrsi_k_4h'] > 90
|
||||
|
||||
# 条件3:看跌蜡烛图形态
|
||||
open = dataframe['open_4h']
|
||||
close = dataframe['close_4h']
|
||||
high = dataframe['high_4h']
|
||||
low = dataframe['low_4h']
|
||||
prev_open = open.shift(1)
|
||||
prev_close = close.shift(1)
|
||||
# 条件 c:看跌蜡烛图形态
|
||||
open_4h = dataframe['open_4h']
|
||||
close_4h = dataframe['close_4h']
|
||||
high_4h = dataframe['high_4h']
|
||||
low_4h = dataframe['low_4h']
|
||||
prev_open = open_4h.shift(1)
|
||||
prev_close = close_4h.shift(1)
|
||||
|
||||
# 看跌吞没形态
|
||||
cond_engulfing = (
|
||||
(open < prev_close) &
|
||||
(close > prev_open) &
|
||||
(close < prev_close)
|
||||
(prev_close > prev_open) &
|
||||
(close_4h < open_4h) &
|
||||
(close_4h < prev_open) &
|
||||
(open_4h > prev_close)
|
||||
)
|
||||
|
||||
# 乌云盖顶
|
||||
cond_dark_cloud_cover = (
|
||||
(close < prev_open) &
|
||||
(open > prev_close) &
|
||||
(close < (prev_open + prev_close) / 2)
|
||||
(prev_close > prev_open) &
|
||||
(open_4h > prev_close) &
|
||||
(close_4h < (prev_open + prev_close) / 2) &
|
||||
(close_4h < open_4h)
|
||||
)
|
||||
|
||||
# 射击之星
|
||||
body = abs(open - close)
|
||||
upper_wick = high - np.maximum(open, close)
|
||||
lower_wick = np.minimum(open, close) - low
|
||||
cond_shooting_star = (upper_wick > 2 * body) & (lower_wick < body)
|
||||
body = abs(open_4h - close_4h)
|
||||
upper_wick = high_4h - np.maximum(open_4h, close_4h)
|
||||
lower_wick = np.minimum(open_4h, close_4h) - low_4h
|
||||
cond_shooting_star = (upper_wick > 2 * body) & (lower_wick < body) & (close_4h < open_4h)
|
||||
|
||||
bearish_candle = cond_engulfing | cond_dark_cloud_cover | cond_shooting_star
|
||||
# STOCHRSI 最近10周期均值>85
|
||||
cond_stochrsi_high = self.is_stochrsi_overbought(dataframe, period=10, threshold=85)
|
||||
|
||||
# 最终熊市信号
|
||||
bearish_signal = cond1 & cond2 & bearish_candle
|
||||
cond_c = cond_engulfing | cond_dark_cloud_cover | cond_shooting_star | cond_stochrsi_high
|
||||
|
||||
logger.debug(f"[{pair}] 熊市信号生成完成,共 {bearish_signal.sum()} 根 K 线符合")
|
||||
# 条件 d:成交量显著下降(volume_z_score < -1.0)
|
||||
cond_d = dataframe['volume_z_score_4h'] < -1.0
|
||||
|
||||
# 综合熊市信号(至少满足两个条件以提高稳定性)
|
||||
bearish_signal = (cond_a & cond_b) | (cond_a & cond_c) | (cond_b & cond_c) | (cond_a & cond_d)
|
||||
|
||||
logger.debug(f"[{pair}] 熊市信号生成完成,满足条件的 K 线数:{bearish_signal.sum()}")
|
||||
return bearish_signal
|
||||
|
||||
def trailing_space(self):
|
||||
return [
|
||||
DecimalParameter(0.01, 0.05, name="trailing_stop_start"),
|
||||
DecimalParameter(0.005, 0.02, name="trailing_stop_distance")
|
||||
]
|
||||
|
||||
def leverage_space(self):
|
||||
return [
|
||||
DecimalParameter(-0.05, -0.01, name="add_position_threshold", default=-0.02),
|
||||
DecimalParameter(0.2, 0.7, name="exit_position_ratio", default=0.5),
|
||||
IntParameter(1, 10, name="cooldown_period_minutes", default=5),
|
||||
IntParameter(1, 3, name="max_entry_position_adjustment", default=2)
|
||||
]
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
计算主时间框架(3m)和 4h 时间框架的指标,并映射到主 dataframe。
|
||||
包含 FreqAI 预测、布林带、RSI、成交量 Z 分数等,并确保 4h 数据列完整性。
|
||||
"""
|
||||
pair = metadata.get('pair', 'Unknown')
|
||||
logger.info(f"[{pair}] 当前可用列(调用FreqAI前):{list(dataframe.columns)}")
|
||||
|
||||
# 计算200周期EMA和历史价值背离
|
||||
# 计算主时间框架(3m)指标
|
||||
dataframe["ema200"] = ta.EMA(dataframe, timeperiod=200)
|
||||
dataframe["price_value_divergence"] = (dataframe["close"] - dataframe["ema200"]) / dataframe["ema200"]
|
||||
|
||||
# 调用FreqAI预测价值背离
|
||||
if not hasattr(self, 'freqai') or self.freqai is None:
|
||||
logger.error(f"[{pair}] FreqAI 未初始化,请确保回测命令中启用了 --freqai")
|
||||
dataframe["&-price_value_divergence"] = dataframe["price_value_divergence"]
|
||||
else:
|
||||
logger.debug(f"self.freqai 类型:{type(self.freqai)}")
|
||||
dataframe = self.freqai.start(dataframe, metadata, self)
|
||||
|
||||
if "&-price_value_divergence" not in dataframe.columns:
|
||||
logger.warning(f"[{pair}] 回归模型未生成 &-price_value_divergence,回退到规则计算")
|
||||
dataframe["&-price_value_divergence"] = dataframe["price_value_divergence"]
|
||||
|
||||
# 计算其他指标
|
||||
upperband, middleband, lowerband = ta.BBANDS(dataframe["close"], timeperiod=20, nbdevup=2.0, nbdevdn=2.0)
|
||||
dataframe["bb_upperband"] = upperband
|
||||
dataframe["bb_middleband"] = middleband
|
||||
@ -259,45 +274,66 @@ class FreqaiPrimer(IStrategy):
|
||||
dataframe["volume_mean_20"] = dataframe["volume"].rolling(20).mean()
|
||||
dataframe["volume_std_20"] = dataframe["volume"].rolling(20).std()
|
||||
dataframe["volume_z_score"] = (dataframe["volume"] - dataframe["volume_mean_20"]) / dataframe["volume_std_20"]
|
||||
# 获取 4h 时间框架的数据
|
||||
# 计算主时间框架的 STOCHRSI
|
||||
stochrsi = ta.STOCHRSI(dataframe, timeperiod=14, fastk_period=3, fastd_period=3)
|
||||
dataframe["stochrsi_k"] = stochrsi["fastk"]
|
||||
dataframe["stochrsi_d"] = stochrsi["fastd"]
|
||||
|
||||
# 获取 4h 时间框架数据
|
||||
dataframe_4h = self.dp.get_pair_dataframe(pair=pair, timeframe="4h")
|
||||
|
||||
# 在 4h 上计算 STOCHRSI 和布林带等指标
|
||||
stochrsi = ta.STOCHRSI(dataframe_4h, timeperiod=14, fastk_period=3, fastd_period=3)
|
||||
dataframe_4h['stochrsi_k'] = stochrsi['fastk']
|
||||
dataframe_4h['stochrsi_d'] = stochrsi['fastd']
|
||||
|
||||
if dataframe_4h.empty or len(dataframe_4h) < 50:
|
||||
logger.warning(f"[{pair}] 4h 数据为空或不足({len(dataframe_4h)} 根K线),初始化空列")
|
||||
for col in ['open_4h', 'high_4h', 'low_4h', 'close_4h', 'stochrsi_k_4h', 'stochrsi_d_4h',
|
||||
'bb_upper_4h', 'bb_middle_4h', 'bb_lower_4h', 'volume_z_score_4h']:
|
||||
dataframe[col] = np.nan
|
||||
else:
|
||||
# 计算 4h 指标
|
||||
stochrsi_4h = ta.STOCHRSI(dataframe_4h, timeperiod=14, fastk_period=3, fastd_period=3)
|
||||
dataframe_4h['stochrsi_k'] = stochrsi_4h['fastk']
|
||||
dataframe_4h['stochrsi_d'] = stochrsi_4h['fastd']
|
||||
real = ta.TYPPRICE(dataframe_4h)
|
||||
upperband, middleband, lowerband = ta.BBANDS(real, timeperiod=20, nbdevup=2.0, nbdevdn=2.0)
|
||||
dataframe_4h['bb_upper'] = upperband
|
||||
dataframe_4h['bb_middle'] = middleband
|
||||
dataframe_4h['bb_lower'] = lowerband
|
||||
dataframe_4h['bb_upper_4h'] = upperband
|
||||
dataframe_4h['bb_middle_4h'] = middleband
|
||||
dataframe_4h['bb_lower_4h'] = lowerband
|
||||
dataframe_4h['volume_mean_20_4h'] = dataframe_4h["volume"].rolling(20).mean()
|
||||
dataframe_4h['volume_std_20_4h'] = dataframe_4h["volume"].rolling(20).std()
|
||||
dataframe_4h['volume_z_score_4h'] = (dataframe_4h["volume"] - dataframe_4h['volume_mean_20_4h']) / dataframe_4h['volume_std_20_4h']
|
||||
|
||||
# 映射 OHLC 和其他指标到主时间框架,添加 _4h 后缀
|
||||
for col in ['open', 'high', 'low', 'close', 'stochrsi_k', 'stochrsi_d', 'bb_upper', 'bb_middle', 'bb_lower']:
|
||||
new_col = f"{col}_4h"
|
||||
dataframe[new_col] = dataframe_4h[col].reindex(dataframe.index, method='ffill').bfill()
|
||||
# 映射 4h 数据到主时间框架
|
||||
for col in ['open', 'high', 'low', 'close', 'stochrsi_k', 'stochrsi_d', 'bb_upper_4h', 'bb_middle_4h', 'bb_lower_4h', 'volume_z_score']:
|
||||
if col in dataframe_4h.columns:
|
||||
dataframe[f"{col}_4h" if not col.endswith('_4h') else col] = dataframe_4h[col].reindex(dataframe.index, method='ffill').bfill()
|
||||
else:
|
||||
logger.warning(f"[{pair}] 4h 数据缺少列 {col},初始化为空")
|
||||
dataframe[f"{col}_4h" if not col.endswith('_4h') else col] = np.nan
|
||||
|
||||
# 数据清理
|
||||
for col in ["ema200", "bb_upperband", "bb_middleband", "bb_lowerband", "rsi", "volume_z_score", "&-price_value_divergence", "price_value_divergence"]:
|
||||
# 数据清理:处理 NaN 和无穷值
|
||||
for col in ["ema200", "bb_upperband", "bb_middleband", "bb_lowerband", "rsi", "volume_z_score",
|
||||
"&-price_value_divergence", "price_value_divergence", "open_4h", "high_4h", "low_4h",
|
||||
"close_4h", "stochrsi_k_4h", "stochrsi_d_4h", "bb_upper_4h", "bb_middle_4h", "bb_lower_4h",
|
||||
"volume_z_score_4h"]:
|
||||
if col in dataframe.columns:
|
||||
dataframe[col] = dataframe[col].replace([np.inf, -np.inf], 0).ffill().fillna(0)
|
||||
|
||||
# 添加调试日志
|
||||
logger.debug(f"[{pair}] 最新数据 - close:{dataframe['close'].iloc[-1]:.6f}, "
|
||||
f"rsi:{dataframe['rsi'].iloc[-1]:.2f}, "
|
||||
f"&-price_value_divergence:{dataframe['&-price_value_divergence'].iloc[-1]:.6f}, "
|
||||
f"volume_z_score:{dataframe['volume_z_score'].iloc[-1]:.2f}, "
|
||||
f"bb_lowerband:{dataframe['bb_lowerband'].iloc[-1]:.6f}")
|
||||
# 调用 FreqAI 预测
|
||||
if not hasattr(self, 'freqai') or self.freqai is None:
|
||||
logger.error(f"[{pair}] FreqAI 未初始化,回退到规则计算")
|
||||
dataframe["&-price_value_divergence"] = dataframe["price_value_divergence"]
|
||||
else:
|
||||
logger.debug(f"[{pair}] 调用 FreqAI 预测,类型:{type(self.freqai)}")
|
||||
dataframe = self.freqai.start(dataframe, metadata, self)
|
||||
if "&-price_value_divergence" not in dataframe.columns:
|
||||
logger.warning(f"[{pair}] FreqAI 未生成 &-price_value_divergence,回退到规则计算")
|
||||
dataframe["&-price_value_divergence"] = dataframe["price_value_divergence"]
|
||||
|
||||
# 获取 labels_mean 和 labels_std
|
||||
# 计算 labels_mean 和 labels_std
|
||||
labels_mean = None
|
||||
labels_std = None
|
||||
|
||||
try:
|
||||
model_base_dir = os.path.join(self.config["user_data_dir"], "models", self.freqai_info["identifier"])
|
||||
pair_base = pair.split('/')[0] if '/' in pair else pair
|
||||
sub_dirs = glob.glob(os.path.join(model_base_dir, f"sub-train-{pair_base}_*"))
|
||||
|
||||
if not sub_dirs:
|
||||
logger.warning(f"[{pair}] 未找到任何子目录:{model_base_dir}/sub-train-{pair_base}_*")
|
||||
else:
|
||||
@ -305,7 +341,6 @@ class FreqaiPrimer(IStrategy):
|
||||
pair_base_lower = pair_base.lower()
|
||||
timestamp = latest_sub_dir.split('_')[-1]
|
||||
metadata_file = os.path.join(latest_sub_dir, f"cb_{pair_base_lower}_{timestamp}_metadata.json")
|
||||
|
||||
if os.path.exists(metadata_file):
|
||||
with open(metadata_file, "r") as f:
|
||||
metadata = json.load(f)
|
||||
@ -330,8 +365,8 @@ class FreqaiPrimer(IStrategy):
|
||||
|
||||
# 根据市场趋势得分动态调整买卖阈值
|
||||
market_trend_score = self.get_market_trend(dataframe=dataframe, metadata={'pair': pair})
|
||||
k_buy = FreqaiPrimer.linear_map(market_trend_score, 0, 100, 1.2, 0.8)
|
||||
k_sell = FreqaiPrimer.linear_map(market_trend_score, 0, 100, 1.5, 1.0)
|
||||
k_buy = self.linear_map(market_trend_score, 0, 100, 1.2, 0.8)
|
||||
k_sell = self.linear_map(market_trend_score, 0, 100, 1.5, 1.0)
|
||||
|
||||
self.buy_threshold = labels_mean - k_buy * labels_std
|
||||
self.sell_threshold = labels_mean + k_sell * labels_std
|
||||
@ -342,9 +377,18 @@ class FreqaiPrimer(IStrategy):
|
||||
self.sell_threshold = min(self.sell_threshold, self.SELL_THRESHOLD_MAX.value)
|
||||
self.sell_threshold = max(self.sell_threshold, self.SELL_THRESHOLD_MIN.value)
|
||||
|
||||
# 调试日志
|
||||
logger.info(f"[{pair}] 市场趋势得分:{market_trend_score}, labels_mean:{labels_mean:.4f}, labels_std:{labels_std:.4f}")
|
||||
logger.info(f"[{pair}] k_buy:{k_buy:.2f}, k_sell:{k_sell:.2f}")
|
||||
logger.info(f"[{pair}] 动态买入阈值:{self.buy_threshold:.4f}, 卖出阈值:{self.sell_threshold:.4f}")
|
||||
logger.debug(f"[{pair}] 最新数据 - close: {dataframe['close'].iloc[-1]:.6f}, "
|
||||
f"rsi: {dataframe['rsi'].iloc[-1]:.2f}, "
|
||||
f"&-price_value_divergence: {dataframe['&-price_value_divergence'].iloc[-1]:.6f}, "
|
||||
f"volume_z_score: {dataframe['volume_z_score'].iloc[-1]:.2f}, "
|
||||
f"bb_lowerband: {dataframe['bb_lowerband'].iloc[-1]:.6f}, "
|
||||
f"close_4h: {dataframe['close_4h'].iloc[-1] if 'close_4h' in dataframe else 'N/A'}, "
|
||||
f"stochrsi_k_4h: {dataframe['stochrsi_k_4h'].iloc[-1] if 'stochrsi_k_4h' in dataframe else 'N/A'}, "
|
||||
f"volume_z_score_4h: {dataframe['volume_z_score_4h'].iloc[-1] if 'volume_z_score_4h' in dataframe else 'N/A'}")
|
||||
|
||||
if not self.stats_logged:
|
||||
logger.info("===== 所有币对的 labels_mean 和 labels_std 汇总 =====")
|
||||
@ -354,21 +398,6 @@ class FreqaiPrimer(IStrategy):
|
||||
self.stats_logged = True
|
||||
|
||||
return dataframe
|
||||
|
||||
def trailing_space(self):
|
||||
return [
|
||||
DecimalParameter(0.01, 0.05, name="trailing_stop_start"),
|
||||
DecimalParameter(0.005, 0.02, name="trailing_stop_distance")
|
||||
]
|
||||
|
||||
def leverage_space(self):
|
||||
return [
|
||||
DecimalParameter(-0.05, -0.01, name="add_position_threshold", default=-0.02),
|
||||
DecimalParameter(0.2, 0.7, name="exit_position_ratio", default=0.5),
|
||||
IntParameter(1, 10, name="cooldown_period_minutes", default=5),
|
||||
IntParameter(1, 3, name="max_entry_position_adjustment", default=2)
|
||||
]
|
||||
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
pair = metadata.get('pair', 'Unknown')
|
||||
conditions = []
|
||||
@ -376,115 +405,63 @@ class FreqaiPrimer(IStrategy):
|
||||
# 获取市场趋势得分
|
||||
trend_score = self.get_market_trend(dataframe=dataframe, metadata=metadata)
|
||||
|
||||
# 动态调整成交量阈值
|
||||
# 动态调整成交量和 RSI 阈值
|
||||
volume_z_score_min = 0.5
|
||||
volume_z_score_max = 1.5
|
||||
volume_z_score_threshold = self.linear_map(trend_score, 0, 100, volume_z_score_max, volume_z_score_min)
|
||||
|
||||
# 动态调整 RSI 阈值
|
||||
rsi_min = 35
|
||||
rsi_max = 55
|
||||
rsi_threshold = self.linear_map(trend_score, 0, 100, rsi_max, rsi_min)
|
||||
|
||||
# 新增:动态调整 STOCHRSI 阈值
|
||||
stochrsi_min = 25
|
||||
stochrsi_max = 45
|
||||
stochrsi_threshold = self.linear_map(trend_score, 0, 100, stochrsi_max, stochrsi_min)
|
||||
|
||||
# 获取 4h 时间框架的数据
|
||||
dataframe_4h = dataframe[['close', 'stochrsi_k_4h', 'stochrsi_d_4h', 'bb_middle_4h', 'open']].copy()
|
||||
bearish_signal = self.is_bearish_market(dataframe_4h, metadata, timeframe="4h")
|
||||
bearish_signal_aligned = bearish_signal.reindex(dataframe.index, method='ffill').fillna(False)
|
||||
cond6 = ~bearish_signal_aligned
|
||||
|
||||
# 确保指标存在(或提前在 populate_indicators 中计算好)
|
||||
if not dataframe_4h.empty and 'stochrsi_k' in dataframe_4h.columns:
|
||||
stochrsi_overbought = self.is_stochrsi_overbought(dataframe_4h, period=10, threshold=85)
|
||||
else:
|
||||
stochrsi_overbought = pd.Series([False] * len(dataframe), index=dataframe.index)
|
||||
|
||||
# 映射回主时间框架
|
||||
stochrsi_overbought_aligned = stochrsi_overbought.reindex(dataframe.index, method='ffill').fillna(True)
|
||||
# 计算指标(或提前在 populate_indicators 中完成)
|
||||
stochrsi = ta.STOCHRSI(dataframe_4h, timeperiod=14, fastk_period=3, fastd_period=3)
|
||||
dataframe_4h['stochrsi_k'] = stochrsi['fastk']
|
||||
dataframe_4h['stochrsi_d'] = stochrsi['fastd']
|
||||
|
||||
# 在 populate_entry_trend 中
|
||||
high = dataframe['high_4h'].values
|
||||
low = dataframe['low_4h'].values
|
||||
close = dataframe['close_4h'].values
|
||||
|
||||
# 手动实现 TYPPRICE
|
||||
real = (high + low + close) / 3
|
||||
upperband, middleband, lowerband = ta.BBANDS(real, timeperiod=20, nbdevup=2.0, nbdevdn=2.0)
|
||||
|
||||
# 将结果放回 dataframe
|
||||
dataframe["bb_upperband-period"] = upperband
|
||||
dataframe["bb_middleband-period"] = middleband
|
||||
dataframe["bb_lowerband-period"] = lowerband
|
||||
|
||||
# 调用熊市判断函数
|
||||
# 计算熊市信号
|
||||
bearish_signal = self.is_bearish_market(dataframe, metadata, timeframe="4h")
|
||||
bearish_signal_aligned = bearish_signal.reindex(dataframe.index, method='ffill').fillna(False)
|
||||
|
||||
# 映射回主时间框架
|
||||
dataframe['bearish_signal'] = bearish_signal.reindex(dataframe.index, method='ffill').fillna(False)
|
||||
# 计算 STOCHRSI 超买信号
|
||||
stochrsi_overbought = self.is_stochrsi_overbought(dataframe, period=10, threshold=85)
|
||||
stochrsi_overbought_aligned = stochrsi_overbought.reindex(dataframe.index, method='ffill').fillna(True)
|
||||
|
||||
|
||||
# 现在你可以使用 dataframe_4h 做任何判断了
|
||||
if not dataframe_4h.empty:
|
||||
logger.info(f"[{pair}] 成功获取 4h 数据,共 {len(dataframe_4h)} 根 K 线")
|
||||
# 示例:打印最新一根 K 线的收盘价
|
||||
latest_close = dataframe_4h['close'].iloc[-1]
|
||||
logger.info(f"[{pair}] 4h 最新收盘价: {latest_close}")
|
||||
else:
|
||||
logger.warning(f"[{pair}] 无法获取 4h 数据")
|
||||
# 买入条件
|
||||
if "&-price_value_divergence" in dataframe.columns:
|
||||
divergence_value = dataframe['&-price_value_divergence'].iloc[-1]
|
||||
volume_z_score_value = dataframe['volume_z_score'].iloc[-1]
|
||||
rsi_value = dataframe['rsi'].iloc[-1]
|
||||
stochrsi_value = dataframe['stochrsi_k'].iloc[-1]
|
||||
bb_close_value = dataframe['close'].iloc[-1]
|
||||
bb_lower_value = dataframe['bb_lowerband'].iloc[-1]
|
||||
cond1 = (dataframe["&-price_value_divergence"] < self.buy_threshold)
|
||||
cond2 = (dataframe["volume_z_score"] > volume_z_score_threshold)
|
||||
cond3 = (dataframe["rsi"] < rsi_threshold)
|
||||
cond4 = (dataframe["close"] <= dataframe["bb_lowerband"])
|
||||
cond5 = (dataframe["stochrsi_k"] < stochrsi_threshold)
|
||||
cond6 = ~self.is_bearish_market(dataframe_4h, metadata, timeframe="4h")
|
||||
cond6 = ~bearish_signal_aligned
|
||||
cond7 = ~stochrsi_overbought_aligned
|
||||
|
||||
buy_condition = cond1 & cond2 & cond3 & cond4 & cond5 & cond6 & cond7
|
||||
#buy_condition = cond1 & cond2 & cond3 & cond4 & cond5
|
||||
conditions.append(buy_condition)
|
||||
|
||||
# logger.debug(f"[{pair}] 买入条件检查 - "
|
||||
# f"&-price_value_divergence={divergence_value:.6f} < {self.buy_threshold:.6f}: {cond1.iloc[-1]}, "
|
||||
# f"volume_z_score={volume_z_score_value:.2f} > {volume_z_score_threshold:.2f}: {cond2.iloc[-1]}, "
|
||||
# f"rsi={rsi_value:.2f} < {rsi_threshold:.2f}: {cond3.iloc[-1]}, "
|
||||
# f"close={bb_close_value:.6f} <= bb_lowerband={bb_lower_value:.6f}: {cond4.iloc[-1]}, "
|
||||
# f"stochrsi_k={stochrsi_value:.2f} < {stochrsi_threshold:.2f}: {cond5.iloc[-1]}, "
|
||||
# f"非熊市={cond6.iloc[-1]}, "
|
||||
# f"STOCHRSI未持续超买={cond7.iloc[-1]}")
|
||||
# bearish_signal = cond6.iloc[-1]
|
||||
|
||||
# logger.debug(f"[{pair}] 买入条件检查 - "
|
||||
# f"&-price_value_divergence={divergence_value:.6f} < {self.buy_threshold:.6f}: {cond1.iloc[-1]}, "
|
||||
# f"volume_z_score={volume_z_score_value:.2f} > {volume_z_score_threshold:.2f}: {cond2.iloc[-1]}, "
|
||||
# f"rsi={rsi_value:.2f} < {rsi_threshold:.2f}: {cond3.iloc[-1]}, "
|
||||
# f"close={bb_close_value:.6f} <= bb_lowerband={bb_lower_value:.6f}: {cond4.iloc[-1]}, "
|
||||
# f"stochrsi_k={stochrsi_value:.2f} < {stochrsi_threshold:.2f}: {cond5.iloc[-1]}, "
|
||||
# f"非熊市={bearish_signal}")
|
||||
# 调试日志
|
||||
divergence_value = dataframe["&-price_value_divergence"].iloc[-1]
|
||||
volume_z_score_value = dataframe["volume_z_score"].iloc[-1]
|
||||
rsi_value = dataframe["rsi"].iloc[-1]
|
||||
stochrsi_value = dataframe["stochrsi_k"].iloc[-1]
|
||||
bb_close_value = dataframe["close"].iloc[-1]
|
||||
bb_lower_value = dataframe["bb_lowerband"].iloc[-1]
|
||||
logger.debug(f"[{pair}] 买入条件检查 - "
|
||||
f"&-price_value_divergence={divergence_value:.6f} < {self.buy_threshold:.6f}: {cond1.iloc[-1]}, "
|
||||
f"volume_z_score={volume_z_score_value:.2f} > {volume_z_score_threshold:.2f}: {cond2.iloc[-1]}, "
|
||||
f"rsi={rsi_value:.2f} < {rsi_threshold:.2f}: {cond3.iloc[-1]}, "
|
||||
f"close={bb_close_value:.6f} <= bb_lowerband={bb_lower_value:.6f}: {cond4.iloc[-1]}, "
|
||||
f"stochrsi_k={stochrsi_value:.2f} < {stochrsi_threshold:.2f}: {cond5.iloc[-1]}, "
|
||||
f"非熊市={cond6.iloc[-1]}, "
|
||||
f"STOCHRSI未持续超买={cond7.iloc[-1]}")
|
||||
else:
|
||||
logger.warning(f"[{pair}] ⚠️ &-price_value_divergence 列缺失,跳过买入信号生成")
|
||||
logger.warning(f"[{pair}] &-price_value_divergence 列缺失,跳过买入信号生成")
|
||||
|
||||
if len(conditions) > 0:
|
||||
if conditions:
|
||||
combined_condition = reduce(lambda x, y: x & y, conditions)
|
||||
if combined_condition.any():
|
||||
dataframe.loc[combined_condition, 'enter_long'] = 1
|
||||
logger.info(f"[{pair}] 买入信号触发,条件满足,趋势得分:{trend_score:.2f}")
|
||||
if combined_condition.any():
|
||||
logger.info(f"[{pair}] 买入信号触发,趋势得分:{trend_score:.2f}")
|
||||
else:
|
||||
logger.debug(f"[{pair}] 买入条件未满足,无买入信号")
|
||||
logger.debug(f"[{pair}] 买入条件未满足")
|
||||
else:
|
||||
logger.debug(f"[{pair}] 无有效买入条件")
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user