加入一个回测,

This commit is contained in:
ddrwode
2026-03-09 11:20:28 +08:00
parent 0c88c29fd6
commit 39d67b1cc6

View File

@@ -106,6 +106,11 @@ class BBDelayReversalTrader:
self.highest_since_open = None # 持有多仓以来的最高价
self.lowest_since_open = None # 持有空仓以来的最低价
# 延迟平仓(碰轨不平,回落/反弹再平)状态
self.touched_band_price = None # 最近一次触碰轨道的触发价格
self.touched_prev_open = None # 发生触碰时的前一根K线开盘价
self.current_kline_id = None # 记录当前在处理的K线
# 加仓状态
self.pyramid_count = 0 # 当前已加仓次数 (0=仅首次开仓)
@@ -206,6 +211,8 @@ class BBDelayReversalTrader:
self.has_half_closed = False
self.highest_since_open = None
self.lowest_since_open = None
self.touched_band_price = None
self.touched_prev_open = None
return True
pos = positions[0]
self.position = 1 if pos["position_type"] == 1 else -1
@@ -299,6 +306,8 @@ class BBDelayReversalTrader:
self.has_half_closed = False
self.highest_since_open = None
self.lowest_since_open = None
self.touched_band_price = None
self.touched_prev_open = None
# ------------------------------------------------------------------
# 仓位操作
@@ -539,11 +548,42 @@ class BBDelayReversalTrader:
else:
logger.error(f"止损平仓失败,当前仍有持仓({self.position})")
# 5. 极值更新与半仓/全平反手逻辑 (需求: 如果当前做多,涨破中轨后回落碰中轨平一半;再跌到开仓价平全仓反手)
# 5. 极值更新与半仓/延迟全平反手逻辑
if self.position == 1 and self.open_avg_price:
if self.highest_since_open is None or current_price > self.highest_since_open:
self.highest_since_open = current_price
# 延迟平仓逻辑: 之前触碰过上轨
if self.touched_band_price is not None:
# 检查是否回落到 触发的上轨价格 或者 上一根K线的开盘价
trigger_target = max(self.touched_band_price, self.touched_prev_open) if self.touched_prev_open else self.touched_band_price
if current_price <= trigger_target or cur_low <= trigger_target:
if self.can_trade():
logger.info(f"多单延迟回落平仓: 当前价跌破触发点 {trigger_target:.2f} (上轨价: {self.touched_band_price}, 上根开: {self.touched_prev_open})")
self.browser_close_position()
time.sleep(1)
for _ in range(10):
if self.get_position_status() and self.position == 0: break
time.sleep(1)
self.reset_position_state()
self.click_safe('x://button[normalize-space(text()) ="开仓"]')
time.sleep(0.5)
self.click_safe('x://button[normalize-space(text()) ="市价"]')
order_usdt = self.calc_order_usdt()
if order_usdt > 0:
self.page.ele('x://*[@id="size_0"]').input(vals=order_usdt, clear=True)
time.sleep(0.5)
self.click_safe('x://span[normalize-space(text()) ="卖出/做空"]')
time.sleep(3)
self.get_position_status()
self.write_trade_log("延迟全平反手(多转空)", current_price, bb_upper, bb_mid, bb_lower, f"多单碰上轨后回落至 {trigger_target:.2f}")
page_start = True
try: self.page.close()
except: pass
self.page = None
time.sleep(5)
continue
# 规则 A1: 涨过中轨
if self.highest_since_open >= bb_mid:
# 从最高点回落触碰中轨,且未平过一半
@@ -594,7 +634,38 @@ class BBDelayReversalTrader:
elif self.position == -1 and self.open_avg_price:
if self.lowest_since_open is None or current_price < self.lowest_since_open:
self.lowest_since_open = current_price
# 延迟平仓逻辑: 之前触碰过下轨
if self.touched_band_price is not None:
# 检查是否反弹到 触发的下轨价格 或者 上一根K线的开盘价
trigger_target = min(self.touched_band_price, self.touched_prev_open) if self.touched_prev_open else self.touched_band_price
if current_price >= trigger_target or cur_high >= trigger_target:
if self.can_trade():
logger.info(f"空单延迟反弹平仓: 当前价突破触发点 {trigger_target:.2f} (下轨价: {self.touched_band_price}, 上根开: {self.touched_prev_open})")
self.browser_close_position()
time.sleep(1)
for _ in range(10):
if self.get_position_status() and self.position == 0: break
time.sleep(1)
self.reset_position_state()
self.click_safe('x://button[normalize-space(text()) ="开仓"]')
time.sleep(0.5)
self.click_safe('x://button[normalize-space(text()) ="市价"]')
order_usdt = self.calc_order_usdt()
if order_usdt > 0:
self.page.ele('x://*[@id="size_0"]').input(vals=order_usdt, clear=True)
time.sleep(0.5)
self.click_safe('x://span[normalize-space(text()) ="买入/做多"]')
time.sleep(3)
self.get_position_status()
self.write_trade_log("延迟全平反手(空转多)", current_price, bb_upper, bb_mid, bb_lower, f"空单碰下轨后反弹至 {trigger_target:.2f}")
page_start = True
try: self.page.close()
except: pass
self.page = None
time.sleep(5)
continue
# 规则 B1: 跌破过中轨
if self.lowest_since_open <= bb_mid:
# 从最低点回升触碰中轨,且未平过一半
@@ -656,7 +727,7 @@ class BBDelayReversalTrader:
reason = ""
success = False
# ===== 触及上轨 → 开空 / 翻转为空 / 加仓空 =====
# ===== 触及上轨 → 等待延迟平/开空/加仓空 =====
if touched_upper:
if not self.can_trade():
time.sleep(self.cfg.POLL_INTERVAL)
@@ -666,33 +737,16 @@ class BBDelayReversalTrader:
f"BB({self.cfg.BB_PERIOD},{self.cfg.BB_STD})")
if self.position == 1:
action = "翻转: 平多→开空"
# 在当前页面点市价平仓
self.browser_close_position()
time.sleep(1)
# 等待确认平仓
for _ in range(10):
if self.get_position_status() and self.position == 0:
break
time.sleep(1)
if self.position != 0:
logger.warning(f"平仓后仍有持仓({self.position}),放弃开空")
time.sleep(self.cfg.POLL_INTERVAL)
continue
self.reset_position_state()
# 平仓后在同一页面直接点卖出/做空
logger.info("平仓完成,直接开空")
self.click_safe('x://button[normalize-space(text()) ="开仓"]')
time.sleep(0.5)
self.click_safe('x://button[normalize-space(text()) ="市价"]')
order_usdt = self.calc_order_usdt()
if order_usdt > 0:
self.page.ele('x://*[@id="size_0"]').input(vals=order_usdt, clear=True)
time.sleep(0.5)
self.click_safe('x://span[normalize-space(text()) ="卖出/做空"]')
time.sleep(3)
if self.verify_position(-1):
success = True
# 延迟平仓逻辑: 记录触碰上轨的信息,等待回落后再平仓,不断创新高则更新上轨目标价
prev_open = closed_klines[-1]["open"] if len(closed_klines) > 0 else cur_high
if self.touched_band_price is None or bb_upper > self.touched_band_price:
self.touched_band_price = bb_upper
self.touched_prev_open = prev_open
logger.info(f"多单已触碰上轨,记录延迟目标价: 轨={bb_upper:.2f}, 上根开={prev_open:.2f}。等待回落再平仓...")
# 特殊保护: 当前一瞬间即使碰到立刻跌下来也要依靠下一轮的主循环去判断防止剧烈波动同K线反复触发
self.current_kline_id = current_kline["id"]
elif self.position == 0:
action = "开空"
self.reset_position_state()
@@ -727,7 +781,7 @@ class BBDelayReversalTrader:
else:
logger.info(f"已持空仓,加仓已达上限({self.pyramid_count}/{self.cfg.PYRAMID_MAX})")
# ===== 触及下轨 → 开多 / 翻转为多 / 加仓多 =====
# ===== 触及下轨 → 等待延迟平/开多/加仓多 =====
elif touched_lower:
if not self.can_trade():
time.sleep(self.cfg.POLL_INTERVAL)
@@ -737,30 +791,15 @@ class BBDelayReversalTrader:
f"BB({self.cfg.BB_PERIOD},{self.cfg.BB_STD})")
if self.position == -1:
action = "翻转: 平空→开多"
self.browser_close_position()
time.sleep(1)
for _ in range(10):
if self.get_position_status() and self.position == 0:
break
time.sleep(1)
if self.position != 0:
logger.warning(f"平仓后仍有持仓({self.position}),放弃开多")
time.sleep(self.cfg.POLL_INTERVAL)
continue
self.reset_position_state()
logger.info("平仓完成,直接开多")
self.click_safe('x://button[normalize-space(text()) ="开仓"]')
time.sleep(0.5)
self.click_safe('x://button[normalize-space(text()) ="市价"]')
order_usdt = self.calc_order_usdt()
if order_usdt > 0:
self.page.ele('x://*[@id="size_0"]').input(vals=order_usdt, clear=True)
time.sleep(0.5)
self.click_safe('x://span[normalize-space(text()) ="买入/做多"]')
time.sleep(3)
if self.verify_position(1):
success = True
# 延迟平仓逻辑: 记录触碰下轨的信息,等待反弹后再平仓,不断创新低则更新下轨目标价
prev_open = closed_klines[-1]["open"] if len(closed_klines) > 0 else cur_low
if self.touched_band_price is None or bb_lower < self.touched_band_price:
self.touched_band_price = bb_lower
self.touched_prev_open = prev_open
logger.info(f"空单已触碰下轨,记录延迟目标价: 轨={bb_lower:.2f}, 上根开={prev_open:.2f}。等待反弹再平仓...")
self.current_kline_id = current_kline["id"]
elif self.position == 0:
action = "开多"
self.reset_position_state()