This commit is contained in:
7LZL
2025-11-23 21:17:08 +08:00
parent 4e0af9402d
commit dd4d01c58a
2 changed files with 188 additions and 61 deletions

View File

@@ -177,28 +177,29 @@ class mt5(Exchange, ImplicitAPI):
self.token = None
async def fetch_markets(self, params={}):
"""获取交易对列表 - 异步修复版本"""
"""获取交易对列表 - 使用 SymbolParamsMany 接口"""
if not hasattr(self, 'token') or not self.token:
await self.get_token()
request = {
'id': self.token,
'limit': 10000, # 添加 limit 参数获取所有交易对
}
try:
response = await self.private_get_symbols(self.extend(request, params))
response = await self.private_get_symbolparamsmany(self.extend(request, params))
markets = []
if isinstance(response, dict):
for symbol, info in response.items():
if isinstance(response, list):
for symbol_data in response:
try:
market = self.parse_market(info)
market = self.parse_market(symbol_data)
if market and market.get('symbol'):
markets.append(market)
except Exception as e:
# 跳过解析失败的市场,继续处理其他市场
if self.verbose:
print(f"跳过交易对 {symbol}: {e}")
symbol_name = self.safe_string(symbol_data, 'symbol', 'unknown')
print(f"跳过交易对 {symbol_name}: {e}")
continue
# 设置市场数据
@@ -220,42 +221,72 @@ class mt5(Exchange, ImplicitAPI):
except Exception as e:
raise ExchangeError(f"获取市场数据失败: {e}")
def parse_market(self, info):
"""解析市场信息 - 更健壮的版本"""
def parse_market(self, symbol_data):
"""解析市场信息 - 根据新的数据格式"""
try:
# 安全获取 symbol
if not isinstance(info, dict):
if not isinstance(symbol_data, dict):
return None
symbol = self.safe_string(info, 'currency', '')
symbol = self.safe_string(symbol_data, 'symbol')
if not symbol:
return None
symbol = symbol.upper().strip()
symbol_info = self.safe_dict(symbol_data, 'symbolInfo', {})
symbol_group = self.safe_dict(symbol_data, 'symbolGroup', {})
# 解析基础信息
symbol_name = symbol.upper().strip()
# 确保符号格式正确 (如 EURUSD)
if len(symbol) < 6:
if len(symbol_name) < 6:
# 处理较短的符号
base = symbol
base = symbol_name
quote = 'USD' # 默认报价货币
else:
base = symbol[:3]
quote = symbol[3:]
base = symbol[:3]
quote = symbol[3:]
base = symbol_name[:3]
quote = symbol_name[3:]
# 安全处理精度
digits = self.safe_integer(info, 'digits', 5)
# 确保 digits 是整数
# 解析精度信息
digits = self.safe_integer(symbol_info, 'digits', 5)
if digits is not None:
try:
digits = int(digits)
except (ValueError, TypeError):
digits = 5
market_id = symbol
# 解析合约大小
contract_size = self.safe_number(symbol_info, 'contractSize', 100000)
# 解析交易量限制
min_volume = self.safe_number(symbol_group, 'minVolume', 0.01)
max_volume = self.safe_number(symbol_group, 'maxVolume', 100)
volume_step = self.safe_number(symbol_group, 'volumeStep', 0.01)
# 处理最小交易量单位转换
# 如果 minVolume 很大,可能是以合约单位表示,需要转换为手数
if min_volume > 1000: # 假设大于1000的是合约单位
min_volume = min_volume / contract_size if contract_size > 0 else 0.01
# 解析价格精度
points = self.safe_number(symbol_info, 'points', 0.00001)
price_precision = digits
# 解析保证金信息
initial_margin = self.safe_number(symbol_group, 'initialMargin', 0)
maintenance_margin = self.safe_number(symbol_group, 'maintenanceMargin', 0)
# 解析货币信息
profit_currency = self.safe_string(symbol_info, 'profitCurrency', 'USD')
margin_currency = self.safe_string(symbol_info, 'marginCurrency', base)
# 解析交易模式
trade_mode = self.safe_string(symbol_group, 'tradeMode', 'Disabled')
active = trade_mode != 'Disabled'
# 解析描述信息
description = self.safe_string(symbol_info, 'description', '')
market_id = symbol_name
return {
'id': market_id,
@@ -264,33 +295,61 @@ class mt5(Exchange, ImplicitAPI):
'quote': quote,
'baseId': base,
'quoteId': quote,
'active': True,
'active': active,
'type': 'spot',
'spot': True,
'margin': True,
'precision': {
'price': digits,
'amount': 2,
'price': price_precision,
'amount': 2, # 手数精度
'base': 2,
'quote': price_precision,
},
'limits': {
'amount': {
'min': self.safe_number(info, 'minVolume', 0.01),
'max': self.safe_number(info, 'maxVolume'),
'min': min_volume,
'max': max_volume,
},
'price': {
'min': None,
'min': points, # 最小价格变动
'max': None,
},
'cost': {
'min': None,
'max': None,
},
'leverage': {
'min': 1.0,
'max': self.safe_number(symbol_group, 'accountLeverage', 100.0),
}
},
'info': info,
'contractSize': contract_size,
'expiry': None,
'expiryDatetime': None,
'strike': None,
'optionType': None,
'taker': self.safe_number(symbol_group, 'commission', 0), # 可能需要调整
'maker': self.safe_number(symbol_group, 'commission', 0), # 可能需要调整
'percentage': True,
'tierBased': False,
'feeSide': 'quote',
'info': symbol_data,
'margin': {
'initial': initial_margin,
'maintenance': maintenance_margin,
},
'swap': {
'long': self.safe_number(symbol_group, 'swapLong', 0),
'short': self.safe_number(symbol_group, 'swapShort', 0),
},
'lotSize': volume_step,
'minNotional': None,
'maxNotional': None,
}
except Exception as e:
if self.verbose:
print(f"解析市场信息失败: {e}, info: {info}")
symbol_name = self.safe_string(symbol_data, 'symbol', 'unknown')
print(f"解析市场信息失败 {symbol_name}: {e}")
return None
async def server_timezone(self):

