diff --git a/job_bitmart.py b/job_bitmart.py index 028e1e2..c35b4e1 100644 --- a/job_bitmart.py +++ b/job_bitmart.py @@ -98,6 +98,7 @@ class BBDelayReversalTrader: # 持仓状态: -1=空, 0=无, 1=多 self.position = 0 self.open_avg_price = None + self.initial_open_price = None # 固定记录首次开仓的价格,不受平半仓等影响 self.current_amount = None self.unrealized_value = 0.0 @@ -206,6 +207,7 @@ class BBDelayReversalTrader: if not positions: self.position = 0 self.open_avg_price = None + self.initial_open_price = None self.current_amount = None self.unrealized_value = 0.0 self.has_half_closed = False @@ -217,9 +219,14 @@ class BBDelayReversalTrader: pos = positions[0] self.position = 1 if pos["position_type"] == 1 else -1 self.open_avg_price = float(pos["open_avg_price"]) + + # 只在第一次有了仓位(或未被记录时)保存初始开仓价 + if self.initial_open_price is None or self.pyramid_count == 0: + self.initial_open_price = self.open_avg_price + self.current_amount = float(pos["current_amount"]) self.unrealized_value = float(pos.get("unrealized_value", 0)) - logger.debug(f"持仓: dir={self.position} price={self.open_avg_price} " + logger.debug(f"持仓: dir={self.position} price={self.open_avg_price} (初始:{self.initial_open_price}) " f"amt={self.current_amount} upnl={self.unrealized_value:.2f}") return True except Exception as e: @@ -303,6 +310,7 @@ class BBDelayReversalTrader: def reset_position_state(self): """重置所有关于持仓的变量""" self.pyramid_count = 0 + self.initial_open_price = None self.has_half_closed = False self.highest_since_open = None self.lowest_since_open = None @@ -603,9 +611,9 @@ class BBDelayReversalTrader: self.click_safe('x://button[normalize-space(text()) ="市价"]') # 规则 A2: 平过一半后,跌回开仓价 -> 全平反手开空 - if self.has_half_closed and (cur_low <= self.open_avg_price or current_price <= self.open_avg_price): + if self.has_half_closed and self.initial_open_price and (cur_low <= self.initial_open_price or current_price <= self.initial_open_price): if self.can_trade(): - logger.info("平半仓后跌回多单开仓价,全平反手开空") + logger.info(f"平半仓后跌回多单初始开仓价({self.initial_open_price}),全平反手开空") self.browser_close_position() time.sleep(1) for _ in range(10): @@ -633,6 +641,36 @@ class BBDelayReversalTrader: time.sleep(5) continue + # 规则 A3: 跌到中轨且处于亏损状态 -> 全平反手开空 + if self.initial_open_price and current_price < self.initial_open_price and (cur_low <= bb_mid or current_price <= bb_mid): + if self.can_trade(): + logger.info(f"多单跌回中轨且处于亏损(成本:{self.initial_open_price}),全平反手开空") + 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, "多单亏损时跌触中轨") + page_start = True + try: self.page.close() + except: pass + self.page = None + time.sleep(5) + continue + elif self.position == -1 and self.open_avg_price: # 记录持有期内的最低价 (包含当前实时价和当前K线最低价) current_min = min(current_price, cur_low) @@ -686,9 +724,9 @@ class BBDelayReversalTrader: self.click_safe('x://button[normalize-space(text()) ="市价"]') # 规则 B2: 平过一半后,涨回开仓价 -> 全平反手开多 - if self.has_half_closed and (cur_high >= self.open_avg_price or current_price >= self.open_avg_price): + if self.has_half_closed and self.initial_open_price and (cur_high >= self.initial_open_price or current_price >= self.initial_open_price): if self.can_trade(): - logger.info("平半仓后涨回空单开仓价,全平反手开多") + logger.info(f"平半仓后涨回空单初始开仓价({self.initial_open_price}),全平反手开多") self.browser_close_position() time.sleep(1) for _ in range(10): @@ -716,6 +754,36 @@ class BBDelayReversalTrader: time.sleep(5) continue + # 规则 B3: 涨到中轨且处于亏损状态 -> 全平反手开多 + if self.initial_open_price and current_price > self.initial_open_price and (cur_high >= bb_mid or current_price >= bb_mid): + if self.can_trade(): + logger.info(f"空单涨回中轨且处于亏损(成本:{self.initial_open_price}),全平反手开多") + 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, "空单亏损时涨触中轨") + page_start = True + try: self.page.close() + except: pass + self.page = None + time.sleep(5) + continue + # 6. 基本信号判断 (上轨空/下轨多) kline_id = current_kline["id"] if kline_id == last_kline_id: