修复了很多问题, 需要进一步验证,所以单开一个分支

This commit is contained in:
zhangkun9038@dingtalk.com 2025-12-27 03:03:20 +08:00
parent 418559b51d
commit eba5040214
2 changed files with 201 additions and 37 deletions

162
doc/问题.md Normal file
View File

@ -0,0 +1,162 @@
好的,我来对 FreqAI 相关逻辑和变量进行全面排查。
现在我整理出 FreqAI 相关逻辑的全面排查结果:
---
## **FreqAI 逻辑排查报告**
### **问题 1pandas 废弃方法(第 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` 永远不会匹配到(前缀错误)**。
---
### **问题 4entry_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 相关逻辑排查报告**
### **🔴 问题1pandas `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 参数,但代码中**缺少这两个参数定义**
---
### **🟡 问题3FreqAI 列名备选逻辑可能永远不匹配**
**位置:** 第 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`
---
### **🟡 问题4trailing_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 初始化时行为不确定
---
### **🟢 问题5custom_entry_price / custom_exit_price 方法缺失**
**位置:** 不存在
**问题:**
- 没有定义 `custom_entry_price``custom_exit_price` 方法
- 当前入场价格是在 `populate_entry_trend` 中通过设置 `enter_price` 列实现的(第 666 行)
- 这种方式**仅在回测中生效,实盘中不生效**
- 根据记忆,之前已经发现 "live模式下价格调整策略未生效" 的问题
---
### **🟢 问题6freqai_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

View File

@ -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