From 9eaab254515b60f6d9ea3e2e228ed6d235fc0724 Mon Sep 17 00:00:00 2001 From: Zichao Lin Date: Sun, 20 Jul 2025 06:52:30 +0800 Subject: [PATCH] fix: a lot of things --- main.py | 295 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 179 insertions(+), 116 deletions(-) diff --git a/main.py b/main.py index 649b15c..db16aeb 100644 --- a/main.py +++ b/main.py @@ -110,9 +110,9 @@ class GridTradingBot: side = order_response["side"] trade_type = "买入" if side == "BUY" else "卖出" - timestamp = datetime.fromtimestamp(order_response["updateTime"] / 1000).strftime( - "%Y-%m-%dT%H:%M" - ) + timestamp = datetime.fromtimestamp( + order_response["updateTime"] / 1000 + ).strftime("%Y-%m-%dT%H:%M") row = [ timestamp, @@ -182,7 +182,7 @@ class GridTradingBot: self.symbol, str(e), ) - raise + return self.api_get_price() def api_get_balances(self) -> Tuple[float, float]: """获取基础货币和报价货币的可用余额(不包括冻结金额)""" @@ -224,7 +224,7 @@ class GridTradingBot: logger.error( "[GridTradingBot.api_get_balances] Failed to get balances: %s", str(e) ) - raise + return self.api_get_balances() def calculate_order_value(self, price: float) -> float: """计算订单价值 (价格 * 数量)""" @@ -360,7 +360,7 @@ class GridTradingBot: price, str(e), ) - return None + return self.api_place_order(price, side) def api_cancel_order(self, order_id: str): """取消订单""" @@ -379,6 +379,7 @@ class GridTradingBot: order_id, str(e), ) + self.api_cancel_order(order_id) def api_cancel_all_orders(self): """取消所有活跃订单""" @@ -388,15 +389,19 @@ class GridTradingBot: ) try: self.api_trade.delete_openorders({"symbol": self.symbol}) + self.active_orders.clear() logger.info( "[GridTradingBot.api_cancel_all_orders] Successfully canceled all open orders for %s", self.symbol, ) + self.current_buy_levels = 0 + self.current_sell_levels = 0 except Exception as e: logger.error( "[GridTradingBot.api_cancel_all_orders] Failed to cancel all open orders: %s", str(e), ) + self.api_cancel_all_orders() def api_update_order_statuses(self): """更新所有活跃订单的状态""" @@ -453,6 +458,7 @@ class GridTradingBot: order_id, str(e), ) + self.api_update_order_statuses() def get_active_orders_by_side(self, side: str) -> List[Order]: """获取指定方向的所有活跃订单""" @@ -500,7 +506,7 @@ class GridTradingBot: market_price, ) - # 初始下单:买1和卖1 + # 初始下单: 买1和卖1 buy_price = self.calculate_grid_price(market_price, 1, "BUY") sell_price = self.calculate_grid_price(market_price, 1, "SELL") logger.custom_debug( @@ -593,14 +599,13 @@ class GridTradingBot: self.reserve_base, ) - for _ in range(1, self.grid_count): - self.extend_grid() + self.extend_grid() except Exception as e: logger.error( "[GridTradingBot.initialize_grid] Failed to initialize grid: %s", str(e) ) - raise + self.initialize_grid() def extend_grid(self): """扩展网格,保证两侧都有指定个数的挂单""" @@ -613,11 +618,23 @@ class GridTradingBot: ) try: + # 如果两侧都没有挂单 (如: 插针) 则重启机器人 lowest_buy, highest_sell = self.get_extreme_prices() - base_balance, quote_balance = self.api_get_balances() + if lowest_buy is None and highest_sell is None: + self.stop() + self.run() # 扩展买单网格 (向下) - if lowest_buy is not None and self.current_buy_levels < self.grid_count: + while self.current_buy_levels < self.grid_count: + lowest_buy, highest_sell = self.get_extreme_prices() + base_balance, quote_balance = self.api_get_balances() + if lowest_buy is None: + lowest_buy = self.calculate_grid_price( + highest_sell, self.grid_count, "BUY" + ) + logger.custom_debug( + "[GridTradingBot.extend_grid] lowest_buy was None, calculating based on highest_sell" + ) new_buy_price = self.calculate_grid_price(lowest_buy, 1, "BUY") logger.custom_debug( "[GridTradingBot.extend_grid] Extending buy grid - current lowest: %f, new price: %f", @@ -656,15 +673,26 @@ class GridTradingBot: new_buy_price * self.order_amount, self.min_order_value, ) + break else: logger.error( "[GridTradingBot.extend_grid] Insufficient quote balance for extended buy: %f <= %f", quote_balance, self.reserve_quote, ) + break # 扩展卖单网格 (向上) - if highest_sell is not None and self.current_sell_levels < self.grid_count: + while self.current_sell_levels < self.grid_count: + lowest_buy, highest_sell = self.get_extreme_prices() + base_balance, quote_balance = self.api_get_balances() + if highest_sell is None: + highest_sell = self.calculate_grid_price( + lowest_buy, self.grid_count, "SELL" + ) + logger.custom_debug( + "[GridTradingBot.extend_grid] highest_sell was None, calculating based on lowest_buy" + ) new_sell_price = self.calculate_grid_price(highest_sell, 1, "SELL") logger.custom_debug( "[GridTradingBot.extend_grid] Extending sell grid - current highest: %f, new price: %f", @@ -703,26 +731,28 @@ class GridTradingBot: new_sell_price * self.order_amount, self.min_order_value, ) + break else: logger.error( "[GridTradingBot.extend_grid] Insufficient base balance for extended sell: %f <= %f", base_balance, self.reserve_base, ) + break except Exception as e: logger.error( "[GridTradingBot.extend_grid] Failed to extend grid: %s", str(e) ) - raise + self.extend_grid() - def adjust_grid(self): - """调整网格 - 优化后的对称逻辑: - 买单成交时: + def adjust_grid_for_filled(self): + """调整网格 - 优化后的对称逻辑: + 买单成交时: 1. 取消最高价卖单 2. 在卖单侧挂一个更低价的卖单(卖0) 3. 在买单侧挂一个更低价的买单(买n) - 卖单成交时: + 卖单成交时: 1. 取消最低价买单 2. 在买单侧挂一个更高价的买单(买0) 3. 在卖单侧挂一个更高价的卖单(卖n)""" @@ -741,113 +771,145 @@ class GridTradingBot: if order.order_id in current_order_ids and order.status == "FILLED" ] - if not newly_filled_orders: + if newly_filled_orders: logger.custom_debug( - "[GridTradingBot.adjust_grid] No newly filled orders found" + "[GridTradingBot.adjust_grid] Newly filled orders found" ) - return - - # 处理每个新成交的订单 - for filled_order in newly_filled_orders: - filled_side = filled_order.side - filled_price = filled_order.price - filled_id = filled_order.order_id - self.active_orders.pop(filled_id, None) - logger.info( - "[GridTradingBot.adjust_grid] Processing newly filled %s order at price %f", - filled_side, - filled_price, - ) - - # 获取当前活跃订单 - active_buys = [ - o - for o in self.active_orders.values() - if o.side == "BUY" and o.status == "NEW" - ] - active_sells = [ - o - for o in self.active_orders.values() - if o.side == "SELL" and o.status == "NEW" - ] - - if filled_side == "BUY" and active_sells: - # 买单成交时的处理逻辑 - self.current_buy_levels -= 1 - # 1. 取消最高价卖单 - highest_sell = max(active_sells, key=lambda x: x.price) - self.api_cancel_order(highest_sell.order_id) - self.active_orders.pop(highest_sell.order_id, None) + # 处理每个新成交的订单 + for filled_order in newly_filled_orders: + filled_side = filled_order.side + filled_price = filled_order.price + filled_id = filled_order.order_id + self.active_orders.pop(filled_id, None) logger.info( - "[GridTradingBot.adjust_grid] Cancelled highest SELL order at %f (order_id: %s)", - highest_sell.price, - highest_sell.order_id, + "[GridTradingBot.adjust_grid] Processing newly filled %s order at price %f", + filled_side, + filled_price, ) - # 2. 在卖单侧挂一个更低价的卖单(卖0) - # 使用最近成交的买单价格作为基准 - new_sell_price = self.calculate_grid_price(filled_price, 1, "SELL") - # 检查余额和订单价值 - base_balance, _ = self.api_get_balances() - if base_balance > self.reserve_base and self.is_order_value_valid( - new_sell_price - ): - sell_order_id = self.api_place_order(new_sell_price, "SELL") - if sell_order_id: - self.active_orders[sell_order_id] = Order( - order_id=sell_order_id, - price=new_sell_price, - quantity=self.order_amount, - side="SELL", - status="NEW", - ) - logger.info( - "[GridTradingBot.adjust_grid] Placed new lower SELL order at %f (order_id: %s)", - new_sell_price, - sell_order_id, - ) - elif filled_side == "SELL" and active_buys: - # 卖单成交时的处理逻辑 - self.current_sell_levels -= 1 - # 1. 取消最低价买单 - lowest_buy = min(active_buys, key=lambda x: x.price) - self.api_cancel_order(lowest_buy.order_id) - self.active_orders.pop(lowest_buy.order_id, None) + # 获取当前活跃订单 + active_buys = [ + o + for o in self.active_orders.values() + if o.side == "BUY" and o.status == "NEW" + ] + active_sells = [ + o + for o in self.active_orders.values() + if o.side == "SELL" and o.status == "NEW" + ] - logger.info( - "[GridTradingBot.adjust_grid] Cancelled lowest BUY order at %f (order_id: %s)", - lowest_buy.price, - lowest_buy.order_id, - ) - # 2. 在买单侧挂一个更高价的买单(买0) - # 使用最近成交的卖单价格作为基准 - new_buy_price = self.calculate_grid_price(filled_price, 1, "BUY") - # 检查余额和订单价值 - _, quote_balance = self.api_get_balances() - if ( - quote_balance > self.reserve_quote - and self.is_order_value_valid(new_buy_price) - ): - buy_order_id = self.api_place_order(new_buy_price, "BUY") - if buy_order_id: - self.active_orders[buy_order_id] = Order( - order_id=buy_order_id, - price=new_buy_price, - quantity=self.order_amount, - side="BUY", - status="NEW", - ) - logger.info( - "[GridTradingBot.adjust_grid] Placed new higher BUY order at %f (order_id: %s)", - new_buy_price, - buy_order_id, - ) + if filled_side == "BUY": + self.current_buy_levels -= 1 + elif filled_side == "SELL": + self.current_sell_levels -= 1 + if filled_side == "BUY" and active_sells: + # 买单成交时的处理逻辑 + # 1. 取消最高价卖单 + highest_sell = max(active_sells, key=lambda x: x.price) + self.api_cancel_order(highest_sell.order_id) + self.active_orders.pop(highest_sell.order_id, None) + logger.info( + "[GridTradingBot.adjust_grid] Cancelled highest SELL order at %f (order_id: %s)", + highest_sell.price, + highest_sell.order_id, + ) + # 2. 在卖单侧挂一个更低价的卖单(卖0) + # 使用最近成交的买单价格作为基准 + new_sell_price = self.calculate_grid_price( + filled_price, 1, "SELL" + ) + # 检查余额和订单价值 + base_balance, _ = self.api_get_balances() + if ( + base_balance > self.reserve_base + and self.is_order_value_valid(new_sell_price) + ): + sell_order_id = self.api_place_order(new_sell_price, "SELL") + if sell_order_id: + self.active_orders[sell_order_id] = Order( + order_id=sell_order_id, + price=new_sell_price, + quantity=self.order_amount, + side="SELL", + status="NEW", + ) + logger.info( + "[GridTradingBot.adjust_grid] Placed new lower SELL order at %f (order_id: %s)", + new_sell_price, + sell_order_id, + ) + elif filled_side == "SELL" and active_buys: + # 卖单成交时的处理逻辑 + # 1. 取消最低价买单 + lowest_buy = min(active_buys, key=lambda x: x.price) + self.api_cancel_order(lowest_buy.order_id) + self.active_orders.pop(lowest_buy.order_id, None) + + logger.info( + "[GridTradingBot.adjust_grid] Cancelled lowest BUY order at %f (order_id: %s)", + lowest_buy.price, + lowest_buy.order_id, + ) + # 2. 在买单侧挂一个更高价的买单(买0) + # 使用最近成交的卖单价格作为基准 + new_buy_price = self.calculate_grid_price( + filled_price, 1, "BUY" + ) + # 检查余额和订单价值 + _, quote_balance = self.api_get_balances() + if ( + quote_balance > self.reserve_quote + and self.is_order_value_valid(new_buy_price) + ): + buy_order_id = self.api_place_order(new_buy_price, "BUY") + if buy_order_id: + self.active_orders[buy_order_id] = Order( + order_id=buy_order_id, + price=new_buy_price, + quantity=self.order_amount, + side="BUY", + status="NEW", + ) + logger.info( + "[GridTradingBot.adjust_grid] Placed new higher BUY order at %f (order_id: %s)", + new_buy_price, + buy_order_id, + ) except Exception as e: logger.error( "[GridTradingBot.adjust_grid] Failed to adjust grid: %s", str(e) ) - raise + self.adjust_grid_for_filled() + + def adjust_grid_for_violation(self): + try: + market_price = self.api_get_price() + lowest_buy, highest_sell = self.get_extreme_prices() + if lowest_buy is None and market_price < self.calculate_grid_price( + highest_sell, self.grid_count + 1, "BUY" + ): + logger.warning( + "[GridTradingBot.adjust_grid_for_violation] Price varied too low, restarting grid." + ) + self.api_cancel_all_orders() + self.initialize_grid() + elif highest_sell is None and market_price > self.calculate_grid_price( + lowest_buy, self.grid_count + 1, "SELL" + ): + logger.warning( + "[GridTradingBot.adjust_grid_for_violation] Price varied too high, restarting grid." + ) + self.api_cancel_all_orders() + self.initialize_grid() + + except Exception as e: + logger.error( + "[GridTradingBot.adjust_grid_for_violation] Failed to adjust grid: %s", + str(e), + ) + self.adjust_grid_for_violation() def run(self): """运行网格交易机器人""" @@ -871,7 +933,8 @@ class GridTradingBot: self.api_update_order_statuses() # 调整网格 - self.adjust_grid() + self.adjust_grid_for_filled() + self.adjust_grid_for_violation() # 尝试扩展网格 self.extend_grid() @@ -885,7 +948,7 @@ class GridTradingBot: except Exception as e: logger.error("[GridTradingBot.run] Error in main loop: %s", str(e)) - sleep_time = 3 + sleep_time = 1 logger.custom_debug( "[GridTradingBot.run] Error occurred, sleeping for %d seconds", sleep_time,