params file removed, and other update

This commit is contained in:
zhangkun9038@dingtalk.com 2025-05-30 12:13:08 +00:00
parent e2b7fe5dcf
commit 09d40a2cf7
2 changed files with 79 additions and 113 deletions

View File

@ -1,31 +0,0 @@
{
"strategy_name": "FreqaiPrimer",
"params": {
"max_open_trades": {
"max_open_trades": 4
},
"buy": {
"buy_rsi": 50.0
},
"sell": {
"sell_rsi": 90.0
},
"protection": {},
"roi": {
"0": 0.07,
"6": 0.022,
"12": 0.01,
"21": 0
},
"stoploss": {
"stoploss": -0.075
},
"trailing": {
"trailing_stop": true,
"trailing_stop_positive": 0.01,
"trailing_stop_positive_offset": 0.015
}
},
"ft_stratparam_v": 1,
"export_time": "2025-05-27 08:29:12.681268+00:00"
}

View File

@ -5,9 +5,10 @@ from functools import reduce
from freqtrade.persistence import Trade
import talib.abstract as ta
from pandas import DataFrame
from typing import Dict
from typing import Dict, Optional
from technical import qtpylib
from freqtrade.strategy import IStrategy
from logging import getLogger
logger = logging.getLogger(__name__)
@ -172,82 +173,90 @@ class FreqaiPrimer(IStrategy):
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
logger.info(f"[{metadata['pair']}] 当前可用列: {list(dataframe.columns)}")
dataframe = self.freqai.start(dataframe, metadata, self)
# FreqAI 提供的预测列
if "&-trend" in dataframe.columns:
dataframe["in_uptrend"] = dataframe["&-trend"] > 0.5
# 缓存 mean/std 供后续使用
if self.freqai and hasattr(self.freqai, "data"):
labels_mean = self.freqai.data.labels_mean
labels_std = self.freqai.data.labels_std
# 将 roi_target 存入 dataframe供后续使用
if "&-roi_target" in dataframe.columns:
dataframe["&-roi_target"] = dataframe["&-roi_target"].ffill().fillna(0.01)
else:
dataframe["&-roi_target"] = 0.01
dataframe["mean_trend"] = labels_mean.get("&-trend_strength", 0.0001)
dataframe["std_trend"] = labels_std.get("&-trend_strength", 0.0031)
# 添加 trailing stop 参数到 dataframe
if "&-volatility_forecast" in dataframe.columns:
volatility = dataframe["&-volatility_forecast"].iloc[-1]
dataframe["trailing_stop_positive"] = max(0.003, volatility * 0.5)
dataframe["trailing_stop_positive_offset"] = max(0.006, volatility * 1.0)
else:
dataframe["trailing_stop_positive"] = 0.005
dataframe["trailing_stop_positive_offset"] = 0.01
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)
return dataframe
def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
"""
基于 FreqAI 的预测结果生成入场信号
使用滚动分位数 + Z-score + 市场状态过滤提高信号质量
"""
conditions = []
# 确保 &-buy_signal 存在
if "&-buy_signal" 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"]) & (df["&-buy_signal"] > 0.4)
buy_condition = df["&-buy_signal"] >= df["buy_threshold"]
# 👇 新增:滚动 Z-score 趋势判断
window = 50
df["trend_mean"] = df["&-trend_strength"].rolling(window).mean()
df["trend_std"] = df["&-trend_strength"].rolling(window).std()
df["z_score_trend"] = (df["&-trend_strength"] - df["trend_mean"]) / df["trend_std"]
# 使用 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]
# 只有当 z-score > 1 时才认为趋势显著
buy_condition &= (df["z_score_trend"] > 1)
z_score_trend = (df["&-trend_strength"] - mean_trend) / std_trend
buy_condition &= (z_score_trend > 1) # 只保留趋势显著的信号
# 打印模型统计信息用于调试
if self.freqai and hasattr(self.freqai, "data"):
labels_mean = self.freqai.data.labels_mean
labels_std = self.freqai.data.labels_std
# 市场状态过滤:震荡市减少交易频率
if "&-market_condition" in df.columns:
buy_condition &= ~(
(df["&-market_condition"] == "sideways") &
(df["&-buy_signal"] < df["buy_threshold"] * 1.2)
)
mean_trend = labels_mean.get("&-trend_strength", 0)
std_trend = labels_std.get("&-trend_strength", 1e-6)
# 在超买市场中进一步过滤买入信号
buy_condition &= ~(df["&-market_condition"] == "overbought")
logger.info(f"[{metadata['pair']}] Model trend mean: {mean_trend:.6f}, std: {std_trend:.6f}")
# EMA 趋势过滤
# 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)
# 市场状态过滤(只排除超买)
if "&-market_condition" in df.columns:
buy_condition &= ~(
(df["&-market_condition"] == "overbought")
)
conditions.append(buy_condition)
else:
logger.warning("⚠️ &-buy_signal 列缺失,跳过该条件")
self.logger.warning("⚠️ &-buy_signal 列缺失,跳过该条件")
if len(conditions) == 0:
return df
# 如果有多个条件,使用逻辑与合并
if len(conditions):
df.loc[reduce(lambda x, y: x & y, conditions), 'enter_long'] = 1
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()
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 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
conditions = [
@ -263,60 +272,48 @@ class FreqaiPrimer(IStrategy):
df.loc[reduce(lambda x, y: x & y, conditions), 'exit_long'] = 1
return df
def adjust_trade_position(self, trade: Trade, current_time: datetime,
current_rate: float, current_profit: float,
min_roi: Dict[float, float], max_profit: float):
min_roi: Dict[float, float], max_profit: float) -> Optional[Dict[float, float]]:
"""
动态调整当前交易的止盈目标
动态调整持仓逻辑基于 FreqAI 预测的 ROI 目标
根据 Z-score 判断趋势强度动态设置止盈时间窗口
"""
# 获取当前币种的 dataframe
pair = trade.pair
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe)
last_candle = dataframe.iloc[-1]
# 获取预测的 ROI 目标
roi_target = last_candle.get("&-roi_target", 0.01)
# 获取预测的 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)
# 获取模型输出统计信息用于自适应判断
mean_roi = 0.01
std_roi = 0.01
# 计算 Z-score
z_score_roi = (roi_target - mean_roi) / std_roi if std_roi != 0 else 0
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", mean_roi)
std_roi = labels_std.get("&-roi_target", std_roi)
high_threshold = mean_roi + std_roi
low_threshold = mean_roi - std_roi
# 根据预测值生成新的 ROI 表
if roi_target > high_threshold:
new_minimal_roi = {
"0": roi_target * 1.0,
"10": roi_target * 0.8,
"30": roi_target * 0.5,
"60": roi_target * 0.2,
"120": 0.005
# 根据 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
}
elif low_threshold <= roi_target <= high_threshold:
new_minimal_roi = {
elif z_score_roi > 0:
return {
"0": roi_target * 1.0,
"20": roi_target * 0.7,
"60": roi_target * 0.3,
"120": 0.005
"120": 0.01
}
else:
new_minimal_roi = {
return {
"0": max(0.005, roi_target),
"60": 0.005,
"180": 0.005
}
return new_minimal_roi
def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
"""