加入一个回测,
This commit is contained in:
151
job_bitmart.py
151
job_bitmart.py
@@ -106,6 +106,11 @@ class BBDelayReversalTrader:
|
|||||||
self.highest_since_open = None # 持有多仓以来的最高价
|
self.highest_since_open = None # 持有多仓以来的最高价
|
||||||
self.lowest_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=仅首次开仓)
|
self.pyramid_count = 0 # 当前已加仓次数 (0=仅首次开仓)
|
||||||
|
|
||||||
@@ -206,6 +211,8 @@ class BBDelayReversalTrader:
|
|||||||
self.has_half_closed = False
|
self.has_half_closed = False
|
||||||
self.highest_since_open = None
|
self.highest_since_open = None
|
||||||
self.lowest_since_open = None
|
self.lowest_since_open = None
|
||||||
|
self.touched_band_price = None
|
||||||
|
self.touched_prev_open = None
|
||||||
return True
|
return True
|
||||||
pos = positions[0]
|
pos = positions[0]
|
||||||
self.position = 1 if pos["position_type"] == 1 else -1
|
self.position = 1 if pos["position_type"] == 1 else -1
|
||||||
@@ -299,6 +306,8 @@ class BBDelayReversalTrader:
|
|||||||
self.has_half_closed = False
|
self.has_half_closed = False
|
||||||
self.highest_since_open = None
|
self.highest_since_open = None
|
||||||
self.lowest_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:
|
else:
|
||||||
logger.error(f"止损平仓失败,当前仍有持仓({self.position})")
|
logger.error(f"止损平仓失败,当前仍有持仓({self.position})")
|
||||||
|
|
||||||
# 5. 极值更新与半仓/全平反手逻辑 (需求: 如果当前做多,涨破中轨后回落碰中轨平一半;再跌到开仓价平全仓反手)
|
# 5. 极值更新与半仓/延迟全平反手逻辑
|
||||||
if self.position == 1 and self.open_avg_price:
|
if self.position == 1 and self.open_avg_price:
|
||||||
if self.highest_since_open is None or current_price > self.highest_since_open:
|
if self.highest_since_open is None or current_price > self.highest_since_open:
|
||||||
self.highest_since_open = current_price
|
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: 涨过中轨
|
# 规则 A1: 涨过中轨
|
||||||
if self.highest_since_open >= bb_mid:
|
if self.highest_since_open >= bb_mid:
|
||||||
# 从最高点回落触碰中轨,且未平过一半
|
# 从最高点回落触碰中轨,且未平过一半
|
||||||
@@ -594,7 +634,38 @@ class BBDelayReversalTrader:
|
|||||||
elif self.position == -1 and self.open_avg_price:
|
elif self.position == -1 and self.open_avg_price:
|
||||||
if self.lowest_since_open is None or current_price < self.lowest_since_open:
|
if self.lowest_since_open is None or current_price < self.lowest_since_open:
|
||||||
self.lowest_since_open = current_price
|
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: 跌破过中轨
|
# 规则 B1: 跌破过中轨
|
||||||
if self.lowest_since_open <= bb_mid:
|
if self.lowest_since_open <= bb_mid:
|
||||||
# 从最低点回升触碰中轨,且未平过一半
|
# 从最低点回升触碰中轨,且未平过一半
|
||||||
@@ -656,7 +727,7 @@ class BBDelayReversalTrader:
|
|||||||
reason = ""
|
reason = ""
|
||||||
success = False
|
success = False
|
||||||
|
|
||||||
# ===== 触及上轨 → 开空 / 翻转为空 / 加仓空 =====
|
# ===== 触及上轨 → 等待延迟平/开空/加仓空 =====
|
||||||
if touched_upper:
|
if touched_upper:
|
||||||
if not self.can_trade():
|
if not self.can_trade():
|
||||||
time.sleep(self.cfg.POLL_INTERVAL)
|
time.sleep(self.cfg.POLL_INTERVAL)
|
||||||
@@ -666,33 +737,16 @@ class BBDelayReversalTrader:
|
|||||||
f"BB({self.cfg.BB_PERIOD},{self.cfg.BB_STD})")
|
f"BB({self.cfg.BB_PERIOD},{self.cfg.BB_STD})")
|
||||||
|
|
||||||
if self.position == 1:
|
if self.position == 1:
|
||||||
action = "翻转: 平多→开空"
|
# 延迟平仓逻辑: 记录触碰上轨的信息,等待回落后再平仓,不断创新高则更新上轨目标价
|
||||||
# 在当前页面点市价平仓
|
prev_open = closed_klines[-1]["open"] if len(closed_klines) > 0 else cur_high
|
||||||
self.browser_close_position()
|
if self.touched_band_price is None or bb_upper > self.touched_band_price:
|
||||||
time.sleep(1)
|
self.touched_band_price = bb_upper
|
||||||
# 等待确认平仓
|
self.touched_prev_open = prev_open
|
||||||
for _ in range(10):
|
logger.info(f"多单已触碰上轨,记录延迟目标价: 轨={bb_upper:.2f}, 上根开={prev_open:.2f}。等待回落再平仓...")
|
||||||
if self.get_position_status() and self.position == 0:
|
|
||||||
break
|
# 特殊保护: 当前一瞬间即使碰到立刻跌下来,也要依靠下一轮的主循环去判断,防止剧烈波动同K线反复触发
|
||||||
time.sleep(1)
|
self.current_kline_id = current_kline["id"]
|
||||||
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
|
|
||||||
elif self.position == 0:
|
elif self.position == 0:
|
||||||
action = "开空"
|
action = "开空"
|
||||||
self.reset_position_state()
|
self.reset_position_state()
|
||||||
@@ -727,7 +781,7 @@ class BBDelayReversalTrader:
|
|||||||
else:
|
else:
|
||||||
logger.info(f"已持空仓,加仓已达上限({self.pyramid_count}/{self.cfg.PYRAMID_MAX})")
|
logger.info(f"已持空仓,加仓已达上限({self.pyramid_count}/{self.cfg.PYRAMID_MAX})")
|
||||||
|
|
||||||
# ===== 触及下轨 → 开多 / 翻转为多 / 加仓多 =====
|
# ===== 触及下轨 → 等待延迟平/开多/加仓多 =====
|
||||||
elif touched_lower:
|
elif touched_lower:
|
||||||
if not self.can_trade():
|
if not self.can_trade():
|
||||||
time.sleep(self.cfg.POLL_INTERVAL)
|
time.sleep(self.cfg.POLL_INTERVAL)
|
||||||
@@ -737,30 +791,15 @@ class BBDelayReversalTrader:
|
|||||||
f"BB({self.cfg.BB_PERIOD},{self.cfg.BB_STD})")
|
f"BB({self.cfg.BB_PERIOD},{self.cfg.BB_STD})")
|
||||||
|
|
||||||
if self.position == -1:
|
if self.position == -1:
|
||||||
action = "翻转: 平空→开多"
|
# 延迟平仓逻辑: 记录触碰下轨的信息,等待反弹后再平仓,不断创新低则更新下轨目标价
|
||||||
self.browser_close_position()
|
prev_open = closed_klines[-1]["open"] if len(closed_klines) > 0 else cur_low
|
||||||
time.sleep(1)
|
if self.touched_band_price is None or bb_lower < self.touched_band_price:
|
||||||
for _ in range(10):
|
self.touched_band_price = bb_lower
|
||||||
if self.get_position_status() and self.position == 0:
|
self.touched_prev_open = prev_open
|
||||||
break
|
logger.info(f"空单已触碰下轨,记录延迟目标价: 轨={bb_lower:.2f}, 上根开={prev_open:.2f}。等待反弹再平仓...")
|
||||||
time.sleep(1)
|
|
||||||
if self.position != 0:
|
self.current_kline_id = current_kline["id"]
|
||||||
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
|
|
||||||
elif self.position == 0:
|
elif self.position == 0:
|
||||||
action = "开多"
|
action = "开多"
|
||||||
self.reset_position_state()
|
self.reset_position_state()
|
||||||
|
|||||||
Reference in New Issue
Block a user