View File

@@ -209,25 +209,27 @@ class mt5(Exchange, ImplicitAPI):
return self.timezone
def fetch_markets(self, params={}):
"""获取交易对列表 - 修复版本"""
"""获取交易对列表 - 使用 SymbolParamsMany 接口"""
self.load_token()
request = {
'id': self.token,
'limit': 10000, # 添加 limit 参数获取所有交易对
}
try:
response = self.private_get_symbols(self.extend(request, params))
response = self.private_get_symbolparamsmany(self.extend(request, params))
markets = []
if isinstance(response, dict):
for symbol, info in response.items():
if isinstance(response, list):
for symbol_data in response:
try:
market = self.parse_market(info)
market = self.parse_market(symbol_data)
if market and market.get('symbol'):
markets.append(market)
except Exception as e:
if self.verbose:
print(f"跳过交易对 {symbol}: {e}")
symbol_name = self.safe_string(symbol_data, 'symbol', 'unknown')
print(f"跳过交易对 {symbol_name}: {e}")
continue
# 设置市场数据
@@ -249,34 +251,72 @@ class mt5(Exchange, ImplicitAPI):
except Exception as e:
raise ExchangeError(f"获取市场数据失败: {e}")
def parse_market(self, info):
"""解析市场信息 - 更健壮的版本"""
def parse_market(self, symbol_data):
"""解析市场信息 - 根据新的数据格式"""
try:
if not isinstance(info, dict):
if not isinstance(symbol_data, dict):
return None
symbol = self.safe_string(info, 'currency', '')
symbol = self.safe_string(symbol_data, 'symbol')
if not symbol:
return None
symbol = symbol.upper().strip()
symbol_info = self.safe_dict(symbol_data, 'symbolInfo', {})
symbol_group = self.safe_dict(symbol_data, 'symbolGroup', {})
# 处理符号格式
if len(symbol) < 6:
base = symbol
quote = 'USD'
# 解析基础信息
symbol_name = symbol.upper().strip()
# 确保符号格式正确 (如 EURUSD)
if len(symbol_name) < 6:
# 处理较短的符号
base = symbol_name
quote = 'USD' # 默认报价货币
else:
base = symbol[:3]
quote = symbol[3:]
base = symbol_name[:3]
quote = symbol_name[3:]
digits = self.safe_integer(info, 'digits', 5)
# 解析精度信息
digits = self.safe_integer(symbol_info, 'digits', 5)
if digits is not None:
try:
digits = int(digits)
except (ValueError, TypeError):
digits = 5
market_id = symbol
# 解析合约大小
contract_size = self.safe_number(symbol_info, 'contractSize', 100000)
# 解析交易量限制
min_volume = self.safe_number(symbol_group, 'minVolume', 0.01)
max_volume = self.safe_number(symbol_group, 'maxVolume', 100)
volume_step = self.safe_number(symbol_group, 'volumeStep', 0.01)
# 处理最小交易量单位转换
# 如果 minVolume 很大,可能是以合约单位表示,需要转换为手数
if min_volume > 1000: # 假设大于1000的是合约单位
min_volume = min_volume / contract_size if contract_size > 0 else 0.01
# 解析价格精度
points = self.safe_number(symbol_info, 'points', 0.00001)
price_precision = digits
# 解析保证金信息
initial_margin = self.safe_number(symbol_group, 'initialMargin', 0)
maintenance_margin = self.safe_number(symbol_group, 'maintenanceMargin', 0)
# 解析货币信息
profit_currency = self.safe_string(symbol_info, 'profitCurrency', 'USD')
margin_currency = self.safe_string(symbol_info, 'marginCurrency', base)
# 解析交易模式
trade_mode = self.safe_string(symbol_group, 'tradeMode', 'Disabled')
active = trade_mode != 'Disabled'
# 解析描述信息
description = self.safe_string(symbol_info, 'description', '')
market_id = symbol_name
return {
'id': market_id,
@@ -285,35 +325,63 @@ class mt5(Exchange, ImplicitAPI):
'quote': quote,
'baseId': base,
'quoteId': quote,
'active': True,
'active': active,
'type': 'spot',
'spot': True,
'margin': True,
'precision': {
'price': digits,
'amount': 2,
'price': price_precision,
'amount': 2, # 手数精度
'base': 2,
'quote': price_precision,
},
'limits': {
'amount': {
'min': self.safe_number(info, 'minVolume', 0.01),
'max': self.safe_number(info, 'maxVolume'),
'min': min_volume,
'max': max_volume,
},
'price': {
'min': None,
'min': points, # 最小价格变动
'max': None,
},
'cost': {
'min': None,
'max': None,
},
'leverage': {
'min': 1.0,
'max': self.safe_number(symbol_group, 'accountLeverage', 100.0),
}
},
'info': info,
'contractSize': contract_size,
'expiry': None,
'expiryDatetime': None,
'strike': None,
'optionType': None,
'taker': self.safe_number(symbol_group, 'commission', 0), # 可能需要调整
'maker': self.safe_number(symbol_group, 'commission', 0), # 可能需要调整
'percentage': True,
'tierBased': False,
'feeSide': 'quote',
'info': symbol_data,
'margin': {
'initial': initial_margin,
'maintenance': maintenance_margin,
},
'swap': {
'long': self.safe_number(symbol_group, 'swapLong', 0),
'short': self.safe_number(symbol_group, 'swapShort', 0),
},
'lotSize': volume_step,
'minNotional': None,
'maxNotional': None,
}
except Exception as e:
if self.verbose:
print(f"解析市场信息失败: {e}, info: {info}")
symbol_name = self.safe_string(symbol_data, 'symbol', 'unknown')
print(f"解析市场信息失败 {symbol_name}: {e}")
return None
def fetch_ticker(self, symbol, params={}):
"""获取行情数据"""
self.load_token()