fix: a lot of things
This commit is contained in:
295
main.py
295
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,
|
||||
|
Reference in New Issue
Block a user