价值背离
This commit is contained in:
parent
eacad43b80
commit
71687b5539
245
chat/result13.md
Normal file
245
chat/result13.md
Normal file
@ -0,0 +1,245 @@
|
||||
> 请实现代码:
|
||||
> 1. **将 `&-divergence_score` 改为连续值形式**
|
||||
> 2. **移除任何离散值列(如 market_condition 编码)**
|
||||
> 3. **保持使用 `LightGBMMultiTargetRegressor` 模型**
|
||||
> 4. **在策略中使用这些连续值进行动态交易决策**
|
||||
|
||||
|
||||
Error: {
|
||||
exit = 56,
|
||||
message = 'post https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions - curl error exit_code=56 stderr={ "curl: (56) OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0" }',
|
||||
stderr = '{ "curl: (56) OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0" }'
|
||||
}
|
||||
|
||||
-------
|
||||
|
||||
- Datetime: 2025-05-31 08:40:04
|
||||
|
||||
- Model: _qwen3/qwen-plus-latest
|
||||
|
||||
- Selected files:
|
||||
- freqtrade/templates/freqaiprimer.py
|
||||
|
||||
> 中断了,请继续
|
||||
|
||||
|
||||
非常理解,我们继续完成你的需求。
|
||||
|
||||
---
|
||||
|
||||
## ✅ 你的目标
|
||||
|
||||
你希望:
|
||||
|
||||
1. **将 `&-divergence_score` 改为连续值形式**
|
||||
2. **移除任何离散值列(如 `&-market_condition`)**
|
||||
3. **保持使用 `LightGBMMultiTargetRegressor` 模型**
|
||||
4. **在策略中使用这些连续值进行动态交易决策**
|
||||
|
||||
---
|
||||
|
||||
## ✅ 实现步骤概览
|
||||
|
||||
我们将完成以下修改:
|
||||
|
||||
| 步骤 | 内容 |
|
||||
|------|------|
|
||||
| 🧮 Step 1 | 修改 `set_freqai_targets()`:生成连续背离评分 |
|
||||
| 🧹 Step 2 | 移除所有离散值列(如 `&-market_condition`) |
|
||||
| 📈 Step 3 | 配置 FreqAI 使用 `LightGBMMultiTargetRegressor` |
|
||||
| 🛠 Step 4 | 在 `populate_entry_trend()` 和 `populate_exit_trend()` 中使用连续背离信号 |
|
||||
|
||||
---
|
||||
|
||||
## 🧮 Step 1:修改 `set_freqai_targets()`,生成连续背离评分
|
||||
|
||||
```python
|
||||
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
|
||||
"""
|
||||
使用历史窗口预测未来趋势和波动率作为辅助信号,
|
||||
并新增一个连续值的背离评分列 &-divergence_score
|
||||
"""
|
||||
|
||||
label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
|
||||
|
||||
# 1. 趋势强度:使用过去 N 根 K 线的收益率判断当前趋势
|
||||
dataframe["&-trend_strength"] = dataframe["close"].pct_change(label_period)
|
||||
|
||||
# 2. 波动率预测:使用过去 N 根 K 线的价格变动绝对值
|
||||
dataframe["&-volatility_forecast"] = dataframe["close"].pct_change(label_period).abs()
|
||||
|
||||
# 3. ROI 目标:基于趋势强度缩放
|
||||
dataframe["&-roi_target"] = np.where(
|
||||
dataframe["&-trend_strength"] > 0,
|
||||
dataframe["&-trend_strength"] * 1.5,
|
||||
0.01 # 最小 ROI
|
||||
)
|
||||
|
||||
# 4. 动态止损目标:基于波动率缩放
|
||||
dataframe["&-stoploss_target"] = -dataframe["&-volatility_forecast"] * 1.2
|
||||
|
||||
# 5. 新增:连续背离评分(价格与趋势的偏离程度)
|
||||
dataframe["price_change"] = dataframe["close"].pct_change(label_period)
|
||||
dataframe["trend_change"] = dataframe["&-trend_strength"].pct_change(label_period)
|
||||
|
||||
# 连续背离评分:正值表示正向背离,负值表示负向背离
|
||||
dataframe["&-divergence_score"] = dataframe["price_change"] - dataframe["trend_change"]
|
||||
|
||||
return dataframe
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧹 Step 2:移除所有离散值列(如 `&-market_condition`)
|
||||
|
||||
如果你之前定义了 `&-market_condition` 或其他分类列,请从 `set_freqai_targets()` 和 `populate_indicators()` 中删除它们。
|
||||
|
||||
### ❌ 删除示例:
|
||||
```python
|
||||
# 删除以下代码(如果存在)
|
||||
if "bb_upperband-period" in dataframe.columns and "bb_lowerband-period" in dataframe.columns:
|
||||
dataframe["&-market_condition"] = np.select([
|
||||
(dataframe["close"] > dataframe["bb_upperband-period"]),
|
||||
(dataframe["close"] < dataframe["bb_lowerband-period"]),
|
||||
(dataframe["&-trend_strength"] > 0.03),
|
||||
], [
|
||||
"overbought",
|
||||
"oversold",
|
||||
"strong_up",
|
||||
], default="sideways")
|
||||
```
|
||||
|
||||
同时确保不再使用这些列做任何逻辑判断。
|
||||
|
||||
---
|
||||
|
||||
## 📈 Step 3:配置 FreqAI 使用 `LightGBMMultiTargetRegressor`
|
||||
|
||||
在你的策略类中设置:
|
||||
|
||||
```python
|
||||
freqai_info = {
|
||||
"model": "LightGBMMultiTargetRegressor", # ✅ 多目标回归模型
|
||||
"feature_parameters": {
|
||||
"include_timeframes": ["5m", "15m", "1h"],
|
||||
"label_period_candles": 24,
|
||||
"include_shifted_candles": 3,
|
||||
"principal_component_analysis": True, # 可选:启用 PCA 提升泛化能力
|
||||
},
|
||||
"data_split_parameters": {
|
||||
"test_size": 0.2,
|
||||
"shuffle": False,
|
||||
},
|
||||
"model_training_parameters": {
|
||||
"n_estimators": 200,
|
||||
"learning_rate": 0.05,
|
||||
"num_leaves": 31,
|
||||
"verbose": -1,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
这样 FreqAI 将使用 LightGBM 的多输出回归模型来同时预测多个连续目标列。
|
||||
|
||||
---
|
||||
|
||||
## 🛠 Step 4:在策略中使用连续背离信号进行交易决策
|
||||
|
||||
### ✅ 示例:在 `populate_entry_trend()` 中使用 `&-divergence_score`
|
||||
|
||||
```python
|
||||
def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
|
||||
conditions = []
|
||||
|
||||
if "&-divergence_score" in df.columns:
|
||||
|
||||
# 正向背离:价格下跌但趋势上升(背离评分为正值)
|
||||
buy_condition = df["&-divergence_score"] > 0.01
|
||||
|
||||
# 结合趋势强度过滤
|
||||
if "&-trend_strength" in df.columns:
|
||||
buy_condition &= df["&-trend_strength"] > 0.005
|
||||
|
||||
# 成交量过滤:成交量需大于 20 日均值的 1 倍
|
||||
df["vol_mean"] = df["volume"].rolling(20).mean()
|
||||
buy_condition &= (df["volume"] > df["vol_mean"] * 1)
|
||||
|
||||
conditions.append(buy_condition)
|
||||
|
||||
if len(conditions):
|
||||
df.loc[reduce(lambda x, y: x & y, conditions), 'enter_long'] = 1
|
||||
|
||||
return df
|
||||
```
|
||||
|
||||
### ✅ 示例:在 `populate_exit_trend()` 中使用 `&-divergence_score`
|
||||
|
||||
```python
|
||||
def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
|
||||
conditions = []
|
||||
|
||||
if "&-divergence_score" in df.columns:
|
||||
|
||||
# 负向背离:价格上涨但趋势下降(背离评分为负值)
|
||||
sell_condition = df["&-divergence_score"] < -0.01
|
||||
|
||||
# 结合趋势强度过滤
|
||||
if "&-trend_strength" in df.columns:
|
||||
sell_condition &= df["&-trend_strength"] < -0.005
|
||||
|
||||
conditions.append(sell_condition)
|
||||
|
||||
if len(conditions):
|
||||
df.loc[reduce(lambda x, y: x & y, conditions), 'exit_long'] = 1
|
||||
|
||||
return df
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 Step 5:更新 `plot_config`(可选)
|
||||
|
||||
你可以将背离评分加入绘图配置,方便可视化观察:
|
||||
|
||||
```python
|
||||
plot_config = {
|
||||
"main_plot": {},
|
||||
"subplots": {
|
||||
"Signals": {
|
||||
"enter_long": {"color": "green"},
|
||||
"exit_long": {"color": "red"}
|
||||
},
|
||||
"FreqAI Predictions": {
|
||||
"&-trend_strength": {"color": "blue"},
|
||||
"&-volatility_forecast": {"color": "orange"},
|
||||
"&-divergence_score": {"color": "purple"}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 总结改进点
|
||||
|
||||
| 改进项 | 描述 |
|
||||
|--------|------|
|
||||
| ✅ `&-divergence_score` 改为连续值 | 更适合回归模型学习 |
|
||||
| ✅ 移除所有离散值列 | 如 `&-market_condition` |
|
||||
| ✅ 使用 `LightGBMMultiTargetRegressor` | 同时预测多个连续目标 |
|
||||
| ✅ 在策略中使用背离评分进行交易决策 | 提高反转识别能力 |
|
||||
|
||||
---
|
||||
|
||||
## ✅ 下一步建议
|
||||
|
||||
你可以:
|
||||
|
||||
- 使用 `freqtrade plot-dataframe` 查看背离信号是否合理
|
||||
- 使用 `freqtrade backtesting` 测试新策略表现
|
||||
- 使用 `freqtrade hyperopt` 对背离阈值进行优化
|
||||
|
||||
---
|
||||
|
||||
如果你希望我帮你生成完整的策略文件,并提供对应的 `config.json` 示例,请告诉我 👇 我可以一步步帮你完成。
|
||||
|
||||
@ -68,8 +68,8 @@
|
||||
"freqaimodel": "LightGBMMultiTargetRegressor",
|
||||
"purge_old_models": 2,
|
||||
"identifier": "test58",
|
||||
"train_period_days": 30,
|
||||
"backtest_period_days": 7,
|
||||
"train_period_days": 7,
|
||||
"backtest_period_days": 1,
|
||||
"live_retrain_hours": 2,
|
||||
"outlier_detection": {
|
||||
"method": "IsolationForest",
|
||||
@ -80,7 +80,7 @@
|
||||
},
|
||||
"feature_parameters": {
|
||||
"include_timeframes": [
|
||||
"3m",
|
||||
"5m",
|
||||
"15m",
|
||||
"1h"
|
||||
],
|
||||
@ -89,11 +89,11 @@
|
||||
"SOL/USDT"
|
||||
],
|
||||
"outlier_protection_percentage": 0.1,
|
||||
"label_period_candles": 12,
|
||||
"label_period_candles": 24,
|
||||
"include_shifted_candles": 3,
|
||||
"DI_threshold": 0.7,
|
||||
"weight_factor": 0.9,
|
||||
"principal_component_analysis": false,
|
||||
"principal_component_analysis": true,
|
||||
"use_SVM_to_remove_outliers": true,
|
||||
"indicator_periods_candles": [
|
||||
10,
|
||||
@ -107,7 +107,7 @@
|
||||
"shuffle": false
|
||||
},
|
||||
"model_training_parameters": {
|
||||
"n_estimators": 100,
|
||||
"n_estimators": 200,
|
||||
"learning_rate": 0.05,
|
||||
"num_leaves": 31,
|
||||
"verbose": -1,
|
||||
|
||||
@ -8,18 +8,21 @@ from pandas import DataFrame
|
||||
from typing import Dict, Optional
|
||||
from technical import qtpylib
|
||||
from freqtrade.strategy import IStrategy
|
||||
from logging import getLogger
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class FreqaiPrimer(IStrategy):
|
||||
|
||||
class DivergenceRegressionStrategy(IStrategy):
|
||||
"""
|
||||
策略说明:
|
||||
- 所有交易信号由 FreqAI 动态预测
|
||||
- 不使用 Hyperopt 优化任何参数
|
||||
- 使用 FreqAI 提供的趋势和波动率信号进行交易决策
|
||||
- 所有交易信号基于 FreqAI 的动态预测
|
||||
- 使用多目标回归模型预测趋势强度、波动率、ROI、止损和背离评分
|
||||
- 入场/出场基于连续背离信号
|
||||
- 不使用 Hyperopt 优化参数
|
||||
- 不包含任何分类列(如 market_condition)
|
||||
"""
|
||||
# 👇 添加在这里
|
||||
|
||||
# 👇 币种特定参数(可选)
|
||||
PAIR_PARAMS = {
|
||||
"BTC/USDT": {"volatility_factor": 1.0, "min_stop": -0.005},
|
||||
"TON/USDT": {"volatility_factor": 1.3, "min_stop": -0.0035},
|
||||
@ -39,10 +42,10 @@ class FreqaiPrimer(IStrategy):
|
||||
}
|
||||
|
||||
use_custom_stoploss = True
|
||||
trailing_stop = True
|
||||
trailing_stop_positive = 0.005
|
||||
trailing_stop_positive_offset = 0.01
|
||||
trailing_only_offset_is_reached = True
|
||||
trailing_stop = False # 关闭 trailing_stop,避免干扰背离信号
|
||||
use_dynamic_roi = True
|
||||
position_adjuster = True
|
||||
|
||||
plot_config = {
|
||||
"main_plot": {},
|
||||
"subplots": {
|
||||
@ -51,19 +54,20 @@ class FreqaiPrimer(IStrategy):
|
||||
"exit_long": {"color": "red"}
|
||||
},
|
||||
"FreqAI Predictions": {
|
||||
"&-buy_signal": {"color": "blue"},
|
||||
"&-sell_signal": {"color": "orange"},
|
||||
"&-volatility_forecast": {"color": "purple"}
|
||||
"&-trend_strength": {"color": "blue"},
|
||||
"&-volatility_forecast": {"color": "orange"},
|
||||
"&-divergence_score": {"color": "purple"}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
freqai_info = {
|
||||
"model": "LightGBMClassifier",
|
||||
"model": "LightGBMMultiTargetRegressor",
|
||||
"feature_parameters": {
|
||||
"include_timeframes": ["5m", "15m", "1h"],
|
||||
"label_period_candles": 24,
|
||||
"include_shifted_candles": 3,
|
||||
"principal_component_analysis": True,
|
||||
},
|
||||
"data_split_parameters": {
|
||||
"test_size": 0.2,
|
||||
@ -76,12 +80,15 @@ class FreqaiPrimer(IStrategy):
|
||||
"verbose": -1,
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self, config: dict, *args, **kwargs):
|
||||
super().__init__(config, *args, **kwargs)
|
||||
|
||||
# 设置日志级别为 DEBUG
|
||||
logger.setLevel(logging.DEBUG)
|
||||
logger.debug("✅ 策略已初始化,日志级别设置为 DEBUG")
|
||||
|
||||
# 👇 特征工程函数
|
||||
def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, metadata: dict, **kwargs) -> DataFrame:
|
||||
# 保留原有指标
|
||||
dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period)
|
||||
@ -93,7 +100,7 @@ class FreqaiPrimer(IStrategy):
|
||||
dataframe["bb_lowerband-period"] = lowerband
|
||||
dataframe["bb_upperband-period"] = upperband
|
||||
dataframe["bb_middleband-period"] = middleband
|
||||
dataframe["%-bb_width-period"] = (dataframe["bb_upperband-period"] - dataframe["bb_lowerband-period"]) / dataframe["bb_middleband-period"]
|
||||
dataframe["%-bb_width-period"] = (dataframe["bb_upperband-period"] - dataframe["bb_middleband-period"]) / dataframe["bb_middleband-period"]
|
||||
dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period)
|
||||
|
||||
# 添加策略 B 的指标
|
||||
@ -103,79 +110,53 @@ class FreqaiPrimer(IStrategy):
|
||||
dataframe["%-relative_volume-period"] = dataframe["volume"] / dataframe["volume"].rolling(period).mean() # 相对成交量
|
||||
dataframe["%-close-bb_lower-period"] = dataframe["close"] / dataframe["bb_lowerband-period"] # 收盘价/布林带下轨
|
||||
|
||||
# 新增:与背离相关的衍生特征
|
||||
dataframe["%-price_trend_diff-period"] = dataframe["close"] - dataframe["%-ema-period"] # 价格与趋势偏离
|
||||
dataframe["%-roc_mfi_ratio-period"] = dataframe["%-roc-period"] / (dataframe["%-mfi-period"].replace(0, 1)) # ROC/MFI 比率
|
||||
|
||||
# 数据清理
|
||||
columns_to_clean = [
|
||||
"%-rsi-period", "%-mfi-period", "%-sma-period", "%-ema-period", "%-adx-period",
|
||||
"bb_lowerband-period", "bb_middleband-period", "bb_upperband-period",
|
||||
"%-bb_width-period", "%-roc-period", "%-relative_volume-period", "%-close-bb_lower-period", "%-tema-period"
|
||||
"%-bb_width-period", "%-roc-period", "%-relative_volume-period", "%-close-bb_lower-period", "%-tema-period",
|
||||
"%-price_trend_diff-period", "%-roc_mfi_ratio-period"
|
||||
]
|
||||
for col in columns_to_clean:
|
||||
dataframe[col] = dataframe[col].replace([np.inf, -np.inf], 0).ffill().fillna(0)
|
||||
|
||||
return dataframe
|
||||
|
||||
# 👇 定义目标列(全部为连续值)
|
||||
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
|
||||
"""
|
||||
使用历史窗口预测未来趋势和波动率作为辅助信号,
|
||||
避免使用任何未来数据(如 shift(-N))
|
||||
"""
|
||||
|
||||
label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
|
||||
|
||||
# 1. 趋势强度:使用过去 N 根 K 线的收益率判断当前趋势
|
||||
# 1. 趋势强度
|
||||
dataframe["&-trend_strength"] = dataframe["close"].pct_change(label_period)
|
||||
|
||||
# 2. 波动率预测:使用过去 N 根 K 线的价格变动绝对值
|
||||
# 2. 波动率预测
|
||||
dataframe["&-volatility_forecast"] = dataframe["close"].pct_change(label_period).abs()
|
||||
|
||||
# 3. 动态 ROI 目标:基于趋势强度缩放
|
||||
# 3. ROI 目标
|
||||
dataframe["&-roi_target"] = np.where(
|
||||
dataframe["&-trend_strength"] > 0,
|
||||
dataframe["&-trend_strength"] * 1.5,
|
||||
0.01 # 最小 ROI
|
||||
0.01
|
||||
)
|
||||
|
||||
# 4. 动态止损目标:基于波动率缩放
|
||||
# 4. 动态止损目标
|
||||
dataframe["&-stoploss_target"] = -dataframe["&-volatility_forecast"] * 1.2
|
||||
|
||||
# 👇 新增:z-score 标准化模型输出
|
||||
if self.freqai and hasattr(self.freqai, "data"):
|
||||
labels_mean = self.freqai.data.labels_mean
|
||||
labels_std = self.freqai.data.labels_std
|
||||
|
||||
mean_roi = labels_mean.get("&-roi_target", 0.01)
|
||||
std_roi = labels_std.get("&-roi_target", 0.01)
|
||||
mean_stop = labels_mean.get("&-stoploss_target", -0.01)
|
||||
std_stop = labels_std.get("&-stoploss_target", 0.01)
|
||||
|
||||
# z-score 标准化
|
||||
dataframe["&-roi_target_z"] = (dataframe["&-roi_target"] - mean_roi) / std_roi
|
||||
dataframe["&-stoploss_target_z"] = (dataframe["&-stoploss_target"] - mean_stop) / std_stop
|
||||
|
||||
# 市场状态识别:判断当前是震荡、趋势、超买还是超卖
|
||||
if "bb_upperband-period" in dataframe.columns and "bb_lowerband-period" in dataframe.columns:
|
||||
dataframe["&-market_condition"] = np.select([
|
||||
(dataframe["close"] > dataframe["bb_upperband-period"]),
|
||||
(dataframe["close"] < dataframe["bb_lowerband-period"]),
|
||||
(dataframe["&-trend_strength"] > 0.03),
|
||||
], [
|
||||
"overbought",
|
||||
"oversold",
|
||||
"strong_up",
|
||||
], default="sideways")
|
||||
|
||||
# 买入信号(必须存在)
|
||||
dataframe["&-buy_signal"] = np.where(dataframe["&-trend_strength"] > 0.01, 1, 0)
|
||||
|
||||
# 卖出信号(必须存在)
|
||||
dataframe["&-sell_signal"] = np.where(dataframe["&-trend_strength"] < -0.01, 1, 0)
|
||||
# 5. 连续背离评分
|
||||
dataframe["price_change"] = dataframe["close"].pct_change(label_period)
|
||||
dataframe["trend_change"] = dataframe["&-trend_strength"].pct_change(label_period)
|
||||
dataframe["&-divergence_score"] = dataframe["price_change"] - dataframe["trend_change"]
|
||||
|
||||
return dataframe
|
||||
|
||||
# 👇 缓存 mean/std 供后续使用
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe = self.freqai.start(dataframe, metadata, self)
|
||||
|
||||
# 缓存 mean/std 供后续使用
|
||||
if self.freqai and hasattr(self.freqai, "data"):
|
||||
labels_mean = self.freqai.data.labels_mean
|
||||
labels_std = self.freqai.data.labels_std
|
||||
@ -186,120 +167,82 @@ class FreqaiPrimer(IStrategy):
|
||||
dataframe["mean_volatility"] = labels_mean.get("&-volatility_forecast", 0.0021)
|
||||
dataframe["std_volatility"] = labels_std.get("&-volatility_forecast", 0.0022)
|
||||
|
||||
dataframe["mean_roi"] = labels_mean.get("&-roi_target", 0.0065)
|
||||
dataframe["std_roi"] = labels_std.get("&-roi_target", 0.0041)
|
||||
|
||||
dataframe["mean_stop"] = labels_mean.get("&-stoploss_target", -0.0026)
|
||||
dataframe["std_stop"] = labels_std.get("&-stoploss_target", 0.0027)
|
||||
dataframe["mean_divergence"] = labels_mean.get("&-divergence_score", 0.0)
|
||||
dataframe["std_divergence"] = labels_std.get("&-divergence_score", 1.0)
|
||||
|
||||
return dataframe
|
||||
|
||||
# 👇 使用背离信号作为入场条件
|
||||
def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
基于 FreqAI 的预测结果生成入场信号。
|
||||
使用滚动分位数 + Z-score + 市场状态过滤,提高信号质量。
|
||||
"""
|
||||
|
||||
conditions = []
|
||||
|
||||
# 确保 &-buy_signal 存在
|
||||
if "&-buy_signal" in df.columns:
|
||||
if "&-divergence_score" in df.columns:
|
||||
|
||||
# 使用过去 20 根 K 线中 buy_signal 的 80 分位作为动态阈值
|
||||
df["buy_threshold"] = df["&-buy_signal"].rolling(20).quantile(0.8)
|
||||
buy_condition = df["&-buy_signal"] >= df["buy_threshold"]
|
||||
buy_condition = df["&-divergence_score"] > 0.01
|
||||
|
||||
# 使用 Z-score 判断趋势显著性(仅保留趋势较强的时间点)
|
||||
if "mean_trend" in df.columns and "std_trend" in df.columns:
|
||||
mean_trend = df["mean_trend"].iloc[-1]
|
||||
std_trend = df["std_trend"].iloc[-1]
|
||||
if "&-trend_strength" in df.columns:
|
||||
buy_condition &= df["&-trend_strength"] > 0.005
|
||||
|
||||
z_score_trend = (df["&-trend_strength"] - mean_trend) / std_trend
|
||||
buy_condition &= (z_score_trend > 1) # 只保留趋势显著的信号
|
||||
|
||||
# 市场状态过滤:震荡市减少交易频率
|
||||
if "&-market_condition" in df.columns:
|
||||
buy_condition &= ~(
|
||||
(df["&-market_condition"] == "sideways") &
|
||||
(df["&-buy_signal"] < df["buy_threshold"] * 1.2)
|
||||
)
|
||||
|
||||
# 在超买市场中进一步过滤买入信号
|
||||
buy_condition &= ~(df["&-market_condition"] == "overbought")
|
||||
|
||||
# EMA 趋势过滤:只在价格高于 EMA50 时开仓
|
||||
df["ema50"] = ta.EMA(df, timeperiod=50)
|
||||
buy_condition &= (df["close"] > df["ema50"])
|
||||
|
||||
# 成交量过滤:成交量需大于 20 日均值的 1 倍
|
||||
df["vol_mean"] = df["volume"].rolling(20).mean()
|
||||
buy_condition &= (df["volume"] > df["vol_mean"] * 1)
|
||||
|
||||
conditions.append(buy_condition)
|
||||
else:
|
||||
self.logger.warning("⚠️ &-buy_signal 列缺失,跳过该条件")
|
||||
|
||||
# 如果有多个条件,使用逻辑与合并
|
||||
if len(conditions):
|
||||
df.loc[reduce(lambda x, y: x & y, conditions), 'enter_long'] = 1
|
||||
|
||||
return df
|
||||
|
||||
# 👇 使用背离信号作为出场条件
|
||||
def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
|
||||
# Compute sell_signal_high outside the conditions list
|
||||
|
||||
pair = metadata['pair']
|
||||
trade = Trade.get_trades([("pair", pair)]).first()
|
||||
conditions = []
|
||||
|
||||
if trade and trade.is_open:
|
||||
open_candle_index = df.index.get_loc(trade.open_date.replace(tzinfo=None))
|
||||
current_index = len(df) - 1
|
||||
holding_period = current_index - open_candle_index
|
||||
if "&-divergence_score" in df.columns:
|
||||
|
||||
if holding_period < 5:
|
||||
df.loc[df.index[-1], 'exit_long'] = 0
|
||||
return df
|
||||
df["sell_signal_high"] = (df["&-sell_signal"] > 0.3).rolling(3).sum() >= 2
|
||||
sell_condition = df["&-divergence_score"] < -0.01
|
||||
|
||||
conditions = [
|
||||
df["sell_signal_high"] # Append the condition, not an assignment
|
||||
]
|
||||
if "&-trend_strength" in df.columns:
|
||||
sell_condition &= df["&-trend_strength"] < -0.005
|
||||
|
||||
if "&-market_condition" in df.columns:
|
||||
# 在超卖市场中减少卖出信号
|
||||
conditions.append(df["&-market_condition"] != "oversold")
|
||||
conditions.append(sell_condition)
|
||||
|
||||
# 在超买市场中增强卖出信号
|
||||
conditions.append(~((df["&-market_condition"] == "overbought") & (df["&-sell_signal"] < 0.7)))
|
||||
if len(conditions):
|
||||
df.loc[reduce(lambda x, y: x & y, conditions), 'exit_long'] = 1
|
||||
|
||||
df.loc[reduce(lambda x, y: x & y, conditions), 'exit_long'] = 1
|
||||
return df
|
||||
|
||||
# 👇 自定义止损(基于波动率缩放)
|
||||
def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime,
|
||||
current_rate: float, current_profit: float, **kwargs) -> float:
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1]
|
||||
|
||||
volatility = last_candle.get("&-volatility_forecast", 0.0021)
|
||||
dynamic_stoploss = -volatility * 2 # 设置为波动率的两倍
|
||||
dynamic_stoploss = max(dynamic_stoploss, -0.01) # 最大不超过 1%
|
||||
|
||||
return dynamic_stoploss
|
||||
|
||||
# 👇 动态调整持仓止盈
|
||||
def adjust_trade_position(self, trade: Trade, current_time: datetime,
|
||||
current_rate: float, current_profit: float,
|
||||
min_roi: Dict[float, float], max_profit: float) -> Optional[Dict[float, float]]:
|
||||
"""
|
||||
动态调整持仓逻辑,基于 FreqAI 预测的 ROI 目标。
|
||||
根据 Z-score 判断趋势强度,动态设置止盈时间窗口。
|
||||
"""
|
||||
current_rate: float, current_profit: float,
|
||||
min_roi: Dict[float, float], max_profit: float) -> Optional[Dict[float, float]]:
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1]
|
||||
|
||||
# 获取预测的 ROI 目标 和 统计信息
|
||||
roi_target = last_candle.get("&-roi_target", 0.0065)
|
||||
mean_roi = last_candle.get("mean_roi", 0.0065)
|
||||
std_roi = last_candle.get("std_roi", 0.0041)
|
||||
|
||||
# 计算 Z-score
|
||||
z_score_roi = (roi_target - mean_roi) / std_roi if std_roi != 0 else 0
|
||||
|
||||
# 根据 Z-score 设置不同的 ROI 表
|
||||
if z_score_roi > 1:
|
||||
return {
|
||||
"0": roi_target * 1.2,
|
||||
"10": roi_target * 0.9,
|
||||
"30": roi_target * 0.6,
|
||||
"60": roi_target * 0.3,
|
||||
"120": 0.01
|
||||
"30": roi_target * 0.9,
|
||||
"60": roi_target * 0.6,
|
||||
"120": roi_target * 0.3,
|
||||
"180": 0.01
|
||||
}
|
||||
elif z_score_roi > 0:
|
||||
return {
|
||||
@ -315,43 +258,3 @@ class FreqaiPrimer(IStrategy):
|
||||
"180": 0.005
|
||||
}
|
||||
|
||||
def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime,
|
||||
current_rate: float, current_profit: float, **kwargs) -> float:
|
||||
"""
|
||||
动态止损回调函数,基于 FreqAI 预测的 &-stoploss_target 值。
|
||||
"""
|
||||
|
||||
# 获取当前币种的 dataframe
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1]
|
||||
|
||||
# 获取预测的止损目标(使用 z-score 版本)
|
||||
stoploss_z = last_candle.get("&-stoploss_target_z", -1.0) # 默认值为 -1.0(一个标准差)
|
||||
|
||||
# 获取模型统计信息用于自适应判断
|
||||
mean_stop = -0.01
|
||||
std_stop = 0.01
|
||||
|
||||
if self.freqai and hasattr(self.freqai, "data"):
|
||||
labels_mean = self.freqai.data.labels_mean
|
||||
labels_std = self.freqai.data.labels_std
|
||||
|
||||
mean_stop = labels_mean.get("&-stoploss_target", mean_stop)
|
||||
std_stop = labels_std.get("&-stoploss_target", std_stop)
|
||||
|
||||
# 获取币种特定参数
|
||||
params = self.PAIR_PARAMS.get(pair, {"volatility_factor": 1.0, "min_stop": -0.005})
|
||||
volatility_factor = params["volatility_factor"]
|
||||
min_stop = params["min_stop"]
|
||||
|
||||
# 动态止损下限 = 平均值 - volatility_factor * 标准差
|
||||
dynamic_min_stop = min(min_stop, mean_stop - volatility_factor * std_stop)
|
||||
|
||||
# 如果 z-score < -1,则说明当前止损偏移较大,适当放宽
|
||||
if stoploss_z < -1.0:
|
||||
dynamic_min_stop = min(dynamic_min_stop * 1.2, -0.003)
|
||||
|
||||
# 最终止损值 = 模型建议值 和 动态下限中的较小者
|
||||
dynamic_stoploss = dynamic_min_stop
|
||||
|
||||
return dynamic_stoploss
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user