加入一个回测,
This commit is contained in:
@@ -293,7 +293,7 @@ class BBDelayReversalTrader:
|
||||
self.delay_reverse_type = reverse_type
|
||||
self.delay_reverse_price = trigger_price
|
||||
self.delay_reverse_kline_id = kline_id
|
||||
logger.info(f"触发延迟反转: {reverse_type} @ {trigger_price:.2f}")
|
||||
logger.warning(f"⚠️ 延迟反转触发: {reverse_type} @ {trigger_price:.2f} | K线ID: {kline_id}")
|
||||
|
||||
def clear_delay_reversal(self):
|
||||
"""清除延迟反转状态"""
|
||||
@@ -301,40 +301,82 @@ class BBDelayReversalTrader:
|
||||
self.delay_reverse_type = None
|
||||
self.delay_reverse_kline_id = None
|
||||
|
||||
def check_delay_reversal(self, current_kline, prev_kline, kline_index) -> tuple | None:
|
||||
"""检查延迟反转确认"""
|
||||
def check_delay_reversal(self, current_kline, prev_kline, prev_upper, prev_lower) -> tuple | None:
|
||||
"""
|
||||
检查延迟反转确认
|
||||
根据回测代码的逻辑:
|
||||
1. 次K确认:触轨后的下一根K线回调/反弹到记录价格
|
||||
2. 持续追踪:追踪上一根K线的触轨情况或实体
|
||||
"""
|
||||
if self.position == 0 or self.delay_reverse_price is None:
|
||||
return None
|
||||
|
||||
if self.delay_reverse_kline_id is None:
|
||||
return None
|
||||
|
||||
offset = kline_index - self.delay_reverse_kline_id
|
||||
current_kline_id = current_kline['id']
|
||||
trigger_kline_id = self.delay_reverse_kline_id
|
||||
|
||||
# 计算K线偏移(5分钟 = 300000ms)
|
||||
offset = (current_kline_id - trigger_kline_id) // 300000
|
||||
|
||||
if offset <= 0:
|
||||
return None
|
||||
|
||||
high = current_kline['high']
|
||||
low = current_kline['low']
|
||||
|
||||
logger.debug(f"延迟反转检查: offset={offset} | 当前K线 H={high:.2f} L={low:.2f}")
|
||||
|
||||
if self.delay_reverse_type == 'long_to_short':
|
||||
# 多转空: 回调到记录价格
|
||||
if offset == 1 and low <= self.delay_reverse_price:
|
||||
return 'short', self.delay_reverse_price, "次K回调确认"
|
||||
# 多转空: 需要价格回调
|
||||
if offset == 1:
|
||||
# 次K确认:回调到记录的上轨价格
|
||||
if low <= self.delay_reverse_price:
|
||||
logger.success(f"✓ 延迟反转确认(次K): 回调到 {self.delay_reverse_price:.2f}")
|
||||
return 'short', self.delay_reverse_price, "次K回调确认"
|
||||
|
||||
if offset >= 2 and prev_kline:
|
||||
prev_body_low = min(prev_kline['open'], prev_kline['close'])
|
||||
if low <= prev_body_low:
|
||||
return 'short', prev_body_low, "跌破上一根实体"
|
||||
elif offset >= 2 and prev_kline and prev_upper:
|
||||
# 持续追踪上一根K线
|
||||
prev_high = prev_kline['high']
|
||||
prev_touch_upper = prev_high >= prev_upper
|
||||
|
||||
if prev_touch_upper:
|
||||
# 上一根触上轨,当前K回调到上一根上轨价
|
||||
if low <= prev_upper:
|
||||
logger.success(f"✓ 延迟反转确认(追踪): 上一根触上轨后回调到 {prev_upper:.2f}")
|
||||
return 'short', prev_upper, "上一根触上轨后回调确认"
|
||||
else:
|
||||
# 上一根未触轨,跌破上一根实体
|
||||
prev_body_low = min(prev_kline['open'], prev_kline['close'])
|
||||
if low <= prev_body_low:
|
||||
logger.success(f"✓ 延迟反转确认(追踪): 跌破上一根实体 {prev_body_low:.2f}")
|
||||
return 'short', prev_body_low, "跌破上一根实体确认"
|
||||
|
||||
elif self.delay_reverse_type == 'short_to_long':
|
||||
# 空转多: 反弹到记录价格
|
||||
if offset == 1 and high >= self.delay_reverse_price:
|
||||
return 'long', self.delay_reverse_price, "次K反弹确认"
|
||||
# 空转多: 需要价格反弹
|
||||
if offset == 1:
|
||||
# 次K确认:反弹到记录的下轨价格
|
||||
if high >= self.delay_reverse_price:
|
||||
logger.success(f"✓ 延迟反转确认(次K): 反弹到 {self.delay_reverse_price:.2f}")
|
||||
return 'long', self.delay_reverse_price, "次K反弹确认"
|
||||
|
||||
if offset >= 2 and prev_kline:
|
||||
prev_body_high = max(prev_kline['open'], prev_kline['close'])
|
||||
if high >= prev_body_high:
|
||||
return 'long', prev_body_high, "突破上一根实体"
|
||||
elif offset >= 2 and prev_kline and prev_lower:
|
||||
# 持续追踪上一根K线
|
||||
prev_low = prev_kline['low']
|
||||
prev_touch_lower = prev_low <= prev_lower
|
||||
|
||||
if prev_touch_lower:
|
||||
# 上一根触下轨,当前K反弹到上一根下轨价
|
||||
if high >= prev_lower:
|
||||
logger.success(f"✓ 延迟反转确认(追踪): 上一根触下轨后反弹到 {prev_lower:.2f}")
|
||||
return 'long', prev_lower, "上一根触下轨后反弹确认"
|
||||
else:
|
||||
# 上一根未触轨,突破上一根实体
|
||||
prev_body_high = max(prev_kline['open'], prev_kline['close'])
|
||||
if high >= prev_body_high:
|
||||
logger.success(f"✓ 延迟反转确认(追踪): 突破上一根实体 {prev_body_high:.2f}")
|
||||
return 'long', prev_body_high, "突破上一根实体确认"
|
||||
|
||||
return None
|
||||
|
||||
@@ -361,7 +403,9 @@ class BBDelayReversalTrader:
|
||||
logger.info(f"初始持仓: {self.position}")
|
||||
|
||||
page_start = True
|
||||
kline_history = []
|
||||
kline_history = [] # 保存历史K线
|
||||
prev_bb_upper = None # 保存上一根K线的上轨
|
||||
prev_bb_lower = None # 保存上一根K线的下轨
|
||||
|
||||
while True:
|
||||
try:
|
||||
@@ -430,11 +474,16 @@ class BBDelayReversalTrader:
|
||||
touched_lower = cur_low <= bb_lower
|
||||
touched_middle = cur_low <= bb_mid <= cur_high
|
||||
|
||||
# 延迟反转状态显示
|
||||
delay_status = ""
|
||||
if self.delay_reverse_price is not None:
|
||||
delay_status = f" | 🔄延迟反转中: {self.delay_reverse_type} @ {self.delay_reverse_price:.2f}"
|
||||
|
||||
logger.info(
|
||||
f"价格={current_price:.2f} | "
|
||||
f"BB: {bb_lower:.2f}/{bb_mid:.2f}/{bb_upper:.2f} | "
|
||||
f"触上={touched_upper} 触下={touched_lower} 触中={touched_middle} | "
|
||||
f"仓位={self.position}"
|
||||
f"仓位={self.position}{delay_status}"
|
||||
)
|
||||
|
||||
# 同步持仓
|
||||
@@ -447,29 +496,31 @@ class BBDelayReversalTrader:
|
||||
time.sleep(self.cfg.POLL_INTERVAL)
|
||||
continue
|
||||
|
||||
# ===== 延迟反转确认 =====
|
||||
if self.delay_reverse_price is not None and len(kline_history) > 0:
|
||||
# ===== 延迟反转确认(优先级最高)=====
|
||||
if self.delay_reverse_price is not None:
|
||||
prev_kline = kline_history[-1] if len(kline_history) > 0 else None
|
||||
reversal = self.check_delay_reversal(
|
||||
current_kline, prev_kline, len(kline_history)
|
||||
current_kline, prev_kline, prev_bb_upper, prev_bb_lower
|
||||
)
|
||||
|
||||
if reversal:
|
||||
new_direction, reversal_price, reason = reversal
|
||||
logger.info(f"延迟反转确认: {reason} @ {reversal_price:.2f}")
|
||||
logger.warning(f"🔄 延迟反转确认: {reason} @ {reversal_price:.2f}")
|
||||
|
||||
# 平仓
|
||||
logger.info("执行平仓...")
|
||||
self.browser_close_position(1.0)
|
||||
time.sleep(2)
|
||||
time.sleep(3)
|
||||
self.get_position_status()
|
||||
|
||||
if self.position == 0:
|
||||
# 反向开仓
|
||||
logger.info(f"执行反向开{'多' if new_direction == 'long' else '空'}...")
|
||||
balance = self.get_balance()
|
||||
if balance:
|
||||
usdt_amount = round(balance * self.cfg.MARGIN_PCT, 2)
|
||||
self.browser_open_position(new_direction, usdt_amount)
|
||||
time.sleep(2)
|
||||
time.sleep(3)
|
||||
self.get_position_status()
|
||||
|
||||
if self.position != 0:
|
||||
@@ -477,7 +528,14 @@ class BBDelayReversalTrader:
|
||||
self.mid_closed_half = False
|
||||
self.clear_delay_reversal()
|
||||
self.last_kline_id = kline_id
|
||||
logger.success(f"✓ 延迟反转完成!")
|
||||
else:
|
||||
logger.error(f"平仓后仍有持仓: {self.position}")
|
||||
|
||||
# 更新历史
|
||||
kline_history.append(current_kline)
|
||||
prev_bb_upper = bb_upper
|
||||
prev_bb_lower = bb_lower
|
||||
continue
|
||||
|
||||
# ===== 中轨平仓 =====
|
||||
@@ -549,13 +607,13 @@ class BBDelayReversalTrader:
|
||||
|
||||
# ===== 延迟反转触发 =====
|
||||
elif self.position > 0 and touched_upper:
|
||||
logger.info("多仓触上轨,标记延迟反转")
|
||||
self.mark_delay_reversal('long_to_short', bb_upper, len(kline_history))
|
||||
logger.warning("⚠️ 多仓触上轨,标记延迟反转")
|
||||
self.mark_delay_reversal('long_to_short', bb_upper, kline_id)
|
||||
self.last_kline_id = kline_id
|
||||
|
||||
elif self.position < 0 and touched_lower:
|
||||
logger.info("空仓触下轨,标记延迟反转")
|
||||
self.mark_delay_reversal('short_to_long', bb_lower, len(kline_history))
|
||||
logger.warning("⚠️ 空仓触下轨,标记延迟反转")
|
||||
self.mark_delay_reversal('short_to_long', bb_lower, kline_id)
|
||||
self.last_kline_id = kline_id
|
||||
|
||||
# ===== 加仓 =====
|
||||
@@ -582,11 +640,14 @@ class BBDelayReversalTrader:
|
||||
self.position_count = 2
|
||||
self.last_kline_id = kline_id
|
||||
|
||||
# 更新K线历史
|
||||
# 更新K线历史和布林带历史
|
||||
kline_history.append(current_kline)
|
||||
if len(kline_history) > 100:
|
||||
kline_history = kline_history[-100:]
|
||||
|
||||
prev_bb_upper = bb_upper
|
||||
prev_bb_lower = bb_lower
|
||||
|
||||
time.sleep(self.cfg.POLL_INTERVAL)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
|
||||
18183
bb_sweep_results.csv
18183
bb_sweep_results.csv
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user