params file removed, and other update
This commit is contained in:
parent
e2b7fe5dcf
commit
09d40a2cf7
@ -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"
|
||||
}
|
||||
@ -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:
|
||||
"""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user