修复回测与实盘差异问题
- 调整冷启动保护逻辑,使其在回测模式下不启用 - 修复入场时间记录逻辑,确保入场间隔控制在回测中生效 - 移除外部数据校验逻辑,提高回测与实盘一致性 - 优化confirm_trade_entry函数结构
This commit is contained in:
parent
419c1ae813
commit
6446aa5dc1
@ -1352,100 +1352,57 @@ class FreqaiPrimer(IStrategy):
|
|||||||
self.strategy_log(f"[{pair}] 非多头交易,跳过入场检查")
|
self.strategy_log(f"[{pair}] 非多头交易,跳过入场检查")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# 获取虚机名字
|
# 记录所有拒绝条件的列表
|
||||||
import os
|
rejected_conditions = []
|
||||||
virtual_host_name = os.environ.get('VIRTUAL_HOST_NAME')
|
|
||||||
self.strategy_log(f"[{pair}] 当前虚机名字: {virtual_host_name}")
|
|
||||||
|
|
||||||
# 只有当虚机名字是kiko时,才执行从外部获取数据和RMSE限制的逻辑
|
# 冷启动保护:程序启动后前20分钟内不允许入场
|
||||||
if virtual_host_name == 'kiko':
|
cold_start_rejected = False
|
||||||
self.strategy_log(f"[{pair}] 虚机名字是kiko,执行外部数据获取和RMSE限制逻辑")
|
if hasattr(self, "_strategy_start_time"):
|
||||||
import requests
|
# 在回测模式下不启用冷启动保护
|
||||||
import json
|
if not self.config.get("dry_run", False):
|
||||||
|
warmup_minutes = 20
|
||||||
try:
|
# current_time 来自框架,是 offset-aware (UTC)
|
||||||
# 构建API请求URL
|
# _strategy_start_time 是 offset-naive (本地时间)
|
||||||
api_url = f"http://pairlist.xl.home/api/mlpredictionList?pairName={pair}&sortBy=timestamp"
|
# 需要统一处理:把 current_time 转换为本地时间并移除时区信息
|
||||||
self.strategy_log(f"[{pair}] 请求API数据: {api_url}")
|
if current_time.tzinfo is not None:
|
||||||
|
local_current_time = current_time.astimezone(UTC_PLUS_8).replace(tzinfo=None)
|
||||||
# 发送API请求
|
|
||||||
response = requests.get(api_url, timeout=10)
|
|
||||||
response.raise_for_status() # 检查请求是否成功
|
|
||||||
|
|
||||||
# 解析API响应
|
|
||||||
data = response.json()
|
|
||||||
if not data.get('success'):
|
|
||||||
self.strategy_log(f"[{pair}] API请求失败: {data.get('message', '未知错误')}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
predictions = data.get('predictions', [])
|
|
||||||
if not predictions:
|
|
||||||
self.strategy_log(f"[{pair}] API返回空预测数据")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 只取第一条数据
|
|
||||||
first_prediction = predictions[0]
|
|
||||||
self.strategy_log(f"[{pair}] 从API获取到预测数据: 时间戳={first_prediction.get('timestamp')}")
|
|
||||||
|
|
||||||
# 检查时间戳是否不超过现在时间5分钟
|
|
||||||
prediction_timestamp = first_prediction.get('timestamp')
|
|
||||||
if not prediction_timestamp:
|
|
||||||
self.strategy_log(f"[{pair}] 预测数据缺少时间戳")
|
|
||||||
return False
|
|
||||||
|
|
||||||
import time
|
|
||||||
current_timestamp = int(time.time())
|
|
||||||
time_diff_seconds = current_timestamp - prediction_timestamp
|
|
||||||
time_diff_minutes = time_diff_seconds / 60
|
|
||||||
|
|
||||||
if time_diff_minutes > 5:
|
|
||||||
self.strategy_log(f"[{pair}] 预测数据过期: 时间戳 {prediction_timestamp} 距离现在 {time_diff_minutes:.1f} 分钟,超过5分钟限制")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 检查RMSE是否小于0.6
|
|
||||||
rmse = first_prediction.get('rmse')
|
|
||||||
if rmse is None:
|
|
||||||
self.strategy_log(f"[{pair}] 预测数据缺少RMSE值")
|
|
||||||
return False
|
|
||||||
|
|
||||||
if rmse >= 0.6:
|
|
||||||
self.strategy_log(f"[{pair}] RMSE值过大: {rmse} >= 0.6,拒绝入场")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 检查未来波动率,高波动禁止入场
|
|
||||||
values = first_prediction.get('values', {})
|
|
||||||
future_volatility = values.get('&s-future_volatility')
|
|
||||||
|
|
||||||
if future_volatility is None:
|
|
||||||
self.strategy_log(f"[{pair}] 预测数据缺少未来波动率值")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 定义高波动率阈值(可根据需要调整)
|
|
||||||
high_volatility_threshold = 0.7
|
|
||||||
if future_volatility > high_volatility_threshold:
|
|
||||||
self.strategy_log(f"[{pair}] 高波动禁止入场: 未来波动率 {future_volatility} > 阈值 {high_volatility_threshold}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 所有条件通过,允许入场
|
|
||||||
self.strategy_log(f"[{pair}] 所有条件通过,允许入场")
|
|
||||||
self.strategy_log(f"[{pair}] 预测数据详情: ")
|
|
||||||
self.strategy_log(f" - 时间戳: {prediction_timestamp}")
|
|
||||||
self.strategy_log(f" - RMSE: {rmse}")
|
|
||||||
self.strategy_log(f" - 未来波动率: {future_volatility}")
|
|
||||||
self.strategy_log(f" - 入场信号: {values.get('&s-entry_signal')}")
|
|
||||||
self.strategy_log(f" - 出场信号: {values.get('&s-exit_signal')}")
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
except requests.RequestException as e:
|
|
||||||
self.strategy_log(f"[{pair}] API请求失败: {str(e)}")
|
|
||||||
return False
|
|
||||||
except Exception as e:
|
|
||||||
self.strategy_log(f"[{pair}] 检查过程中发生错误: {str(e)}")
|
|
||||||
return False
|
|
||||||
else:
|
else:
|
||||||
# 虚机名字不是kiko,跳过外部数据获取和RMSE限制,直接允许入场
|
local_current_time = current_time
|
||||||
self.strategy_log(f"[{pair}] 虚机名字不是kiko,跳过外部数据获取和RMSE限制,直接允许入场")
|
elapsed_minutes = (local_current_time - self._strategy_start_time).total_seconds() / 60.0
|
||||||
|
if elapsed_minutes < warmup_minutes:
|
||||||
|
rejected_conditions.append(f"冷启动保护: 策略启动未满 {warmup_minutes} 分钟(已运行 {elapsed_minutes:.1f} 分钟)")
|
||||||
|
self.strategy_log(f"[{pair}] {rejected_conditions[-1]}")
|
||||||
|
cold_start_rejected = True
|
||||||
|
|
||||||
|
# 检查1:入场间隔控制(使用hyperopt参数)
|
||||||
|
interval_rejected = False
|
||||||
|
if pair in self._last_entry_time and not cold_start_rejected:
|
||||||
|
last_entry = self._last_entry_time[pair]
|
||||||
|
time_diff = (current_time - last_entry).total_seconds() * 0.0166666667 # 转换为分钟(使用乘法避免除法)
|
||||||
|
if time_diff < self.entry_interval_minutes.value:
|
||||||
|
rejected_conditions.append(f"入场间隔不足: 距离上次入场 {time_diff:.1f}分钟 < {self.entry_interval_minutes.value}分钟")
|
||||||
|
self.strategy_log(f"[{pair}] {rejected_conditions[-1]}")
|
||||||
|
interval_rejected = True
|
||||||
|
|
||||||
|
# 检查2:检查是否处于剧烈拉升的不稳固区域
|
||||||
|
unstable_rejected = False
|
||||||
|
if not cold_start_rejected and not interval_rejected:
|
||||||
|
is_unstable_region = self.detect_h1_rapid_rise(pair)
|
||||||
|
if is_unstable_region:
|
||||||
|
rejected_conditions.append("剧烈拉升检测: 检测到1小时图剧烈拉升")
|
||||||
|
self.strategy_log(f"[{pair}] {rejected_conditions[-1]}")
|
||||||
|
unstable_rejected = True
|
||||||
|
|
||||||
|
# 如果有任何拒绝条件,直接返回 False
|
||||||
|
if rejected_conditions:
|
||||||
|
self.strategy_log(f"[{pair}] 入场被拒绝,原因: {', '.join(rejected_conditions)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 所有条件通过,允许入场并记录入场时间
|
||||||
|
self.strategy_log(f"[{pair}] 所有条件通过,允许入场")
|
||||||
|
self._last_entry_time[pair] = current_time
|
||||||
|
self.strategy_log(f"[{pair}] 更新入场时间为: {current_time}")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user