直接从 self.freqai 获取 JSON 文件中的值
This commit is contained in:
parent
8c5d239f85
commit
2b8ee60ee5
@ -10,30 +10,19 @@ from freqtrade.strategy import IStrategy
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class FreqaiPrimer(IStrategy):
|
||||
"""
|
||||
策略说明:
|
||||
- 只使用回归模型预测价值背离(&-price_value_divergence)
|
||||
- 动态计算 labels_mean 和 labels_std,基于当前数据
|
||||
- 在日志中打印所有币对的 labels_mean 和 labels_std 汇总
|
||||
- 优化出场逻辑,避免过早卖出
|
||||
- 使用RSI和布林带作为辅助过滤条件
|
||||
"""
|
||||
|
||||
# 策略参数
|
||||
class ValueDivergencePrimerRegression(IStrategy):
|
||||
minimal_roi = {
|
||||
"0": 0.02, # 固定止盈2%
|
||||
"0": 0.02,
|
||||
"30": 0.01,
|
||||
"60": 0
|
||||
}
|
||||
|
||||
stoploss = -0.015 # 固定止损-1.5%
|
||||
stoploss = -0.015
|
||||
|
||||
timeframe = "3m" # 3分钟K线
|
||||
timeframe = "3m"
|
||||
|
||||
use_custom_stoploss = False # 不使用动态止损,改为固定止损
|
||||
use_custom_stoploss = False
|
||||
|
||||
# 绘图配置
|
||||
plot_config = {
|
||||
"main_plot": {
|
||||
"ema200": {"color": "blue"},
|
||||
@ -58,7 +47,6 @@ class FreqaiPrimer(IStrategy):
|
||||
}
|
||||
}
|
||||
|
||||
# FreqAI 配置:回归模型(预测价值背离)
|
||||
freqai_info = {
|
||||
"identifier": "divergence_model",
|
||||
"model": "LightGBMRegressor",
|
||||
@ -84,18 +72,13 @@ class FreqaiPrimer(IStrategy):
|
||||
super().__init__(config, *args, **kwargs)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
logger.debug("✅ 策略已初始化,日志级别设置为 DEBUG")
|
||||
# 动态止盈参数
|
||||
self.trailing_stop_enabled = False
|
||||
self.trailing_stop_start = 0.03 # 价格上涨 3% 后启动 Trailing Stop
|
||||
self.trailing_stop_distance = 0.01 # 允许价格回落 1% 时卖出
|
||||
# 存储每个币对的 labels_mean 和 labels_std
|
||||
self.trailing_stop_start = 0.03
|
||||
self.trailing_stop_distance = 0.01
|
||||
self.pair_stats = {}
|
||||
self.stats_logged = False # 标记是否已打印汇总日志
|
||||
self.stats_logged = False
|
||||
|
||||
def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, metadata: dict, **kwargs) -> DataFrame:
|
||||
"""
|
||||
特征工程:计算技术指标作为FreqAI的输入特征
|
||||
"""
|
||||
dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period)
|
||||
dataframe["%-sma-period"] = ta.SMA(dataframe, timeperiod=period)
|
||||
dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period)
|
||||
@ -126,9 +109,6 @@ class FreqaiPrimer(IStrategy):
|
||||
return dataframe
|
||||
|
||||
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
|
||||
"""
|
||||
设置FreqAI的训练目标:只预测价值背离
|
||||
"""
|
||||
if len(dataframe) < 200:
|
||||
logger.warning(f"[{metadata['pair']}] 数据量不足({len(dataframe)}根K线),需要至少200根K线进行训练")
|
||||
return dataframe
|
||||
@ -147,9 +127,6 @@ class FreqaiPrimer(IStrategy):
|
||||
return dataframe
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
计算所有指标,包括FreqAI预测结果,并动态计算 labels_mean 和 labels_std
|
||||
"""
|
||||
logger.info(f"[{metadata['pair']}] 当前可用列(调用FreqAI前):{list(dataframe.columns)}")
|
||||
|
||||
# 计算200周期EMA和历史价值背离
|
||||
@ -181,71 +158,78 @@ class FreqaiPrimer(IStrategy):
|
||||
for col in ["ema200", "bb_upperband", "bb_middleband", "bb_lowerband", "rsi", "volume_z_score", "&-price_value_divergence", "price_value_divergence"]:
|
||||
dataframe[col] = dataframe[col].replace([np.inf, -np.inf], 0).ffill().fillna(0)
|
||||
|
||||
# 动态计算 labels_mean 和 labels_std
|
||||
# 直接从 FreqAI 获取 labels_mean 和 labels_std
|
||||
pair = metadata["pair"]
|
||||
if "&-price_value_divergence" in dataframe.columns:
|
||||
recent_data = dataframe["&-price_value_divergence"].tail(1000)
|
||||
if hasattr(self, 'freqai') and self.freqai is not None and pair in self.freqai.data:
|
||||
# 从 self.freqai.data 中获取 labels_mean 和 labels_std
|
||||
if "labels_mean" in self.freqai.data and "&-price_value_divergence" in self.freqai.data["labels_mean"]:
|
||||
labels_mean = self.freqai.data["labels_mean"]["&-price_value_divergence"]
|
||||
labels_std = self.freqai.data["labels_std"]["&-price_value_divergence"]
|
||||
else:
|
||||
logger.warning(f"[{pair}] 无法从 FreqAI 获取 labels_mean 和 labels_std,重新计算")
|
||||
# 回退:重新计算真实目标值
|
||||
dataframe["&-price_value_divergence_actual"] = (dataframe["close"] - dataframe["ema200"]) / dataframe["ema200"]
|
||||
dataframe["&-price_value_divergence_actual"] = dataframe["&-price_value_divergence_actual"].replace([np.inf, -np.inf], 0).ffill().fillna(0)
|
||||
recent_data = dataframe["&-price_value_divergence_actual"].tail(self.freqai_info["fit_live_predictions_candles"])
|
||||
labels_mean = recent_data.mean()
|
||||
labels_std = recent_data.std()
|
||||
if np.isnan(labels_std) or labels_std == 0:
|
||||
labels_std = 0.01
|
||||
logger.warning(f"[{pair}] labels_std 计算异常,使用默认值 0.01")
|
||||
else:
|
||||
logger.warning(f"[{pair}] FreqAI 未初始化或数据不可用,重新计算")
|
||||
# 回退:重新计算真实目标值
|
||||
dataframe["&-price_value_divergence_actual"] = (dataframe["close"] - dataframe["ema200"]) / dataframe["ema200"]
|
||||
dataframe["&-price_value_divergence_actual"] = dataframe["&-price_value_divergence_actual"].replace([np.inf, -np.inf], 0).ffill().fillna(0)
|
||||
recent_data = dataframe["&-price_value_divergence_actual"].tail(self.freqai_info["fit_live_predictions_candles"])
|
||||
labels_mean = recent_data.mean()
|
||||
labels_std = recent_data.std()
|
||||
|
||||
if np.isnan(labels_std) or labels_std == 0:
|
||||
labels_std = 0.01
|
||||
logger.warning(f"[{pair}] labels_std 计算异常,使用默认值 0.01")
|
||||
|
||||
# 存储到 pair_stats
|
||||
self.pair_stats[pair] = {"labels_mean": labels_mean, "labels_std": labels_std}
|
||||
|
||||
# 根据 labels_std 调整 k_buy 和 k_sell
|
||||
if labels_std > 0.015:
|
||||
k_buy = 1.2
|
||||
k_sell = 1.5
|
||||
elif labels_std < 0.010:
|
||||
k_buy = 0.8
|
||||
k_sell = 1.0
|
||||
else:
|
||||
k_buy = 1.0
|
||||
k_sell = 1.2
|
||||
|
||||
if labels_mean > 0.015:
|
||||
k_sell += 0.5
|
||||
logger.info(f"[{pair}] labels_mean 较高({labels_mean:.4f}),增加 k_sell 到 {k_sell:.2f}")
|
||||
|
||||
# 计算阈值
|
||||
self.buy_threshold = labels_mean - k_buy * labels_std
|
||||
self.sell_threshold = labels_mean + k_sell * labels_std
|
||||
|
||||
# 边界保护
|
||||
self.buy_threshold = max(self.buy_threshold, -0.05)
|
||||
self.buy_threshold = min(self.buy_threshold, -0.005)
|
||||
self.sell_threshold = min(self.sell_threshold, 0.05)
|
||||
self.sell_threshold = max(self.sell_threshold, 0.005)
|
||||
|
||||
# 打印当前币对的详细日志
|
||||
logger.info(f"[{pair}] 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}")
|
||||
logger.info(f"[{pair}] 动态卖出阈值:{self.sell_threshold:.4f}")
|
||||
|
||||
# 打印所有币对的 labels_mean 和 labels_std 汇总(仅第一次)
|
||||
if not self.stats_logged:
|
||||
logger.info("===== 所有币对的 labels_mean 和 labels_std 汇总 =====")
|
||||
for p, stats in self.pair_stats.items():
|
||||
logger.info(f"[{p}] labels_mean:{stats['labels_mean']:.4f}, labels_std:{stats['labels_std']:.4f}")
|
||||
logger.info("==============================================")
|
||||
self.stats_logged = True # 标记已打印,避免重复
|
||||
# 存储统计信息
|
||||
self.pair_stats[pair] = {"labels_mean": labels_mean, "labels_std": labels_std}
|
||||
|
||||
# 计算动态阈值
|
||||
if labels_std > 0.015:
|
||||
k_buy = 1.2
|
||||
k_sell = 1.5
|
||||
elif labels_std < 0.010:
|
||||
k_buy = 0.8
|
||||
k_sell = 1.0
|
||||
else:
|
||||
self.buy_threshold = -0.015
|
||||
self.sell_threshold = 0.015
|
||||
logger.warning(f"[{pair}] 无法计算 labels_mean 和 labels_std,使用默认阈值 ±0.015")
|
||||
k_buy = 1.0
|
||||
k_sell = 1.2
|
||||
|
||||
if labels_mean > 0.015:
|
||||
k_sell += 0.5
|
||||
logger.info(f"[{pair}] labels_mean 较高({labels_mean:.4f}),增加 k_sell 到 {k_sell:.2f}")
|
||||
|
||||
self.buy_threshold = labels_mean - k_buy * labels_std
|
||||
self.sell_threshold = labels_mean + k_sell * labels_std
|
||||
|
||||
self.buy_threshold = max(self.buy_threshold, -0.05)
|
||||
self.buy_threshold = min(self.buy_threshold, -0.005)
|
||||
self.sell_threshold = min(self.sell_threshold, 0.05)
|
||||
self.sell_threshold = max(self.sell_threshold, 0.005)
|
||||
|
||||
logger.info(f"[{pair}] 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}")
|
||||
logger.info(f"[{pair}] 动态卖出阈值:{self.sell_threshold:.4f}")
|
||||
|
||||
if not self.stats_logged:
|
||||
logger.info("===== 所有币对的 labels_mean 和 labels_std 汇总 =====")
|
||||
for p, stats in self.pair_stats.items():
|
||||
logger.info(f"[{p}] labels_mean:{stats['labels_mean']:.4f}, labels_std:{stats['labels_std']:.4f}")
|
||||
logger.info("==============================================")
|
||||
self.stats_logged = True
|
||||
|
||||
logger.info(f"[{metadata['pair']}] 指标计算完成,列:{list(dataframe.columns)}")
|
||||
return dataframe
|
||||
|
||||
def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
入场逻辑:保持不变,基于动态阈值
|
||||
"""
|
||||
conditions = []
|
||||
|
||||
if "&-price_value_divergence" in df.columns:
|
||||
@ -264,9 +248,6 @@ class FreqaiPrimer(IStrategy):
|
||||
return df
|
||||
|
||||
def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
出场逻辑:优化以避免过早卖出
|
||||
"""
|
||||
conditions = []
|
||||
|
||||
if "&-price_value_divergence" in df.columns:
|
||||
@ -285,9 +266,6 @@ class FreqaiPrimer(IStrategy):
|
||||
def adjust_trade_position(self, trade: Trade, current_time: datetime,
|
||||
current_rate: float, current_profit: float,
|
||||
min_roi: Dict[float, float], max_profit: float):
|
||||
"""
|
||||
动态调整仓位:添加最小持仓时间和 Trailing Stop
|
||||
"""
|
||||
hold_time = (current_time - trade.open_date_utc).total_seconds() / 60
|
||||
|
||||
if hold_time < 15:
|
||||
@ -315,9 +293,6 @@ class FreqaiPrimer(IStrategy):
|
||||
|
||||
def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float,
|
||||
time_in_force: str, current_time: datetime, **kwargs) -> bool:
|
||||
"""
|
||||
交易确认:确保没有快速重复交易
|
||||
"""
|
||||
recent_trades = Trade.get_trades(
|
||||
pair=pair,
|
||||
is_open=False,
|
||||
@ -332,8 +307,5 @@ class FreqaiPrimer(IStrategy):
|
||||
def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float,
|
||||
rate: float, time_in_force: str, exit_reason: str,
|
||||
current_time: datetime, **kwargs) -> bool:
|
||||
"""
|
||||
交易退出确认:记录退出原因
|
||||
"""
|
||||
logger.info(f"[{pair}] 退出交易,原因:{exit_reason}, 利润:{trade.calc_profit_ratio(rate):.2%}")
|
||||
return True
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user