From 82c081a8e710f91eeec47a64069f21a4835d811f Mon Sep 17 00:00:00 2001 From: cgit Date: Sat, 22 Nov 2025 18:52:07 +0800 Subject: [PATCH] aaa --- .gitignore | 2 + ccxt/async_support/mt5_bak.py | 316 ---------------------------------- ccxt/pro/mt5_bak.py | 312 --------------------------------- 3 files changed, 2 insertions(+), 628 deletions(-) create mode 100644 .gitignore delete mode 100644 ccxt/async_support/mt5_bak.py delete mode 100644 ccxt/pro/mt5_bak.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..edd9d60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +dist/ diff --git a/ccxt/async_support/mt5_bak.py b/ccxt/async_support/mt5_bak.py deleted file mode 100644 index 1e44995..0000000 --- a/ccxt/async_support/mt5_bak.py +++ /dev/null @@ -1,316 +0,0 @@ -# -*- coding: utf-8 -*- - -# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN: -# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code - -from ccxt.async_support.base.exchange import Exchange -from ccxt.abstract.mt5 import ImplicitAPI -import asyncio -import hashlib -from ccxt.base.types import Any, Balances, DepositAddress, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, OrderBooks, Trade, TradingFees, Transaction -from typing import List -from ccxt.base.errors import ExchangeError -from ccxt.base.errors import AuthenticationError -from ccxt.base.errors import ArgumentsRequired -from ccxt.base.errors import InsufficientFunds -from ccxt.base.errors import InvalidOrder -from ccxt.base.errors import OrderNotFound -from ccxt.base.errors import DDoSProtection -from ccxt.base.errors import RateLimitExceeded -from ccxt.base.errors import ExchangeNotAvailable -from ccxt.base.errors import InvalidNonce -from ccxt.base.decimal_to_precision import TICK_SIZE -from ccxt.base.precise import Precise - - -class mt5(Exchange, ImplicitAPI): - def describe(self) -> Any: - return self.deep_extend(super(mt5, self).describe(), { - 'id': 'mt5', - 'name': 'MT5', - 'countries': ['US'], - 'version': 'v2025.02.05-05.23', - 'rateLimit': 1000, - 'hostname': '43.167.188.220:5000', - 'pro': True, - 'options': { - 'host': '18.163.85.196', - 'port': 443, - }, - 'has': { - 'CORS': True, - 'spot': True, - 'margin': True, - 'swap': True, - 'future': True, - 'option': True, - 'borrowCrossMargin': True, - 'cancelAllOrders': True, - 'cancelAllOrdersAfter': True, - 'cancelOrder': True, - 'cancelOrders': True, - 'cancelOrdersForSymbols': True, - 'closeAllPositions': False, - 'closePosition': False, - 'createConvertTrade': True, - 'createMarketBuyOrderWithCost': True, - 'createMarketSellOrderWithCost': True, - 'createOrder': True, - 'createOrders': True, - 'createOrderWithTakeProfitAndStopLoss': True, - 'createPostOnlyOrder': True, - 'createReduceOnlyOrder': True, - 'createStopLimitOrder': True, - 'createStopLossOrder': True, - 'createStopMarketOrder': True, - 'createStopOrder': True, - 'createTakeProfitOrder': True, - 'createTrailingAmountOrder': True, - 'createTriggerOrder': True, - 'editOrder': True, - 'editOrders': True, - 'fetchAllGreeks': True, - 'fetchBalance': True, - 'fetchBidsAsks': 'emulated', - 'fetchBorrowInterest': False, # temporarily disabled, doesn't work - 'fetchBorrowRateHistories': False, - 'fetchBorrowRateHistory': False, - 'fetchCanceledAndClosedOrders': True, - 'fetchCanceledOrders': True, - 'fetchClosedOrder': True, - 'fetchClosedOrders': True, - 'fetchConvertCurrencies': True, - 'fetchConvertQuote': True, - 'fetchConvertTrade': True, - 'fetchConvertTradeHistory': True, - 'fetchCrossBorrowRate': True, - 'fetchCrossBorrowRates': False, - 'fetchCurrencies': True, - 'fetchDeposit': False, - 'fetchDepositAddress': True, - 'fetchDepositAddresses': False, - 'fetchDepositAddressesByNetwork': True, - 'fetchDeposits': True, - 'fetchDepositWithdrawFee': 'emulated', - 'fetchDepositWithdrawFees': True, - 'fetchFundingHistory': True, - 'fetchFundingRate': 'emulated', # emulated in exchange - 'fetchFundingRateHistory': True, - 'fetchFundingRates': True, - 'fetchGreeks': True, - 'fetchIndexOHLCV': True, - 'fetchIsolatedBorrowRate': False, - 'fetchIsolatedBorrowRates': False, - 'fetchLedger': True, - 'fetchLeverage': True, - 'fetchLeverageTiers': True, - 'fetchLongShortRatio': False, - 'fetchLongShortRatioHistory': True, - 'fetchMarginAdjustmentHistory': False, - 'fetchMarketLeverageTiers': True, - 'fetchMarkets': True, - 'fetchMarkOHLCV': True, - 'fetchMyLiquidations': True, - 'fetchMySettlementHistory': True, - 'fetchMyTrades': True, - 'fetchOHLCV': True, - 'fetchOpenInterest': True, - 'fetchOpenInterestHistory': True, - 'fetchOpenOrder': True, - 'fetchOpenOrders': True, - 'fetchOption': True, - 'fetchOptionChain': True, - 'fetchOrder': True, - 'fetchOrderBook': True, - 'fetchOrders': False, - 'fetchOrderTrades': True, - 'fetchPosition': True, - 'fetchPositionHistory': 'emulated', - 'fetchPositions': True, - 'fetchPositionsHistory': True, - 'fetchPremiumIndexOHLCV': True, - 'fetchSettlementHistory': True, - 'fetchTicker': True, - 'fetchTickers': True, - 'fetchTime': True, - 'fetchTrades': True, - 'fetchTradingFee': True, - 'fetchTradingFees': True, - 'fetchTransactions': False, - 'fetchTransfers': True, - 'fetchUnderlyingAssets': False, - 'fetchVolatilityHistory': True, - 'fetchWithdrawals': True, - 'repayCrossMargin': True, - 'sandbox': True, - 'setLeverage': True, - 'setMarginMode': True, - 'setPositionMode': True, - 'transfer': True, - 'withdraw': True, - }, - 'timeframes': { - '1m': 1, - '5m': 5, - '15m': 15, - '30m': 30, - '1h': 60, - '4h': 240, - '1d': 1440, - '1w': 10080, - '1M': 43200, - }, - 'urls': { - 'logo': '', - 'api': { - 'public': 'http://{hostname}', - 'private': 'http://{hostname}', - }, - 'www': 'http://{hostname}', - 'doc': ['http://{hostname}/index.html'], - }, - 'api': { - 'public': { - 'get': { - 'Ping': 1 - }, - }, - 'private': { - 'get': { - 'Connect': 10, - 'CheckConnect': 1, - 'Disconnect': 1, - 'Symbols': 1, - 'ServerTimezone':1, - 'AccountSummary': 1, - 'AccountDetails': 1, - 'SymbolList': 1, - 'GetQuote': 1, - 'GetQuoteMany': 1, - 'MarketWatchMany': 1, - 'OpenedOrders': 1, - 'ClosedOrders': 1, - 'OpenedOrder': 1, - 'OrderHistory': 1, - 'PriceHistory': 1, - 'OrderSend': 1, - 'OrderModify': 1, - 'OrderClose': 1, - }, - }, - 'wsEndpoint': { - 'order': "OnOrderUpdate", - 'quote': "OnQuote", - 'orderbook': "OnOrderBook", - } - }, - 'requiredCredentials': { - 'apiKey': True, - 'secret': True, - 'hostname': True, - }, - 'commonCurrencies': {}, - 'exceptions': { - 'exact': { - 'Invalid token': AuthenticationError, - 'Connection failed': ExchangeError, - 'Invalid symbol': ExchangeError, - 'Invalid order': InvalidOrder, - 'Order not found': OrderNotFound, - }, - }, - }) - - - async def get_token(self): - """获取或刷新 token - 异步版本""" - if self.token and self.token_checked: - try: - await self.check_connect() - return self.token - except Exception: - # Token 无效,重新连接 - pass - - # 重新连接获取 token - return await self.connect() - - async def connect(self): - """连接到 MT5 账户并获取 token - 异步版本""" - request = { - 'user': self.apiKey, - 'password': self.secret, - 'host': self.options['host'], - 'port': self.options['port'], - 'connectTimeoutSeconds': 30, - } - - print(f"🔧 Debug: Connect request params: {request}") - - response = await self.private_get_connect(request) - - print(f"🔧 Debug: Connect response: {response}") - - self.token = response - self.token_checked = True - return self.token - - async def check_connect(self): - """检查连接状态 - 异步版本""" - request = { - 'id': await self.get_token(), - } - return await self.private_get_check_connect(request) - - - async def fetch_markets(self, params={}): - """获取交易对列表""" - - if not self.token: - await self.get_token() - request = { - 'id': self.token, - } - response = await self.private_get_symbols(self.deep_extend(request, params)) - - markets = [] - if isinstance(response, dict): - for symbol, info in response.items(): - market = self.parse_market(info) - if market: - markets.append(market) - - return markets - - def parse_market(self, info): - """解析市场信息 - 根据 SymbolInfo 结构修正""" - symbol = info.get('currency', '').upper() - if not symbol: - return None - - return { - 'id': symbol, - 'symbol': symbol, - 'base': symbol[:3] if len(symbol) >= 6 else symbol, - 'quote': symbol[3:] if len(symbol) >= 6 else 'USD', - 'active': True, - 'precision': { - 'price': info.get('digits', 5), - 'amount': 2, - }, - 'limits': { - 'amount': { - 'min': 0.01, - 'max': None, - }, - 'price': { - 'min': None, - 'max': None, - }, - 'cost': { - 'min': None, - 'max': None, - }, - }, - 'info': info, - } diff --git a/ccxt/pro/mt5_bak.py b/ccxt/pro/mt5_bak.py deleted file mode 100644 index 1e1589a..0000000 --- a/ccxt/pro/mt5_bak.py +++ /dev/null @@ -1,312 +0,0 @@ -# -*- coding: utf-8 -*- - -from ccxt.async_support.mt5 import mt5 as mt5Parent -from ccxt.base.errors import ExchangeError, ArgumentsRequired -from ccxt.async_support.base.ws.client import Client -import asyncio -from typing import Optional, Dict, Any, List - - -class mt5(mt5Parent): - def describe(self): - return self.deep_extend(super(mt5, self).describe(), { - 'platinum': True, - 'hostname': '43.167.188.220:5000', - 'has': { - # 专业版特有功能 - 'watchPosition': True, - 'watchOrder': True, - 'watchLeverage': True, - 'watchMargin': True, - 'advancedAPI': True, - 'batchOrders': True, - 'modifyOrder': True, - 'closePosition': True, - 'setLeverage': True, - 'setMargin': True, - }, - 'urls': { - 'api': { - 'ws': 'ws://{hostname}', - }, - }, - 'options': { - 'defaultType': 'spot', - 'watchOrder': { - 'symbol': None, - 'orderId': None, - }, - 'watchPosition': { - 'symbol': None, - }, - }, - }) - - - - - # 专业版特有方法 - async def watch_order(self, params={}): - """ - 监听特定订单的更新(专业版特有) - """ - - if not self.token: - await self.get_token() - - try: - await self.load_markets() - except Exception as e: - print(f"错误: {e}") - - # await self.fetch_markets() - - # return - request: dict = { - 'id': self.token, - } - endpoint = self.api['wsEndpoint']['order'] - url = self.implode_hostname(self.urls['api']['ws']) + '/' + endpoint - url += '?' + self.urlencode(request) - return await self.watch(url,'order_position') - - def handle_message(self, client: Client, message): - # print(message) - errorCode = self.safe_string(message, 'errorCode') - if errorCode is not None: - self.handle_error_message(client, message) - return - - # 处理 MT5 特定的消息 - message_type = self.safe_string(message, 'type') - - - if message_type == 'OpenedOrders': - print("111111111111111") - self.handle_opened_orders(client, message) - elif message_type == self.api['wsEndpoint']['orderbook']: - self.handle_orderbook(client, message) - elif message_type == self.api['wsEndpoint']['quote']: - self.handle_ticker(client, message) - - def handle_opened_orders(self, client, message): - """ - 处理 OpenedOrders 消息 - """ - orders_data = self.safe_value(message, 'data', []) - message_id = self.safe_string(message, 'id') - timestamp = self.safe_integer(message, 'timestampUTC') - parsed_orders = [] - for order_data in orders_data: - # 解析每个订单 - order = self.parse_ws_order(order_data) - parsed_orders.append(order) - - # 分发到不同的消息流 - order_id = order['id'] - symbol = order['symbol'] - - # 更新特定订单 - client.resolve(order, 'order:' + order_id) - - # 更新符号特定的订单列表 - client.resolve([order], 'orders:' + symbol) - - print('-------------parsed_orders:',parsed_orders) - # 更新所有订单列表 - client.resolve(parsed_orders, 'orders') - - # 如果有请求ID,也解析到该请求 - if message_id: - client.resolve(parsed_orders, 'request:' + message_id) - - def handle_orderbook(self, client, message): - """处理深度数据""" - orderbook = self.parse_ws_order_book(message) - symbol = orderbook['symbol'] - message_hash = 'orderbook:' + symbol - client.resolve(orderbook, message_hash) - - def parse_ws_order(self, order, market=None): - """ - 解析 MT5 WebSocket 订单数据为 CCXT 标准格式 - """ - # 提取订单基本信息 - ticket = self.safe_integer(order, 'ticket') - symbol = self.safe_string(order, 'symbol') - order_type = self.safe_string(order, 'orderType') - deal_type = self.safe_string(order, 'dealType') - state = self.safe_string(order, 'state') - lots = self.safe_number(order, 'lots') - contract_size = self.safe_number(order, 'contractSize', 1.0) - open_price = self.safe_number(order, 'openPrice') - close_price = self.safe_number(order, 'closePrice') - profit = self.safe_number(order, 'profit') - print("ggeggegge========") - # 获取市场信息 - market = self.market(symbol) if market is None else market - - # 解析时间戳 - open_time_str = self.safe_string(order, 'openTime') - open_timestamp = self.safe_integer(order, 'openTimestampUTC') - - # 如果 openTimestampUTC 不存在,尝试解析 openTime 字符串 - if open_timestamp is None and open_time_str: - try: - # 解析格式: "2025-11-15T04:06:06.994" - open_timestamp = self.parse8601(open_time_str) - except: - open_timestamp = None - - # 解析订单状态 - status = self.parse_order_status(state) - - # 解析订单方向 - side = self.parse_order_side(order_type, deal_type) - - # 解析订单类型 - order_type_parsed = self.parse_order_type(order_type) - - # 计算数量 (lots * contractSize) - amount = lots * contract_size if (lots is not None and contract_size is not None) else None - - # 解析成交数量 - volume = self.safe_integer(order, 'volume', 0) - close_volume = self.safe_integer(order, 'closeVolume', 0) - - # 对于已成交订单,filled 应该是 volume - filled = volume - remaining = 0 # MT5 中订单要么完全成交,要么没有 - - # 解析止盈止损 - stop_loss = self.safe_number(order, 'stopLoss') - take_profit = self.safe_number(order, 'takeProfit') - - # 构建标准订单对象 - result = { - 'id': str(ticket), - 'clientOrderId': None, - 'datetime': self.iso8601(open_timestamp) if open_timestamp else None, - 'timestamp': open_timestamp, - 'lastTradeTimestamp': None, - 'status': status, - 'symbol': market['symbol'] if market else symbol, - 'type': order_type_parsed, - 'side': side, - 'price': open_price, - 'amount': amount, - 'filled': filled, - 'remaining': remaining, - 'cost': None, # 可以计算: amount * price - 'average': None, - 'fee': { - 'currency': market['quote'] if market else 'USD', - 'cost': self.safe_number(order, 'fee', 0), - }, - 'trades': None, - 'info': order, - } - - # 计算成本 - if amount is not None and open_price is not None: - result['cost'] = amount * open_price - - # 添加 MT5 特定字段 - result['stopLoss'] = stop_loss - result['takeProfit'] = take_profit - result['profit'] = profit - result['commission'] = self.safe_number(order, 'commission', 0) - result['swap'] = self.safe_number(order, 'swap', 0) - result['comment'] = self.safe_string(order, 'comment', '') - print("-----------result:",result) - return result - - def parse_order_status(self, status): - """ - 解析 MT5 订单状态 - """ - statuses = { - 'Filled': 'closed', # 已成交 - 'PartialFilled': 'open', # 部分成交 - 'Pending': 'open', # 挂单中 - 'Cancelled': 'canceled', # 已取消 - 'Rejected': 'rejected', # 已拒绝 - 'Expired': 'expired', # 已过期 - # 根据您的数据添加更多状态映射 - 'Active': 'open', - 'Closed': 'closed', - } - return self.safe_string(statuses, status, status.lower() if status else 'unknown') - - def parse_order_side(self, order_type, deal_type): - """ - 解析订单方向 - """ - # 优先使用 deal_type,因为它更准确 - if deal_type: - if 'Buy' in deal_type: - return 'buy' - elif 'Sell' in deal_type: - return 'sell' - - # 其次使用 order_type - if order_type: - if order_type == 'Buy': - return 'buy' - elif order_type == 'Sell': - return 'sell' - elif 'Buy' in order_type: - return 'buy' - elif 'Sell' in order_type: - return 'sell' - - return 'unknown' - - def parse_order_type(self, order_type): - """ - 解析订单类型 - """ - if not order_type: - return 'market' # 默认类型 - - order_type_lower = order_type.lower() - - if 'limit' in order_type_lower: - return 'limit' - elif 'stop' in order_type_lower: - return 'stop' - elif 'market' in order_type_lower: - return 'market' - else: - # 根据 dealType 判断 - return 'market' # 默认为市价单 - - def sign(self, path, api='public', method='GET', params={}, headers=None, body=None): - """签名请求 URL 构建""" - endpoint = '/' + self.implode_params(path, params) - url = self.implode_hostname(self.urls['api'][api]) + endpoint - headers = headers if (headers is not None) else {} - - # 对于 GET 请求,将参数添加到查询字符串 - if method == 'GET' and params: - # 特殊处理数组参数 - query_params = {} - for key, value in params.items(): - if isinstance(value, list): - # 对于数组参数,可能需要特殊编码 - query_params[key] = ','.join(value) - else: - query_params[key] = value - - url += '?' + self.urlencode(query_params) - elif method == 'GET' and params: - url += '?' + self.urlencode(params) - - # print(f"🔧 Debug: Final URL: {url}") - - return { - 'url': url, - 'method': method, - 'body': body, - 'headers': headers - }