diff --git a/doc/问题.md b/doc/问题.md new file mode 100644 index 00000000..b9557770 --- /dev/null +++ b/doc/问题.md @@ -0,0 +1,162 @@ +好的,我来对 FreqAI 相关逻辑和变量进行全面排查。 +现在我整理出 FreqAI 相关逻辑的全面排查结果: + +--- + +## **FreqAI 逻辑排查报告** + +### **问题 1:pandas 废弃方法(第 333 行)** ⚠️ + +```python +# 当前代码(废弃) +dataframe["%-raw_price"] = dataframe["close"].fillna(method="ffill") + +# 应改为 +dataframe["%-raw_price"] = dataframe["close"].ffill() +``` + +--- + +### **问题 2:价格调整硬编码(第 666、830 行)** ⚠️ + +价格调整使用硬编码 `0.9833`(1.67%),**没有使用 hyperopt 可优化参数**: + +```python +# 第 666 行 - populate_entry_trend +dataframe.loc[final_condition_updated, 'enter_price'] = dataframe.loc[final_condition_updated, 'close'] * 0.9833 + +# 第 830 行 - confirm_trade_entry +adjusted_entry_price = rate * 0.9833 +``` + +**之前讨论过但未完成**:缺少 `entry_price_discount` 和 `exit_price_premium` 的 hyperopt 参数定义。 + +--- + +### **问题 3:`future_volatility` 列名不一致(第 912-913 行)** ⚠️ + +```python +# 训练时设置的列名是: +dataframe["&s-future_volatility"] = ... # 第 381 行 + +# 读取时的列名不一致: +if '&s-future_volatility' in df.columns: # ✅ 正确 + future_vol_signal = float(last_row['&s-future_volatility']) +elif '&-future_volatility' in df.columns: # ❌ 错误前缀,应该是 &s- + future_vol_signal = float(last_row['&-future_volatility']) +``` + +**第 913 行的 `&-future_volatility` 永远不会匹配到(前缀错误)**。 + +--- + +### **问题 4:entry_signal 列名备选项不一致(第 800-803 行)** + +```python +# 训练时设置: +dataframe["&s-entry_signal"] = ... # 第 357 行 + +# 读取时备选列名不规范: +if '&s-entry_signal' in df.columns: # ✅ 正确 +elif '&-entry_signal_prob' in df.columns: # ❓ 不规范 +elif '&-s-entry_signal_prob' in df.columns: # ❓ 不规范 +``` + +建议统一使用 FreqAI 标准前缀 `&s-`。 + +--- + +### **问题 5:止损参数与之前讨论的 72 分钟窗口不匹配(第 27 行)** + +```python +stoploss = -0.15 # 固定止损 -15% +``` + +**之前讨论过**:72 分钟预测窗口,目标涨幅 1-2%,但止损 -15% 太宽松(风险收益比约 10:1)。 + +建 +现在汇总发现的所有问题: + +--- + +## **FreqAI 相关逻辑排查报告** + +### **🔴 问题1:pandas `fillna(method="ffill")` 废弃警告** +**位置:** 第 333 行 +```python +dataframe["%-raw_price"] = dataframe["close"].fillna(method="ffill") +``` +**问题:** `fillna(method="ffill")` 在 pandas 2.0+ 中已废弃,会抛出 FutureWarning + +--- + +### **🔴 问题2:入场价格硬编码,未使用 hyperopt 参数** +**位置:** 第 666、828-830 行 +```python +# 第 666 行 - populate_entry_trend +dataframe.loc[final_condition_updated, 'enter_price'] = dataframe.loc[final_condition_updated, 'close'] * 0.9833 + +# 第 828-830 行 - confirm_trade_entry +price_discount_percent = 1.67 +adjusted_entry_price = rate * 0.9833 +``` +**问题:** +- 入场价格下调 1.67% 是硬编码的,无法通过 hyperopt 优化 +- 之前记忆中提到需要定义 `entry_price_discount` 和 `exit_price_premium` 为 hyperopt 参数,但代码中**缺少这两个参数定义** + +--- + +### **🟡 问题3:FreqAI 列名备选逻辑可能永远不匹配** +**位置:** 第 800-803、869-871、912-913 行 +```python +# entry_signal 备选列名 +elif '&-entry_signal_prob' in df.columns: # 这个格式不正确 +elif '&-s-entry_signal_prob' in df.columns: # 这个格式也不正确 + +# exit_signal 备选列名 +elif '&-s-exit_signal_prob' in df.columns: # 格式不正确 + +# future_volatility 备选列名 +elif '&-future_volatility' in df.columns: # 格式不正确 +``` +**问题:** 这些备选列名格式与 FreqAI 实际输出的格式不匹配,会永远不被使用。FreqAI 输出的列名是 `&s-xxx`(训练目标)而不是 `&-xxx-prob` + +--- + +### **🟡 问题4:trailing_stop 参数配置不完整** +**位置:** 第 27-29 行 +```python +stoploss = -0.15 # 固定止损 -15% +trailing_stop = True +trailing_stop_positive_offset = 0.005 +# 缺少 trailing_stop_positive 定义! +``` +**问题:** +- 定义了 `trailing_stop = True` 和 `trailing_stop_positive_offset` +- 但 `trailing_stop_positive` 值只在 `@property` 中动态计算(第 220-229 行) +- 如果 `_dataframe_cache` 为 None,会使用 `_trailing_stop_positive_default = 0.004` +- 但类级别没有明确定义 `trailing_stop_positive = xxx`,可能导致 freqtrade 初始化时行为不确定 + +--- + +### **🟢 问题5:custom_entry_price / custom_exit_price 方法缺失** +**位置:** 不存在 +**问题:** +- 没有定义 `custom_entry_price` 和 `custom_exit_price` 方法 +- 当前入场价格是在 `populate_entry_trend` 中通过设置 `enter_price` 列实现的(第 666 行) +- 这种方式**仅在回测中生效,实盘中不生效** +- 根据记忆,之前已经发现 "live模式下价格调整策略未生效" 的问题 + +--- + +### **🟢 问题6:freqai_entry_up_percent / freqai_exit_down_percent 范围不一致** +**位置:** 第 271-274 行 vs 之前的讨论 +```python +freqai_entry_up_percent = DecimalParameter(0.3, 2.0, ...) +freqai_exit_down_percent = DecimalParameter(0.3, 2.0, ...) +``` +**问题:** 之前讨论过将范围改为 0.5-2.0% 匹配 72 分钟预测窗口,但当前代码仍是 0.3-2.0% + +--- + +需要我逐个修复这些问题吗w \ No newline at end of file diff --git a/freqtrade/templates/freqaiprimer.py b/freqtrade/templates/freqaiprimer.py index cb867c2e..d6a2944f 100644 --- a/freqtrade/templates/freqaiprimer.py +++ b/freqtrade/templates/freqaiprimer.py @@ -2,6 +2,7 @@ import warnings warnings.filterwarnings("ignore", category=UserWarning, module="pandas_ta") import logging +from typing import Optional from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter from pandas import DataFrame import pandas as pd @@ -24,9 +25,11 @@ class FreqaiPrimer(IStrategy): # FreqAI 要求 process_only_new_candles = True - stoploss = -0.15 # 固定止损 -15% (大幅放宽止损以承受更大波动) + stoploss = -0.15 # 固定止损 -15% trailing_stop = True - trailing_stop_positive_offset = 0.005 # 追踪止损偏移量 0.5% (更容易触发跟踪止盈) + trailing_stop_positive = 0.004 # 跟踪止盈回调 0.4% + trailing_stop_positive_offset = 0.005 # 追踪止损偏移量 0.5% + trailing_only_offset_is_reached = True # 只有达到 offset 后才启用跟踪止盈 # 用于跟踪市场状态的数据框缓存 _dataframe_cache = None @@ -273,6 +276,10 @@ class FreqaiPrimer(IStrategy): # FreqAI 标签定义:exit_signal 的洛底下跌幅度(%) freqai_exit_down_percent = DecimalParameter(0.3, 2.0, decimals=2, default=0.5, optimize=True, load=True, space='buy') + # 入场/出场价格调整参数(实盘限价单) + entry_price_discount = DecimalParameter(0.005, 0.025, decimals=3, default=0.0167, optimize=False, load=True, space='buy') # 入场下调比例,默认 1.67% + exit_price_premium = DecimalParameter(0.005, 0.025, decimals=3, default=0.0167, optimize=False, load=True, space='sell') # 出场上调比例,默认 1.67% + # 定义可优化参数 # 初始入场金额: 75.00 @@ -330,7 +337,7 @@ class FreqaiPrimer(IStrategy): """FreqAI 基础特征。""" dataframe["%-pct_change"] = dataframe["close"].pct_change().fillna(0) dataframe["%-raw_volume"] = dataframe["volume"].fillna(0) - dataframe["%-raw_price"] = dataframe["close"].fillna(method="ffill") + dataframe["%-raw_price"] = dataframe["close"].ffill() return dataframe def feature_engineering_standard(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame: @@ -661,9 +668,10 @@ class FreqaiPrimer(IStrategy): # 设置入场信号 dataframe.loc[final_condition, 'enter_long'] = 1 - # 设置入场价格:下调1.67%(使用乘法避免除零风险) + # 设置入场价格:使用 hyperopt 参数调整下调比例 final_condition_updated = dataframe['enter_long'] == 1 - dataframe.loc[final_condition_updated, 'enter_price'] = dataframe.loc[final_condition_updated, 'close'] * 0.9833 + discount_multiplier = 1.0 - self.entry_price_discount.value + dataframe.loc[final_condition_updated, 'enter_price'] = dataframe.loc[final_condition_updated, 'close'] * discount_multiplier # 增强调试信息 #self.log_info(f"[{metadata['pair']}] 入场条件检查:") @@ -794,20 +802,9 @@ class FreqaiPrimer(IStrategy): last_row = df.iloc[-1] entry_prob = None - # 优先使用 FreqAI 的 entry_signal 预测列 + # FreqAI 预测列名为 &s-entry_signal if '&s-entry_signal' in df.columns: entry_prob = float(last_row['&s-entry_signal']) - elif '&-entry_signal_prob' in df.columns: - entry_prob = float(last_row['&-entry_signal_prob']) - elif '&-s-entry_signal_prob' in df.columns: - entry_prob = float(last_row['&-s-entry_signal_prob']) - elif '&-entry_signal' in df.columns: - val = last_row['&-entry_signal'] - if isinstance(val, (int, float)): - entry_prob = float(val) - else: - # 文本标签时,简单映射为 0/1 - entry_prob = 1.0 if str(val).lower() in ['entry', 'buy', '1'] else 0.0 if entry_prob is not None: # 确保概率在 [0, 1] 范围内(分类器输出可能有浮点误差) @@ -824,11 +821,10 @@ class FreqaiPrimer(IStrategy): # 如果允许交易,更新最后一次入场时间并输出价格信息 if allow_trade: self._last_entry_time[pair] = current_time - # 计算实际入场价格下调比例(1.67%) - # rate 是当前市场价格,enter_price = rate * 0.9833 - price_discount_percent = 1.67 - adjusted_entry_price = rate * 0.9833 - self.log_info(f"[{pair}] 允许入场 - 市场价: {rate:.8f}, 调整后入场价: {adjusted_entry_price:.8f}, 下调: {price_discount_percent}%") + # 使用 hyperopt 参数计算实际入场价格 + discount_multiplier = 1.0 - self.entry_price_discount.value + adjusted_entry_price = rate * discount_multiplier + self.log_info(f"[{pair}] 允许入场 - 市场价: {rate:.8f}, 调整后入场价: {adjusted_entry_price:.8f}, 下调: {self.entry_price_discount.value:.2%}") # 如果没有阻止因素,允许交易 return allow_trade @@ -863,20 +859,9 @@ class FreqaiPrimer(IStrategy): last_row = df.iloc[-1] exit_prob = None - # 优先使用 FreqAI 的 exit_signal 预测列 + # FreqAI 预测列名为 &s-exit_signal if '&s-exit_signal' in df.columns: exit_prob = float(last_row['&s-exit_signal']) - elif '&-exit_signal_prob' in df.columns: - exit_prob = float(last_row['&-exit_signal_prob']) - elif '&-s-exit_signal_prob' in df.columns: - exit_prob = float(last_row['&-s-exit_signal_prob']) - elif '&-exit_signal' in df.columns: - val = last_row['&-exit_signal'] - if isinstance(val, (int, float)): - exit_prob = float(val) - else: - # 文本标签时,简单映射为 0/1 - exit_prob = 1.0 if str(val).lower() in ['exit', 'sell', '1'] else 0.0 if exit_prob is not None: # 确保概率在 [0, 1] 范围内(分类器输出可能有浮点误差) @@ -905,12 +890,10 @@ class FreqaiPrimer(IStrategy): if current_profit <= 0.02: dynamic_threshold *= 0.8 - # 新增:读取 AI 预测的未来波动率信号(极端化方案) + # 读取 AI 预测的未来波动率信号 future_vol_signal = None if '&s-future_volatility' in df.columns: future_vol_signal = float(last_row['&s-future_volatility']) - elif '&-future_volatility' in df.columns: - future_vol_signal = float(last_row['&-future_volatility']) # 极端化逻辑:根据 AI 预测的未来波动率直接接管部分出场决策 if future_vol_signal is not None and exit_reason == 'exit_signal': @@ -1102,3 +1085,22 @@ class FreqaiPrimer(IStrategy): return adjusted_stake + def custom_entry_price(self, pair: str, trade: Optional['Trade'], current_time: datetime, + proposed_rate: float, entry_tag: Optional[str], side: str, + **kwargs) -> float: + """ + 实盘入场价格调整:使用 hyperopt 参数动态调整降价百分比 + """ + discount_multiplier = 1.0 - self.entry_price_discount.value + adjusted_price = proposed_rate * discount_multiplier + return adjusted_price + + def custom_exit_price(self, pair: str, trade: 'Trade', current_time: datetime, + proposed_rate: float, exit_tag: Optional[str], side: str, + **kwargs) -> float: + """ + 实盘出场价格调整:使用 hyperopt 参数动态调整加价百分比 + """ + premium_multiplier = 1.0 + self.exit_price_premium.value + adjusted_price = proposed_rate * premium_multiplier + return adjusted_price