From a630c42ddde03778f22188627282785f623f15ed Mon Sep 17 00:00:00 2001 From: lz_db Date: Sun, 30 Nov 2025 11:19:39 +0800 Subject: [PATCH] up --- ccxt/async_support/mt5.py | 27 +++++++++++++++++++-------- ccxt/mt5.py | 25 +++++++++++++++++-------- ccxt/pro/mt5.py | 27 ++++++++++++++++++++++----- test/test_mt5_tools.py | 21 ++++++++++----------- 4 files changed, 68 insertions(+), 32 deletions(-) diff --git a/ccxt/async_support/mt5.py b/ccxt/async_support/mt5.py index 0a40b0f..f2ed909 100644 --- a/ccxt/async_support/mt5.py +++ b/ccxt/async_support/mt5.py @@ -766,6 +766,8 @@ class mt5(Exchange, ImplicitAPI): timestamp = self.parse8601(self.safe_string(order, 'openTime')) last_trade_timestamp = self.parse8601(self.safe_string(order, 'closeTime')) + if last_trade_timestamp is None: + last_trade_timestamp = timestamp status = self.parse_order_status(self.safe_string(order, 'state')) side = self.parse_order_side(self.safe_string(order, 'orderType')) @@ -796,7 +798,7 @@ class mt5(Exchange, ImplicitAPI): return self.safe_order({ 'id': id, - 'clientOrderId': None, + 'clientOrderId': self.safe_string(order, 'comment'), 'datetime': self.iso8601(timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': last_trade_timestamp, @@ -836,13 +838,22 @@ class mt5(Exchange, ImplicitAPI): def parse_order_status(self, status): statuses = { - 'Started': 'open', - 'Placed': 'open', - 'Cancelled': 'canceled', - 'Partial': 'open', - 'Filled': 'closed', - 'Rejected': 'rejected', - 'Expired': 'expired', + # MT5 状态 -> CCXT 标准状态 + 'Started': 'open', # 订单已开始 + 'Placed': 'open', # 订单已放置 + 'RequestAdding': 'pending', # 请求添加订单(待处理) + 'RequestModifying': 'pending', # 请求修改订单(待处理) + 'RequestCancelling': 'pending', # 请求取消订单(待处理) + 'Partial': 'open', # 订单部分成交(仍可继续成交) + 'Filled': 'closed', # 订单完全成交 + 'Cancelled': 'canceled', # 订单已取消 + 'Rejected': 'rejected', # 订单被拒绝 + 'Expired': 'expired', # 订单已过期 + # 备用映射 + 'New': 'open', + 'Active': 'open', + 'Done': 'closed', + 'Canceled': 'canceled', } return self.safe_string(statuses, status, status) diff --git a/ccxt/mt5.py b/ccxt/mt5.py index 19cb036..7121706 100644 --- a/ccxt/mt5.py +++ b/ccxt/mt5.py @@ -803,7 +803,7 @@ class mt5(Exchange, ImplicitAPI): return self.safe_order({ 'id': id, - 'clientOrderId': None, + 'clientOrderId': self.safe_string(order, 'comment'), 'datetime': self.iso8601(timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': last_trade_timestamp, @@ -835,13 +835,22 @@ class mt5(Exchange, ImplicitAPI): def parse_order_status(self, status): statuses = { - 'Started': 'open', - 'Placed': 'open', - 'Cancelled': 'canceled', - 'Partial': 'open', - 'Filled': 'closed', - 'Rejected': 'rejected', - 'Expired': 'expired', + # MT5 状态 -> CCXT 标准状态 + 'Started': 'open', # 订单已开始 + 'Placed': 'open', # 订单已放置 + 'RequestAdding': 'pending', # 请求添加订单(待处理) + 'RequestModifying': 'pending', # 请求修改订单(待处理) + 'RequestCancelling': 'pending', # 请求取消订单(待处理) + 'Partial': 'open', # 订单部分成交(仍可继续成交) + 'Filled': 'closed', # 订单完全成交 + 'Cancelled': 'canceled', # 订单已取消 + 'Rejected': 'rejected', # 订单被拒绝 + 'Expired': 'expired', # 订单已过期 + # 备用映射 + 'New': 'open', + 'Active': 'open', + 'Done': 'closed', + 'Canceled': 'canceled', } return self.safe_string(statuses, status, status) diff --git a/ccxt/pro/mt5.py b/ccxt/pro/mt5.py index 8a21d95..d448b5f 100644 --- a/ccxt/pro/mt5.py +++ b/ccxt/pro/mt5.py @@ -382,6 +382,7 @@ class mt5(mt5Parent): update_data = self.safe_value(data, 'update', {}) order_data = self.safe_value(update_data, 'order') if order_data: + order_data['update_type'] = self.safe_value(update_data, 'type', None) # 这个字段可以判断是开仓还是平仓 order = self.parse_ws_order(order_data) if order: # 使用简单的列表而不是 ArrayCacheBySymbolById @@ -601,7 +602,7 @@ class mt5(mt5Parent): """解析单个订单数据""" if not order_data: return None - + # print("++++++",order_data) try: symbol = self.safe_string(order_data, 'symbol') if symbol and len(symbol) >= 6: @@ -621,17 +622,33 @@ class mt5(mt5Parent): if timestamp is None: timestamp = self.milliseconds() - last_trade_timestamp = None + last_trade_timestamp = timestamp if is_closed: last_trade_timestamp = self.parse8601(close_time) + mt5_order_type = self.safe_string(order_data, 'update_type', None) + amount = self.safe_number(order_data, 'lots', 0) filled = self.safe_number(order_data, 'closeLots', 0) + price = self.safe_number(order_data, 'openPrice') + side = self.parse_order_side(self.safe_string(order_data, 'orderType')) + + if mt5_order_type == 'MarketOpen': + amount = self.safe_number(order_data, 'lots', 0) + filled = self.safe_number(order_data, 'lots', 0) + elif mt5_order_type == 'MarketClose': + amount = self.safe_number(self.safe_dict(order_data, 'dealInternalIn', {}), 'lots', 0) + filled = self.safe_number(order_data, 'closeLots', 0) + price = self.safe_number(order_data, 'closePrice') + if side == 'buy': + side = 'sell' + else: + side = 'buy' remaining = max(amount - filled, 0) if amount is not None and filled is not None else None return { 'id': self.safe_string(order_data, 'ticket'), - 'clientOrderId': None, + 'clientOrderId': self.safe_string(order_data, 'comment'), 'datetime': self.iso8601(timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': last_trade_timestamp, @@ -641,8 +658,8 @@ class mt5(mt5Parent): 'type': self.parse_order_type(self.safe_string(order_data, 'orderType')), 'timeInForce': None, 'postOnly': None, - 'side': self.parse_order_side(self.safe_string(order_data, 'orderType')), - 'price': self.safe_number(order_data, 'openPrice'), + 'side': side, + 'price': price, 'stopLossPrice': self.safe_number(order_data, 'stopLoss'), 'takeProfitPrice': self.safe_number(order_data, 'takeProfit'), 'reduceOnly': None, diff --git a/test/test_mt5_tools.py b/test/test_mt5_tools.py index 762bdd8..6d9d00a 100644 --- a/test/test_mt5_tools.py +++ b/test/test_mt5_tools.py @@ -135,20 +135,19 @@ async def websocket_quick_test(): async def order_listener(): while True: # print("111111111") - res = await exchange.watch_ticker(symbol='BTCUSD') - logger.error("aaa") - logger.warning("bbb") - logger.debug("ccc") + res = await exchange.watch_orders() print("===========================收到信息") - print(res) + for order in res: + del order['info'] + logger.info(f"📦 订单更新: {order}") # for order in res: # logger.info(f"📦 订单更新: {order}") # 监听余额更新 - async def balance_listener(): - balance = await exchange.watch_balance() - total = sum([v for v in balance['total'].values() if v is not None]) - logger.info(f"💰 余额更新: 总余额 {total:.2f}") + # async def balance_listener(): + # balance = await exchange.watch_balance() + # total = sum([v for v in balance['total'].values() if v is not None]) + # logger.info(f"💰 余额更新: 总余额 {total:.2f}") # 运行监听器 await asyncio.gather( @@ -166,5 +165,5 @@ async def websocket_quick_test(): if __name__ == "__main__": # 运行快速测试 - asyncio.run(quick_order_test()) - # asyncio.run(websocket_quick_test()) \ No newline at end of file + # asyncio.run(quick_order_test()) + asyncio.run(websocket_quick_test()) \ No newline at end of file