From fdc43477d0d64a05100b4a7c5d264fa5bf3808ec Mon Sep 17 00:00:00 2001 From: 27942 <1313123@342> Date: Wed, 4 Feb 2026 01:50:34 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E5=85=A5=E7=B2=BE=E5=87=86=E5=9B=9E?= =?UTF-8?q?=E6=B5=8B=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bitmart/三分之一策略交易.py | 172 +++++++++++++++++++++++++++--------- 1 file changed, 130 insertions(+), 42 deletions(-) diff --git a/bitmart/三分之一策略交易.py b/bitmart/三分之一策略交易.py index 31f3b55..ac0d47d 100644 --- a/bitmart/三分之一策略交易.py +++ b/bitmart/三分之一策略交易.py @@ -305,41 +305,143 @@ class BitmartFuturesTransaction: return None + def verify_no_position(self, max_retries=5, retry_interval=3): + """ + 验证当前无持仓 + 返回: True 表示无持仓可以开仓,False 表示有持仓不能开仓 + """ + for i in range(max_retries): + if self.get_position_status(): + if self.start == 0: + logger.info(f"确认无持仓,可以开仓") + return True + else: + logger.warning(f"仍有持仓 (方向: {self.start}),等待 {retry_interval} 秒后重试 ({i+1}/{max_retries})") + time.sleep(retry_interval) + else: + logger.warning(f"查询持仓状态失败,等待 {retry_interval} 秒后重试 ({i+1}/{max_retries})") + time.sleep(retry_interval) + + logger.error(f"经过 {max_retries} 次重试仍有持仓或查询失败,放弃开仓") + return False + + def verify_position_direction(self, expected_direction): + """ + 验证当前持仓方向是否与预期一致 + expected_direction: 1 多仓, -1 空仓 + 返回: True 表示持仓方向正确,False 表示不正确 + """ + if self.get_position_status(): + if self.start == expected_direction: + logger.info(f"持仓方向验证成功: {self.start}") + return True + else: + logger.warning(f"持仓方向不符: 期望 {expected_direction}, 实际 {self.start}") + return False + else: + logger.error("查询持仓状态失败") + return False + def execute_trade(self, signal, size=1): """执行交易""" signal_type, trigger_price = signal - size= 25 + size = 25 + if signal_type == 'long': - # 开多 - logger.info(f"执行开多,触发价: {trigger_price:.2f}") + # 开多前先确认无持仓 + logger.info(f"准备开多,触发价: {trigger_price:.2f}") + if not self.get_position_status(): + logger.error("开仓前查询持仓状态失败,放弃开仓") + return False + if self.start != 0: + logger.warning(f"开多前发现已有持仓 (方向: {self.start}),放弃开仓避免双向持仓") + return False + + logger.info(f"确认无持仓,执行开多") self.开单(marketPriceLongOrder=1, size=size) - self.start = 1 + time.sleep(3) # 等待订单执行 + + # 验证开仓是否成功 + if self.verify_position_direction(1): + logger.success("开多成功") + return True + else: + logger.error("开多后持仓验证失败") + return False elif signal_type == 'short': - # 开空 - logger.info(f"执行开空,触发价: {trigger_price:.2f}") + # 开空前先确认无持仓 + logger.info(f"准备开空,触发价: {trigger_price:.2f}") + if not self.get_position_status(): + logger.error("开仓前查询持仓状态失败,放弃开仓") + return False + if self.start != 0: + logger.warning(f"开空前发现已有持仓 (方向: {self.start}),放弃开仓避免双向持仓") + return False + + logger.info(f"确认无持仓,执行开空") self.开单(marketPriceLongOrder=-1, size=size) - self.start = -1 + time.sleep(3) # 等待订单执行 + + # 验证开仓是否成功 + if self.verify_position_direction(-1): + logger.success("开空成功") + return True + else: + logger.error("开空后持仓验证失败") + return False elif signal_type == 'reverse_long': # 平空 + 开多(反手做多) logger.info(f"执行反手做多,触发价: {trigger_price:.2f}") self.平仓() - logger.info("反手等待15秒后再开仓...") + logger.info("反手等待平仓完成...") + time.sleep(15) + # 验证平仓是否成功(必须无持仓才能开新仓) + if not self.verify_no_position(max_retries=5, retry_interval=3): + logger.error("平仓未完成,放弃开多避免双向持仓") + return False + + logger.info("平仓完成,执行开多") self.开单(marketPriceLongOrder=1, size=size) - self.start = 1 - time.sleep(35) + time.sleep(3) # 等待订单执行 + + # 验证开仓是否成功 + if self.verify_position_direction(1): + logger.success("反手做多成功") + time.sleep(20) # 额外等待避免频繁交易 + return True + else: + logger.error("反手做多后持仓验证失败") + return False elif signal_type == 'reverse_short': # 平多 + 开空(反手做空) logger.info(f"执行反手做空,触发价: {trigger_price:.2f}") self.平仓() - logger.info("反手等待15秒后再开仓...") - + logger.info("反手等待平仓完成...") + time.sleep(15) + + # 验证平仓是否成功(必须无持仓才能开新仓) + if not self.verify_no_position(max_retries=5, retry_interval=3): + logger.error("平仓未完成,放弃开空避免双向持仓") + return False + + logger.info("平仓完成,执行开空") self.开单(marketPriceLongOrder=-1, size=size) - self.start = -1 - time.sleep(35) + time.sleep(3) # 等待订单执行 + + # 验证开仓是否成功 + if self.verify_position_direction(-1): + logger.success("反手做空成功") + time.sleep(20) # 额外等待避免频繁交易 + return True + else: + logger.error("反手做空后持仓验证失败") + return False + + return False def action(self): """主循环""" @@ -360,9 +462,6 @@ class BitmartFuturesTransaction: logger.info("开始运行三分之一策略交易...") - # 标记是否刚执行过交易(用于跳过从交易所获取持仓状态,避免延迟问题) - just_traded = False - while True: try: # 1. 获取K线数据(当前K线和上一根K线) @@ -379,38 +478,27 @@ class BitmartFuturesTransaction: time.sleep(2) continue - # 3. 获取持仓状态(如果刚交易过,信任本地状态,跳过API查询避免延迟) - if not just_traded: - if not self.get_position_status(): - logger.warning("获取持仓状态失败,等待重试...") - time.sleep(2) - continue - else: - logger.info(f"刚执行交易,信任本地持仓状态: {self.start}") - just_traded = False # 重置标记 + # 3. 每次循环都通过SDK获取真实持仓状态(避免状态不同步导致双向持仓) + if not self.get_position_status(): + logger.warning("获取持仓状态失败,等待重试...") + time.sleep(2) + continue + + logger.debug(f"当前持仓状态: {self.start} (0=无, 1=多, -1=空)") # 4. 检查信号 signal = self.check_signal(current_price, prev_kline, current_kline) # 5. 有信号则执行交易 if signal: - self.execute_trade(signal, size=1) - logger.success(f"交易执行完成: {signal[0]}, 当前持仓状态: {self.start}") - just_traded = True # 标记刚执行过交易 + trade_success = self.execute_trade(signal, size=1) + if trade_success: + logger.success(f"交易执行完成: {signal[0]}, 当前持仓状态: {self.start}") + else: + logger.warning(f"交易执行失败或被阻止: {signal[0]}") - # 交易后立即再次检查是否有反手信号(同一根K线内可能多次反手) - time.sleep(1) # 短暂等待 - - # 重新获取价格,检查是否需要再次反手 - new_price = self.get_current_price() - if new_price: - new_signal = self.check_signal(new_price, prev_kline, current_kline) - if new_signal: - logger.info(f"检测到连续反手信号!当前价格: {new_price:.2f}") - self.execute_trade(new_signal, size=1) - logger.success(f"连续反手执行完成: {new_signal[0]}, 当前持仓状态: {self.start}") - - time.sleep(1) # 交易后稍等 + # 交易后等待一段时间再继续监控(无论成功失败) + time.sleep(3) continue # 立即进入下一次循环继续监控 # 6. 短暂等待后继续循环(同一根K线遇到信号就操作)