2
This commit is contained in:
@@ -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):
|
||||
|
||||
124
ccxt/mt5.py
124
ccxt/mt5.py
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user