From 586da576b4137fbd667a26b1232912448d67cb3f Mon Sep 17 00:00:00 2001 From: "zhangkun9038@dingtalk.com" Date: Sun, 28 Sep 2025 15:35:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B3=A2=E5=8A=A8=E7=B3=BB=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- freqtrade/templates/freqaiprimer.py | 110 +++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 3 deletions(-) diff --git a/freqtrade/templates/freqaiprimer.py b/freqtrade/templates/freqaiprimer.py index 64dc68f7..98a579cd 100644 --- a/freqtrade/templates/freqaiprimer.py +++ b/freqtrade/templates/freqaiprimer.py @@ -32,14 +32,118 @@ class FreqaiPrimer(IStrategy): super().__init__(config) # 调用父类的初始化方法并传递config # 存储从配置文件加载的默认值 self._trailing_stop_positive_default = 0.004 # 降低默认值以更容易触发跟踪止盈 + + # 初始化历史波动系数缓存字典,用于存储每个币对的波动系数历史值 + # 格式: {pair: [volatility_coefficient1, volatility_coefficient2, ...]} + self._volatility_history = {} + + # EMA参数 + self._ema_period = 20 # EMA窗口大小 + self._max_history_length = 200 # 最大历史记录长度 # 只用于adjust_trade_position方法的波动系数获取 def get_volatility_coefficient(self, pair: str) -> float: """ - 获取币对的波动系数(简化版,仅用于adjust_trade_position方法) - 返回固定值1.0,假设所有币对波动相当 + 获取币对的波动系数 + - USDT/USDT 波动系数设置为0 + - BTC/USDT 波动系数设置为1 + - 其他币对: + 1. 计算当前波动系数 = 该币对波动率 / BTC/USDT波动率 + 2. 维护最近200个波动系数的历史序列 + 3. 计算该序列的EMA20值作为最终波动系数 + + 波动系数表示某币对与BTC/USDT相比的波动幅度倍数 + - 山寨币的波动系数可能大于3 + - 稳定性较高的币对(如DOT/USDT)波动系数可能小于1 """ - return 1.0 + # 检查特殊币对 + if pair == 'USDT/USDT': + return 0.0 + elif pair == 'BTC/USDT': + return 1.0 + + try: + # 初始化该币对的历史记录(如果不存在) + if pair not in self._volatility_history: + self._volatility_history[pair] = [] + + # 1. 计算当前波动系数(基于最近的k线数据) + current_volatility_coef = self._calculate_current_volatility_coef(pair) + + # 2. 将当前波动系数添加到历史记录中 + self._volatility_history[pair].append(current_volatility_coef) + + # 3. 保持历史记录长度不超过最大限制 + if len(self._volatility_history[pair]) > self._max_history_length: + self._volatility_history[pair] = self._volatility_history[pair][-self._max_history_length:] + + # 4. 计算EMA20值 + if len(self._volatility_history[pair]) >= self._ema_period: + # 使用pandas计算EMA + import pandas as pd + + # 创建一个Series对象 + vol_series = pd.Series(self._volatility_history[pair]) + + # 计算EMA20 + ema_volatility_coef = vol_series.ewm(span=self._ema_period, adjust=False).mean().iloc[-1] + + # 确保EMA值在合理范围内 + final_coef = max(0.1, min(5.0, ema_volatility_coef)) + self.log_once(f"计算波动系数EMA完成 {pair}: 最终系数={final_coef:.4f} (历史数据点数={len(self._volatility_history[pair])})") + return final_coef + else: + # 如果历史数据不足,返回当前波动系数(或默认值) + # 当历史数据少于EMA周期时,使用简单移动平均或直接返回当前值 + # 这里选择直接返回当前波动系数,并限制范围 + final_coef = max(0.1, min(5.0, current_volatility_coef)) + self.log_once(f"计算波动系数EMA完成 {pair}: 最终系数={final_coef:.4f} (历史数据不足,使用当前值)") + return final_coef + except Exception as e: + self.log_once(f"计算波动系数EMA时出错 {pair}: {str(e)}", logger=self.logger.warning) + return 1.0 # 出错时返回默认值1.0 + + def _calculate_current_volatility_coef(self, pair: str) -> float: + """ + 计算当前的波动系数(该币对波动率 / BTC/USDT波动率) + """ + try: + # 获取当前币对的1小时k线数据 + current_pair_df, _ = self.dp.get_analyzed_dataframe(pair, '1h') + # 获取BTC/USDT的1小时k线数据 + btc_df, _ = self.dp.get_analyzed_dataframe('BTC/USDT', '1h') + + # 确保有足够的数据点 + if len(current_pair_df) < 2 or len(btc_df) < 2: + return 1.0 # 如果没有足够数据,返回默认值1.0 + + # 对于数据点少于200个的情况,使用所有可用数据 + # 对于数据点多于200个的情况,使用最近200个数据点 + current_data = current_pair_df.iloc[-min(200, len(current_pair_df)):] + btc_data = btc_df.iloc[-min(200, len(btc_df)):] + + # 计算当前币对的对数收益率和波动率 + current_data['returns'] = current_data['close'].pct_change() + current_volatility = current_data['returns'].std() * 100 # 转换为百分比 + + # 计算BTC/USDT的对数收益率和波动率 + btc_data['returns'] = btc_data['close'].pct_change() + btc_volatility = btc_data['returns'].std() * 100 # 转换为百分比 + + # 避免除以零的情况 + if btc_volatility == 0: + return 1.0 + + # 计算波动系数:当前币对波动率 / BTC/USDT波动率 + volatility_coef = current_volatility / btc_volatility + + # 设置合理的上下限,避免极端值影响策略 + # 上限设置为5.0(非常高波动的币对) + # 下限设置为0.1(非常稳定的币对) + return max(0.1, min(5.0, volatility_coef)) + except Exception as e: + self.log_once(f"计算当前波动系数时出错 {pair}: {str(e)}", logger=self.logger.warning) + return 1.0 # 出错时返回默认值1.0 # 其他辅助方法可以在这里添加