download.sh 重要更新

This commit is contained in:
Ubuntu 2025-07-09 16:37:42 +08:00
parent aba0b61d36
commit dd742d6079
3 changed files with 55 additions and 41 deletions

BIN
.output.log.swp Normal file

Binary file not shown.

View File

@ -173,24 +173,19 @@ class FreqaiPrimer(IStrategy):
return avg_stochrsi > threshold
def is_bearish_market(self, dataframe: DataFrame, metadata: dict, timeframe: str = "4h") -> pd.Series:
"""
判断 4h 时间框架是否为熊市返回布尔 Series
条件
a. 价格远低于布林带中轨
b. STOCHRSI 超过90
c. 看跌蜡烛图形态看跌吞没乌云盖顶射击之星 STOCHRSI 最近10周期均值>85
d. 成交量显著下降
"""
pair = metadata.get('pair', 'Unknown')
logger.debug(f"[{pair}] 开始计算 4h 熊市信号")
# 防御性检查
required_columns = ['close_4h', 'high_4h', 'low_4h', 'open_4h', 'stochrsi_k_4h', 'stochrsi_d_4h', 'bb_middle_4h', 'volume_z_score_4h']
required_columns = ['close_4h', 'high_4h', 'low_4h', 'open_4h', 'stochrsi_k_4h', 'stochrsi_d_4h', 'bb_middle_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)
# 检查 volume_z_score_4h 是否存在
has_volume_z_score = 'volume_z_score_4h' in dataframe.columns and not dataframe['volume_z_score_4h'].isna().all()
# 条件 a价格远低于布林带中轨低于中轨 1% 以上)
cond_a = dataframe['close_4h'] < dataframe['bb_middle_4h'] * 0.99
@ -205,40 +200,38 @@ class FreqaiPrimer(IStrategy):
prev_open = open_4h.shift(1)
prev_close = close_4h.shift(1)
# 看跌吞没形态
cond_engulfing = (
(prev_close > prev_open) &
(close_4h < open_4h) &
(close_4h < prev_open) &
(open_4h > prev_close)
)
# 乌云盖顶
cond_dark_cloud_cover = (
(prev_close > prev_open) &
(open_4h > prev_close) &
(close_4h < (prev_open + prev_close) / 2) &
(close_4h < open_4h)
)
# 射击之星
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)
# STOCHRSI 最近10周期均值>85
cond_stochrsi_high = self.is_stochrsi_overbought(dataframe, period=10, threshold=85)
cond_c = cond_engulfing | cond_dark_cloud_cover | cond_shooting_star | cond_stochrsi_high
# 条件 d成交量显著下降volume_z_score < -1.0
cond_d = dataframe['volume_z_score_4h'] < -1.0
# 条件 d成交量显著下降
cond_d = dataframe['volume_z_score_4h'] < -1.0 if has_volume_z_score else pd.Series([False] * len(dataframe), index=dataframe.index)
# 综合熊市信号(至少满足两个条件以提高稳定性
# 综合熊市信号(至少满足两个条件
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()}")
# 记录每个条件的触发情况
logger.debug(f"[{pair}] 熊市信号 - 条件a (价格低于布林中轨): {cond_a.mean():.2%}, "
f"条件b (STOCHRSI>90): {cond_b.mean():.2%}, "
f"条件c (看跌形态): {cond_c.mean():.2%}, "
f"条件d (成交量下降): {cond_d.mean():.2%}, "
f"总熊市信号触发率: {bearish_signal.mean():.2%}")
return bearish_signal
def trailing_space(self):
@ -283,30 +276,36 @@ class FreqaiPrimer(IStrategy):
dataframe_4h = self.dp.get_pair_dataframe(pair=pair, timeframe="4h")
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',
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_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']
if len(dataframe_4h) >= 20: # 确保有足够数据计算 rolling(20)
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_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']
# 清理 NaN 和无穷值
dataframe_4h['volume_z_score_4h'] = dataframe_4h['volume_z_score_4h'].replace([np.inf, -np.inf], 0).ffill().fillna(0)
else:
logger.warning(f"[{pair}] 4h 数据不足以计算 volume_z_score_4h{len(dataframe_4h)} 根K线需至少20根")
dataframe_4h['volume_z_score_4h'] = np.nan
# 映射 4h 数据到主时间框架
for col in ['open', 'high', 'low', 'close', 'stochrsi_k', 'stochrsi_d', 'bb_upper_4h', 'bb_middle_4h', 'bb_lower_4h', 'volume_z_score']:
for col in ['open', 'high', 'low', 'close', 'stochrsi_k', 'stochrsi_d', 'bb_upper_4h', 'bb_middle_4h', 'bb_lower_4h', 'volume_z_score_4h']:
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()
dataframe[col if col.endswith('_4h') else f"{col}_4h"] = 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
dataframe[col if col.endswith('_4h') else f"{col}_4h"] = np.nan
# 数据清理:处理 NaN 和无穷值
for col in ["ema200", "bb_upperband", "bb_middleband", "bb_lowerband", "rsi", "volume_z_score",
@ -398,10 +397,13 @@ class FreqaiPrimer(IStrategy):
self.stats_logged = True
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
pair = metadata.get('pair', 'Unknown')
conditions = []
logger.info(f"[{pair}] populate_entry_trend 被调用,数据行数:{len(dataframe)},时间:{dataframe.index[-1]}")
# 记录 enter_long 信号统计
logger.info(f"[{pair}] enter_long 信号总数:{dataframe['enter_long'].sum() if 'enter_long' in dataframe.columns else 0}")
# 获取市场趋势得分
trend_score = self.get_market_trend(dataframe=dataframe, metadata=metadata)
@ -416,11 +418,9 @@ class FreqaiPrimer(IStrategy):
stochrsi_max = 45
stochrsi_threshold = self.linear_map(trend_score, 0, 100, stochrsi_max, stochrsi_min)
# 计算熊市信号
# 计算熊市信号和 STOCHRSI 超买信号
bearish_signal = self.is_bearish_market(dataframe, metadata, timeframe="4h")
bearish_signal_aligned = 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)
@ -434,6 +434,12 @@ class FreqaiPrimer(IStrategy):
cond6 = ~bearish_signal_aligned
cond7 = ~stochrsi_overbought_aligned
# 记录 cond6 和 cond7 的触发情况
logger.debug(f"[{pair}] cond6 (非熊市) 触发率: {(~bearish_signal_aligned).mean():.2%}, "
f"熊市信号 K 线数: {bearish_signal_aligned.sum()}")
logger.debug(f"[{pair}] cond7 (STOCHRSI 非超买) 触发率: {(~stochrsi_overbought_aligned).mean():.2%}, "
f"STOCHRSI 超买 K 线数: {stochrsi_overbought_aligned.sum()}")
buy_condition = cond1 & cond2 & cond3 & cond4 & cond5 & cond6 & cond7
conditions.append(buy_condition)
@ -465,6 +471,13 @@ class FreqaiPrimer(IStrategy):
else:
logger.debug(f"[{pair}] 无有效买入条件")
logger.debug(f"[{pair}] 各条件触发率 - "
f"cond1: {cond1.mean():.2%}, "
f"cond2: {cond2.mean():.2%}, "
f"cond3: {cond3.mean():.2%}, "
f"cond4: {cond4.mean():.2%}, "
f"cond5: {cond5.mean():.2%}, "
f"buy_condition: {buy_condition.mean():.2%}")
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:

View File

@ -74,7 +74,8 @@ timeframe=$(get_csv_param_value "--timeframe" "$@")
# Use default values if parameters are not provided
if [[ -z "$pairs" ]]; then
pairs="BTC/USDT,OKB/USDT,TON/USDT,DOT/USDT,SOL/USDT,XRP/USDT"
#"pair_whitelist": ["BTC/USDT" "TON/USDT" "DOT/USDT" "XRP/USDT" "OKB/USDT" "SOL/USDT" "DOGE/USDT" "WCT/USDT" "TRUMP/USDT" "SUI/USDT" "PEPE/USDT" "TRB/USDT" "MASK/USDT" "UNI/USDT" "KAITO/USDT"],
pairs="BTC/USDT" "TON/USDT" "DOT/USDT" "XRP/USDT" "OKB/USDT" "SOL/USDT" "DOGE/USDT" "WCT/USDT" "TRUMP/USDT" "SUI/USDT" "PEPE/USDT" "TRB/USDT" "MASK/USDT" "UNI/USDT" "KAITO/USDT"
fi
if [[ -z "$timeframe" ]]; then