简化逻辑
This commit is contained in:
parent
f6cca3b5bc
commit
2a7ba6a2e9
@ -27,165 +27,21 @@ class FreqaiPrimer(IStrategy):
|
||||
# 用于跟踪市场状态的数据框缓存
|
||||
_dataframe_cache = None
|
||||
|
||||
# 用于存储币对的波动系数
|
||||
_volatility_coefficients = {}
|
||||
# 基准币对 (波动系数设为1.0)
|
||||
_benchmark_pair = 'BTC/USDT'
|
||||
# 稳定币列表 (波动系数设为0.0)
|
||||
_stablecoins = ['USDT', 'USDC', 'BUSD', 'DAI', 'TUSD', 'USDP', 'GUSD', 'USTC']
|
||||
# 波动系数缓存有效期 (分钟)
|
||||
_volatility_cache_ttl = 60
|
||||
# 上次计算波动系数的时间
|
||||
_last_volatility_calculation = 0
|
||||
|
||||
def __init__(self, config=None):
|
||||
"""初始化策略参数,调用父类初始化方法并接受config参数"""
|
||||
super().__init__(config) # 调用父类的初始化方法并传递config
|
||||
# 存储从配置文件加载的默认值
|
||||
self._trailing_stop_positive_default = 0.004 # 降低默认值以更容易触发跟踪止盈
|
||||
# 初始化基准币对和稳定币的波动系数
|
||||
self._volatility_coefficients[self._benchmark_pair] = 1.0
|
||||
for stablecoin in self._stablecoins:
|
||||
# 处理所有稳定币交易对,如USDT/USDC等
|
||||
for quote in self._stablecoins:
|
||||
if stablecoin != quote:
|
||||
pair = f'{stablecoin}/{quote}'
|
||||
self._volatility_coefficients[pair] = 0.0
|
||||
|
||||
def _is_stablecoin_pair(self, pair: str) -> bool:
|
||||
"""
|
||||
判断一个交易对是否为稳定币交易对
|
||||
参数:
|
||||
- pair: 交易对,如 BTC/USDT
|
||||
返回:
|
||||
- bool: 是否为稳定币交易对
|
||||
"""
|
||||
try:
|
||||
base, quote = pair.split('/')
|
||||
return base in self._stablecoins and quote in self._stablecoins
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def _calculate_volatility(self, pair: str, lookback_period: int = 200, timeframe: str = '1h') -> float:
|
||||
"""
|
||||
计算一个币对的波动率
|
||||
参数:
|
||||
- pair: 交易对,如 BTC/USDT
|
||||
- lookback_period: 回看期K线数量,默认200
|
||||
- timeframe: 时间框架,默认1h
|
||||
返回:
|
||||
- float: 波动率值
|
||||
"""
|
||||
try:
|
||||
# 获取K线数据
|
||||
dataframe = self.dp.get_pair_dataframe(pair=pair, timeframe=timeframe)
|
||||
|
||||
# 确保有足够的K线数据
|
||||
if len(dataframe) < lookback_period:
|
||||
logger.warning(f"[{pair}] 没有足够的{timeframe} K线数据,需要{lookback_period}根,当前只有{len(dataframe)}根")
|
||||
# 如果数据不足,返回0.0或默认值
|
||||
return 0.0
|
||||
|
||||
# 获取最近的K线数据
|
||||
recent_data = dataframe.iloc[-lookback_period:].copy()
|
||||
|
||||
# 计算收益率 (收盘价变化百分比)
|
||||
recent_data['returns'] = recent_data['close'].pct_change()
|
||||
|
||||
# 计算对数收益率 (更适合波动率计算)
|
||||
recent_data['log_returns'] = np.log(recent_data['close'] / recent_data['close'].shift(1))
|
||||
|
||||
# 使用对数收益率的标准差作为波动率指标
|
||||
volatility = recent_data['log_returns'].std() * np.sqrt(24) # 年化波动率 (假设1天24小时)
|
||||
|
||||
return volatility
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[{pair}] 计算波动率时出错: {str(e)}")
|
||||
return 0.0
|
||||
|
||||
def _calculate_relative_volatility_coefficient(self, pair: str) -> float:
|
||||
"""
|
||||
计算相对波动系数(以BTC/USDT为基准)
|
||||
参数:
|
||||
- pair: 交易对,如 ETH/USDT
|
||||
返回:
|
||||
- float: 相对波动系数
|
||||
"""
|
||||
try:
|
||||
# 检查是否为稳定币交易对
|
||||
if self._is_stablecoin_pair(pair):
|
||||
return 0.0
|
||||
|
||||
# 检查是否为基准币对
|
||||
if pair == self._benchmark_pair:
|
||||
return 1.0
|
||||
|
||||
# 计算当前币对的波动率
|
||||
pair_volatility = self._calculate_volatility(pair)
|
||||
|
||||
# 计算基准币对的波动率
|
||||
benchmark_volatility = self._calculate_volatility(self._benchmark_pair)
|
||||
|
||||
# 避免除以0的情况
|
||||
if benchmark_volatility == 0:
|
||||
logger.warning(f"基准币对 {self._benchmark_pair} 的波动率为0,无法计算相对波动系数")
|
||||
return 0.0
|
||||
|
||||
# 计算相对波动系数
|
||||
relative_coefficient = pair_volatility / benchmark_volatility
|
||||
|
||||
return relative_coefficient
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[{pair}] 计算相对波动系数时出错: {str(e)}")
|
||||
return 0.0
|
||||
|
||||
# 只用于adjust_trade_position方法的波动系数获取
|
||||
def get_volatility_coefficient(self, pair: str) -> float:
|
||||
"""
|
||||
获取币对的波动系数(带缓存机制)
|
||||
参数:
|
||||
- pair: 交易对,如 ETH/USDT
|
||||
返回:
|
||||
- float: 波动系数(稳定币为0.0,BTC/USDT为1.0,其他币对相对于BTC波动程度)
|
||||
获取币对的波动系数(简化版,仅用于adjust_trade_position方法)
|
||||
返回固定值1.0,假设所有币对波动相当
|
||||
"""
|
||||
try:
|
||||
# 优先从缓存中获取,无需每次都检查时间戳
|
||||
# 这确保了在同一交易周期内多次调用时直接返回缓存值
|
||||
if pair in self._volatility_coefficients:
|
||||
# 检查是否为基准币对或稳定币对(它们的波动系数固定)
|
||||
if pair == self._benchmark_pair or self._is_stablecoin_pair(pair):
|
||||
return self._volatility_coefficients[pair]
|
||||
|
||||
# 获取当前时间戳(分钟)
|
||||
current_time = int(datetime.datetime.now().timestamp() / 60)
|
||||
|
||||
# 对于非固定波动系数的币对,检查缓存是否有效
|
||||
if current_time - self._last_volatility_calculation < self._volatility_cache_ttl:
|
||||
return self._volatility_coefficients[pair]
|
||||
|
||||
# 计算新的波动系数
|
||||
coefficient = self._calculate_relative_volatility_coefficient(pair)
|
||||
|
||||
# 更新缓存
|
||||
self._volatility_coefficients[pair] = coefficient
|
||||
|
||||
# 如果是首次计算或者缓存已过期,更新最后计算时间
|
||||
current_time = int(datetime.datetime.now().timestamp() / 60)
|
||||
if current_time - self._last_volatility_calculation >= self._volatility_cache_ttl:
|
||||
self._last_volatility_calculation = current_time
|
||||
# 日志记录
|
||||
logger.info(f"更新了波动系数缓存,当前时间: {current_time}, 上一次计算时间: {self._last_volatility_calculation}")
|
||||
|
||||
# 日志记录 - 仅在计算新值时记录
|
||||
logger.info(f"[{pair}] 波动系数: {coefficient:.4f}")
|
||||
|
||||
return coefficient
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[{pair}] 获取波动系数时出错: {str(e)}")
|
||||
# 如果出错,返回默认值1.0(假设与BTC波动相当)
|
||||
return 1.0
|
||||
return 1.0
|
||||
|
||||
# 其他辅助方法可以在这里添加
|
||||
|
||||
@property
|
||||
def protections(self):
|
||||
@ -674,44 +530,23 @@ class FreqaiPrimer(IStrategy):
|
||||
last_candle = dataframe.iloc[-1]
|
||||
atr = last_candle['atr']
|
||||
|
||||
# 获取当前币对的波动系数
|
||||
volatility_coef = self.get_volatility_coefficient(pair)
|
||||
|
||||
# 获取当前市场状态
|
||||
current_state = dataframe['market_state'].iloc[-1] if 'market_state' in dataframe.columns else 'unknown'
|
||||
|
||||
# 基础止损倍数
|
||||
base_multiplier = 1.2
|
||||
|
||||
# 根据波动系数调整止损倍数
|
||||
adjusted_multiplier = base_multiplier * volatility_coef
|
||||
|
||||
# 更激进的渐进式止损策略,同时考虑波动系数
|
||||
# 渐进式止损策略
|
||||
if current_profit > 0.05: # 利润超过5%时
|
||||
return -3.0 * adjusted_multiplier * atr / current_rate
|
||||
return -3.0 * atr / current_rate
|
||||
elif current_profit > 0.03: # 利润超过3%时
|
||||
return -2.5 * adjusted_multiplier * atr / current_rate
|
||||
return -2.5 * atr / current_rate
|
||||
elif current_profit > 0.01: # 利润超过1%时
|
||||
return -2.0 * adjusted_multiplier * atr / current_rate
|
||||
return -2.0 * atr / current_rate
|
||||
|
||||
# 在强劲牛市中,即使小亏损也可以容忍更大回调
|
||||
if current_state == 'strong_bull' and current_profit > -0.01:
|
||||
return -1.5 * adjusted_multiplier * atr / current_rate
|
||||
|
||||
# 动态调整止损范围
|
||||
if current_profit > 0.05: # 利润超过5%时
|
||||
return -3.0 * adjusted_multiplier * atr / current_rate
|
||||
elif current_profit > 0.03: # 利润超过3%时
|
||||
return -2.5 * adjusted_multiplier * atr / current_rate
|
||||
elif current_profit > 0.01: # 利润超过1%时
|
||||
return -2.0 * adjusted_multiplier * atr / current_rate
|
||||
|
||||
# 在强劲牛市中,即使小亏损也可以容忍更大回调
|
||||
if current_state == 'strong_bull' and current_profit > -0.01:
|
||||
return -1.8 * adjusted_multiplier * atr / current_rate
|
||||
return -1.8 * atr / current_rate
|
||||
|
||||
if atr > 0:
|
||||
return -adjusted_multiplier * atr / current_rate
|
||||
return -1.2 * atr / current_rate
|
||||
return self.stoploss
|
||||
|
||||
def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_rate: float,
|
||||
@ -723,9 +558,6 @@ class FreqaiPrimer(IStrategy):
|
||||
if trade_age_minutes < 0:
|
||||
trade_age_minutes = 0
|
||||
|
||||
# 获取当前币对的波动系数
|
||||
volatility_coef = self.get_volatility_coefficient(pair)
|
||||
|
||||
# 使用可优化的线性函数: y = (a * (x + k)) + t
|
||||
a = self.roi_param_a.value # 系数a (可优化参数)
|
||||
k = self.roi_param_k.value # 偏移量k (可优化参数)
|
||||
@ -754,11 +586,6 @@ class FreqaiPrimer(IStrategy):
|
||||
exit_ratio = 1.0
|
||||
if entry_tag == 'strong_trend':
|
||||
exit_ratio *= 0.8
|
||||
|
||||
# 根据波动系数调整退出比例
|
||||
# 波动率低的币对可以更激进(降低退出比例,持有更长时间)
|
||||
# 波动率高的币对需要更保守(增加退出比例,更快锁定利润)
|
||||
exit_ratio = max(0.0, min(1.0, exit_ratio * volatility_coef))
|
||||
|
||||
if dynamic_roi_threshold < 0:
|
||||
exit_ratio = 1.0
|
||||
@ -826,13 +653,8 @@ class FreqaiPrimer(IStrategy):
|
||||
|
||||
def custom_stake_amount(self, pair: str, current_time: datetime, **kwargs) -> float:
|
||||
"""
|
||||
根据波动系数动态调整初始仓位大小
|
||||
- 波动率高的币对分配较小的仓位
|
||||
- 波动率低的币对可以分配较大的仓位
|
||||
定义初始仓位大小
|
||||
"""
|
||||
# 获取当前币对的波动系数
|
||||
volatility_coef = self.get_volatility_coefficient(pair)
|
||||
|
||||
# 获取默认的基础仓位大小
|
||||
default_stake = self.stake_amount
|
||||
|
||||
@ -841,20 +663,19 @@ class FreqaiPrimer(IStrategy):
|
||||
max_stake = kwargs.get('max_stake', default_stake)
|
||||
|
||||
|
||||
# 根据波动系数调整仓位大小
|
||||
# 波动率与仓位大小成反比关系
|
||||
# 基础逻辑:波动率高的币对仓位较小,波动率低的币对仓位较大
|
||||
if volatility_coef > 0:
|
||||
# 使用平方根函数来降低极端波动的影响
|
||||
adjusted_stake = default_stake * min(1.5, max(0.5, 1.0 / (volatility_coef ** 0.5)))
|
||||
else:
|
||||
# 如果波动系数无法获取,使用默认仓位
|
||||
adjusted_stake = default_stake
|
||||
# 从kwargs获取最小和最大仓位限制
|
||||
min_stake = kwargs.get('min_stake', 0.0)
|
||||
max_stake = kwargs.get('max_stake', default_stake)
|
||||
|
||||
<<<<<<< Updated upstream
|
||||
# 确保调整后的仓位在允许的范围内
|
||||
adjusted_stake = max(min_stake, min(adjusted_stake, max_stake))
|
||||
|
||||
#logger.info(f"[{pair}] 基于波动系数调整仓位: 波动系数={volatility_coef:.2f}, 默认仓位={default_stake:.2f}, 调整后仓位={adjusted_stake:.2f}")
|
||||
=======
|
||||
# 确保仓位在允许的范围内
|
||||
adjusted_stake = max(min_stake, min(default_stake, max_stake))
|
||||
>>>>>>> Stashed changes
|
||||
|
||||
return adjusted_stake
|
||||
|
||||
@ -872,39 +693,19 @@ class FreqaiPrimer(IStrategy):
|
||||
) -> bool:
|
||||
"""
|
||||
交易买入前的确认函数,用于最终决定是否执行交易
|
||||
此处实现剧烈拉升检查逻辑,并根据波动系数调整入场条件
|
||||
此处实现剧烈拉升检查逻辑
|
||||
"""
|
||||
# 默认允许交易
|
||||
allow_trade = True
|
||||
|
||||
# 仅对多头交易进行检查
|
||||
if side == 'long':
|
||||
# 获取当前币对的波动系数
|
||||
volatility_coef = self.get_volatility_coefficient(pair)
|
||||
|
||||
# 检查是否处于剧烈拉升的不稳固区域
|
||||
is_unstable_region = self.detect_h1_rapid_rise(pair)
|
||||
|
||||
# 基于波动系数调整入场条件的严格程度
|
||||
# 波动率高的币对,入场条件更加严格
|
||||
# 波动率低的币对,入场条件可以适当放宽
|
||||
if is_unstable_region:
|
||||
#logger.info(f"[{pair}] 由于检测到剧烈拉升,取消入场交易")
|
||||
allow_trade = False
|
||||
|
||||
# 如果币对波动率非常高,可以增加额外的入场限制
|
||||
if volatility_coef > 2.0:
|
||||
# 对于高波动币对,可以要求更严格的入场条件
|
||||
# 例如,检查当前价格是否高于某个移动平均线
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
if len(dataframe) > 20:
|
||||
current_price = dataframe['close'].iloc[-1]
|
||||
sma20 = dataframe['sma'].iloc[-1] if 'sma' in dataframe.columns else 0
|
||||
|
||||
# 对于高波动币对,要求当前价格必须显著高于均线才允许入场
|
||||
if sma20 > 0 and (current_price / sma20) < 1.01:
|
||||
#logger.info(f"[{pair}] 由于高波动率且价格未显著高于均线,取消入场交易")
|
||||
allow_trade = False
|
||||
|
||||
# 如果没有阻止因素,允许交易
|
||||
return allow_trade
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user