# -*- coding: utf-8 -*-

from ccxt.base.exchange import Exchange
from ccxt.abstract.mt5 import ImplicitAPI
from ccxt.base.types import Any, Balances, BorrowInterest, Conversion, CrossBorrowRate, Currencies, Currency, DepositAddress, FundingHistory, Greeks, Int, LedgerEntry, Leverage, LeverageTier, LeverageTiers, Liquidation, LongShortRatio, Market, Num, Option, OptionChain, Order, OrderBook, OrderRequest, CancellationRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade, TradingFeeInterface, TradingFees, Transaction, MarketInterface, TransferEntry
from typing import List
from typing import List, Optional  # 添加 Optional 导入
from ccxt.base.errors import ExchangeError
from ccxt.base.errors import AuthenticationError
from ccxt.base.errors import PermissionDenied
from ccxt.base.errors import AccountSuspended
from ccxt.base.errors import ArgumentsRequired
from ccxt.base.errors import BadRequest
from ccxt.base.errors import BadSymbol
from ccxt.base.errors import NoChange
from ccxt.base.errors import MarginModeAlreadySet
from ccxt.base.errors import ManualInteractionNeeded
from ccxt.base.errors import InsufficientFunds
from ccxt.base.errors import InvalidOrder
from ccxt.base.errors import OrderNotFound
from ccxt.base.errors import NotSupported
from ccxt.base.errors import RateLimitExceeded
from ccxt.base.errors import InvalidNonce
from ccxt.base.errors import RequestTimeout
from ccxt.base.decimal_to_precision import TICK_SIZE
from ccxt.base.precise import Precise
from datetime import datetime, timedelta


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': '10.203.0.6:5000', 
            'pro': True,
            'options': {
                'host': '18.163.85.196',
                'port': 443,
                'connectTimeoutSeconds': 30,
            },
            'has': {
                'CORS': True,
                'spot': True,
                'margin': True,
                'swap': False,
                'future': False,
                'option': False,
                'cancelOrder': True,
                'createOrder': True,
                'fetchBalance': True,
                'fetchClosedOrders': True,
                'fetchMarkets': True,
                'fetchMyTrades': True,
                'fetchOHLCV': True,
                'fetchOpenOrders': True,
                'fetchOrder': True,
                'fetchPositions': True,
                'fetchOrderBook': True,
                'fetchTicker': True,
                'fetchTickers': 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,
                        'SymbolParamsMany': 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,
                        'SubscribeOhlc': 1,
                        'UnsubscribeOhlc': 1,
                        'Subscribe': 1,
                        'UnSubscribe': 1,
                    },
                },
            },
            '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,
                },
            },
        })
    
    def ping_server(self):
        """测试连接"""
        response = self.public_get_ping()
        if response == 'OK':
            return True
        else:
            return False
        
    def get_token(self):
        """获取或刷新 token"""
        if hasattr(self, 'token') and self.token:
            try:
                self.check_connect()
                return self.token
            except Exception:
                # Token 无效，重新连接
                pass
        
        # 重新连接获取 token
        return self.connect()

    def connect(self):
        """连接到 MT5 账户并获取 token"""
        params = {
            'user': self.apiKey,
            'password': self.secret,
            'host': self.options['host'],
            'port': self.options['port'],
            'connectTimeoutSeconds': self.options['connectTimeoutSeconds'],
        }
        
        response = self.private_get_connect(params)
        
        self.token = response
        return self.token

    def check_connect(self):
        """检查连接状态"""
        params = {
            'id': self.get_token(),
        }
        return self.private_get_checkconnect(params)

    def disconnect(self):
        """断开连接"""
        if hasattr(self, 'token') and self.token:
            params = {
                'id': self.token,
            }
            try:
                self.private_get_disconnect(params)
            except Exception:
                pass
            finally:
                self.token = None
    
    def load_token(self):
        """确保 token 已加载"""
        if not hasattr(self, 'token') or not self.token:
            self.get_token()
    
    def server_timezone(self):
        """获得mt5服务器时区"""
        if hasattr(self, 'timezone'):
            return self.timezone
        else:
            self.load_token()
            request = {
                'id': self.token,
            }
            response = self.private_get_servertimezone(request)
            self.timezone = int(float(response))
            return self.timezone

    def fetch_markets(self, params={}):
        """获取交易对列表 - 使用 SymbolParamsMany 接口"""
        self.load_token()
        request = {
            'id': self.token,
            'limit': 10000,  # 添加 limit 参数获取所有交易对
        }
        
        try:
            response = self.private_get_symbolparamsmany(self.extend(request, params))
            
            markets = []
            if isinstance(response, list):
                for symbol_data in response:
                    try:
                        market = self.parse_market(symbol_data)
                        if market and market.get('symbol'):
                            markets.append(market)
                    except Exception as e:
                        if self.verbose:
                            symbol_name = self.safe_string(symbol_data, 'symbol', 'unknown')
                            print(f"跳过交易对 {symbol_name}: {e}")
                        continue
            
            # 设置市场数据
            if markets:
                self.markets = {}
                self.symbols = []
                for market in markets:
                    id = market['id']
                    symbol = market['symbol']
                    self.markets[id] = market
                    self.markets[symbol] = market
                    self.symbols.append(symbol)
                
                self.symbols = sorted(self.symbols)
                self.ids = sorted(self.markets.keys())
            
            return markets
            
        except Exception as e:
            raise ExchangeError(f"获取市场数据失败: {e}")

    def parse_market(self, symbol_data):
        """解析市场信息 - 根据新的数据格式"""
        try:
            if not isinstance(symbol_data, dict):
                return None
                
            symbol = self.safe_string(symbol_data, 'symbol')
            if not symbol:
                return None
                
            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_name) < 6:
                # 处理较短的符号
                base = symbol_name
                quote = 'USD'  # 默认报价货币
            else:
                base = symbol_name[:3]
                quote = symbol_name[3:]
            
            # 解析精度信息
            digits = self.safe_integer(symbol_info, 'digits', 5)
            if digits is not None:
                try:
                    digits = int(digits)
                except (ValueError, TypeError):
                    digits = 5
            
            # 解析合约大小
            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,
                'symbol': base + '/' + quote,
                'base': base,
                'quote': quote,
                'baseId': base,
                'quoteId': quote,
                'active': active,
                'type': 'spot',
                'spot': True,
                'margin': True,
                'precision': {
                    'price': price_precision,
                    'amount': 2,  # 手数精度
                    'base': 2,
                    'quote': price_precision,
                },
                'limits': {
                    'amount': {
                        'min': min_volume,
                        'max': max_volume,
                    },
                    'price': {
                        'min': points,  # 最小价格变动
                        'max': None,
                    },
                    'cost': {
                        'min': None,
                        'max': None,
                    },
                    'leverage': {
                        'min': 1.0,
                        'max': self.safe_number(symbol_group, 'accountLeverage', 100.0),
                    }
                },
                '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:
                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()
        market = self.market(symbol)
        request = {
            'id': self.token,
            'symbol': market['id'],
        }
        
        response = self.private_get_getquote(self.extend(request, params))
        return self.parse_ticker(response, market)

    def parse_ticker(self, ticker, market=None):
        """解析行情数据"""
        symbol = market['symbol'] if market else None
        timestamp = None
        if ticker.get('time'):
            try:
                timestamp = self.parse8601(ticker.get('time'))
            except:
                timestamp = None
        
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp) if timestamp else None,
            'high': None,
            'low': None,
            'bid': self.safe_number(ticker, 'bid'),
            'bidVolume': None,
            'ask': self.safe_number(ticker, 'ask'),
            'askVolume': None,
            'vwap': None,
            'open': None,
            'close': None,
            'last': self.safe_number(ticker, 'last'),
            'previousClose': None,
            'change': None,
            'percentage': None,
            'average': None,
            'baseVolume': self.safe_number(ticker, 'volume'),
            'quoteVolume': None,
            'info': ticker,
        }

    def fetch_tickers(self, symbols: Optional[List[str]] = None, params={}):
        """获取多个交易对的行情数据"""
        self.load_token()
        
        request = {
            'id': self.token,
        }
        
        if symbols is not None:
            mt5_symbols = []
            for symbol in symbols:
                market = self.market(symbol)
                mt5_symbols.append(market['id'])
            request['symbols'] = mt5_symbols
        
        try:
            response = self.private_get_getquotemany(self.extend(request, params))
            return self.parse_tickers(response, symbols)
        except Exception as e:
            if symbols is not None:
                return self.fetch_tickers_fallback(symbols, params)
            else:
                raise ExchangeError(f"获取批量行情失败: {e}")

    def fetch_tickers_fallback(self, symbols, params={}):
        """回退方法：逐个获取交易对行情"""
        tickers = {}
        for symbol in symbols:
            try:
                ticker = self.fetch_ticker(symbol, params)
                tickers[symbol] = ticker
            except Exception as e:
                if self.verbose:
                    print(f"获取 {symbol} 行情失败: {e}")
                continue
        return tickers

    def parse_tickers(self, response, symbols=None):
        """解析批量行情数据"""
        tickers = {}
        
        if isinstance(response, list):
            for ticker_data in response:
                try:
                    ticker = self.parse_ticker(ticker_data)
                    if ticker and ticker.get('symbol'):
                        tickers[ticker['symbol']] = ticker
                except Exception as e:
                    if self.verbose:
                        print(f"解析行情数据失败: {e}")
                    continue
        elif isinstance(response, dict):
            for symbol_key, ticker_data in response.items():
                try:
                    ticker = self.parse_ticker(ticker_data)
                    if ticker and ticker.get('symbol'):
                        tickers[ticker['symbol']] = ticker
                except Exception as e:
                    if self.verbose:
                        print(f"解析行情数据失败 {symbol_key}: {e}")
                    continue
        
        if symbols is not None:
            ordered_tickers = {}
            for symbol in symbols:
                if symbol in tickers:
                    ordered_tickers[symbol] = tickers[symbol]
            return ordered_tickers
        
        return tickers

    def fetch_order_book(self, symbol, limit=None, params={}):
        """获取订单簿"""
        self.load_token()
        market = self.market(symbol)
        request = {
            'id': self.token,
            'symbol': market['id'],
        }
        response = self.private_get_getquote(self.extend(request, params))
        
        bid = self.safe_number(response, 'bid')
        ask = self.safe_number(response, 'ask')
        
        return {
            'symbol': symbol,
            'bids': [[bid, 1]] if bid else [],
            'asks': [[ask, 1]] if ask else [],
            'timestamp': None,
            'datetime': None,
            'nonce': None,
        }

    def fetch_balance(self, params={}):
        """获取账户余额"""
        self.load_token()
        request = {
            'id': self.token,
        }
        response = self.private_get_accountsummary(self.extend(request, params))
        
        return self.parse_balance(response)

    def parse_balance(self, response):
        """解析余额信息"""
        result = {
            'info': response,
            'timestamp': None,
            'datetime': None,
        }
        
        currency = 'USDT'
        balance = self.safe_number(response, 'balance', 0.0)
        margin = self.safe_number(response, 'margin', 0.0)
        free_margin = self.safe_number(response, 'freeMargin', 0.0)
        equity = self.safe_number(response, 'equity', 0.0)
        
        result[currency] = {
            'free': free_margin,
            'used': margin,
            'total': balance,
            'equity': equity,
        }
        
        return self.safe_balance(result)

    def fetch_account_details(self, params={}):
        """获取账户信息"""
        self.load_token()
        request = {
            'id': self.token,
        }
        response = self.private_get_accountdetails(self.extend(request, params))
        
        return self.parse_account(response)

    def parse_account(self, response):
        """解析账户信息"""
        return {
            'serverName': self.safe_string(response, 'serverName'),
            'user': self.safe_string(response, 'user'),
            'host': self.safe_string(response, 'host'),
            'port': self.safe_integer(response, 'port'),
            'serverTime': self.safe_string(response, 'serverTime'),
            'serverTimeZone': self.safe_integer(response, 'serverTimeZone'),
            'company': self.safe_string(response, 'company'),
            'currency': self.safe_string(response, 'currency', 'UST'),
            'accountName': self.safe_string(response, 'accountName'),
            'group': self.safe_string(response, 'group'),
            'accountType': self.safe_string(response, 'accountType'),
            'accountLeverage': self.safe_integer(response, 'accountLeverage'),
            'accountMethod': self.safe_string(response, 'accountMethod'),
            'isInvestor': self.safe_value(response, 'isInvestor', False),
        }

    def fetch_positions(self, symbol: Strings = None, params={}):
        """异步获取持仓信息"""
        if not hasattr(self, 'token') or not self.token:
            self.get_token()
            
        request = {
            'id': self.token,
        }
        self.load_markets()
        
        symbol = self.market_symbols(symbol)
        # print(symbol)
        response = self.private_get_openedorders(self.extend(request, params))
        data = []
        for item in response:
            state = self.safe_string(item, 'state', "")
            lots = self.safe_number(item, 'lots', 0)
            close_lots = self.safe_number(item, 'closeLots', 0)
            if state == "Filled" or lots <= close_lots:
                data.append(item)
        # 使用基类的 parse_positions 方法，让 parse_position 自己判断是否为有效持仓
        result = self.parse_positions(data, symbol)
        
        # 过滤掉 None 值（无效持仓）
        result = [position for position in result if position is not None]
        
        return result

    def parse_position(self, position, market: Market = None):
        """解析持仓信息 - 根据真实数据调整"""
        id = self.safe_string(position, 'ticket')
        market_id = self.safe_string(position, 'symbol')
        # 获取市场信息
        symbol = self.safe_symbol(market_id, market, '/')
        
        lots = self.safe_number(position, 'lots', 0)
        close_lots = self.safe_number(position, 'closeLots', 0)
        
        # 解析时间戳
        timestamp = self.parse8601(self.safe_string(position, 'openTime'))
        open_timestamp_utc = self.safe_integer(position, 'openTimestampUTC')
        if open_timestamp_utc:
            timestamp = open_timestamp_utc
        
        # 确定持仓方向
        order_type = self.safe_string(position, 'orderType')
        side = 'long' if order_type == 'Buy' else 'short'
        
        # 获取持仓数量 (未平仓数量)
        contracts = lots - close_lots
        
        # 获取价格信息
        entry_price = self.safe_number(position, 'openPrice', 0)
        current_price = self.safe_number(position, 'closePrice', entry_price)
        mark_price = current_price
        
        # 计算持仓价值
        contract_size = self.safe_number(position, 'contractSize', 1.0)
        notional = contracts * entry_price * contract_size if contracts and entry_price and contract_size else None
        
        # 计算盈亏 - 使用 profit 字段
        unrealized_pnl = self.safe_number(position, 'profit', 0)
        
        # 计算保证金信息
        initial_margin = None
        initial_margin_percentage = None
        
        # 如果有持仓价值，计算保证金
        if notional is not None and notional != 0:
            leverage = self.safe_number(position, 'leverage', 100)
            initial_margin = notional / leverage
            initial_margin_percentage = 1 / leverage
        
        # 计算强平价格 (简化计算)
        liquidation_price = None
        if entry_price is not None:
            if side == 'long':
                liquidation_price = entry_price * 0.95  # 假设 5% 强平线
            else:
                liquidation_price = entry_price * 1.05  # 假设 5% 强平线
        
        # 计算百分比盈亏
        percentage = None
        if entry_price is not None and mark_price is not None and entry_price != 0:
            if side == 'long':
                percentage = (mark_price - entry_price) / entry_price
            else:
                percentage = (entry_price - mark_price) / entry_price
        
        # 获取止损止盈价格
        stop_loss_price = self.safe_number(position, 'stopLoss')
        take_profit_price = self.safe_number(position, 'takeProfit')
        
        # 返回标准化的持仓信息
        return {
            'info': position,
            'id': self.safe_string(position, 'ticket'),
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp) if timestamp else None,
            'lastUpdateTimestamp': timestamp,
            'initialMargin': initial_margin,
            'initialMarginPercentage': initial_margin_percentage,
            'maintenanceMargin': None,
            'maintenanceMarginPercentage': None,
            'entryPrice': entry_price,
            'notional': notional,
            'leverage': self.safe_number(position, 'leverage', 100),
            'unrealizedPnl': unrealized_pnl,
            'realizedPnl': self.safe_number(position, 'realizedPnl', 0),
            'contracts': contracts,
            'contractSize': contract_size,
            'marginRatio': None,
            'liquidationPrice': liquidation_price,
            'markPrice': mark_price,
            'lastPrice': mark_price,
            'collateral': initial_margin,
            'marginMode': 'cross',
            'side': side,
            'percentage': percentage,
            'stopLossPrice': stop_loss_price,
            'takeProfitPrice': take_profit_price,
            'hedged': None,
        }

    def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
        """获取未平仓订单"""
        self.load_token()
        request = {
            'id': self.token,
        }
        
        response = self.private_get_openedorders(self.extend(request, params))
        
        if symbol is not None:
            market = self.market(symbol)
            filtered_orders = []
            for order in response:
                if isinstance(order, dict) and order.get('symbol') == market['id']:
                    filtered_orders.append(order)
            return self.parse_orders(filtered_orders, market, since, limit)
        else:
            return self.parse_orders(response, None, since, limit)

    def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}):
        """获取已平仓订单"""
        self.load_token()
        yesterday = datetime.now() - timedelta(days=3)
        from_day = yesterday.strftime('%Y-%m-%d') + 'T00:00:00'
        tomorrow = datetime.now() + timedelta(days=1)
        to_day = tomorrow.strftime('%Y-%m-%d') + 'T00:00:00'
        request = {
            'id': self.token,
            'from': from_day,
            'to': to_day,
            'sort': 'OpenTime',
            'ascending': 'true',
        }
        
        response = self.private_get_orderhistory(self.extend(request, params))
        data = self.safe_list(response, 'orders')
        
        if symbol is not None:
            market = self.market(symbol)
            filtered_orders = []
            for order in response:
                if isinstance(order, dict) and order.get('symbol') == market['id']:
                    filtered_orders.append(order)
            return self.parse_orders(filtered_orders, market, since, limit)
        else:
            return self.parse_orders(response, None, since, limit)

    def parse_order(self, order, market=None):
        """解析订单信息"""
        try:
            id = self.safe_string(order, 'ticket')
            market_id = self.safe_string(order, 'symbol')
            
            symbol = None
            if market is not None:
                symbol = market['symbol']
            elif market_id is not None:
                if len(market_id) >= 6:
                    base = market_id[:3]
                    quote = market_id[3:]
                    symbol = base + '/' + quote
                else:
                    symbol = market_id
            
            timestamp = self.parse8601(self.safe_string(order, 'openTime'))
            last_trade_timestamp = self.parse8601(self.safe_string(order, 'closeTime'))
            
            status = self.parse_order_status(self.safe_string(order, 'state'))
            side = self.parse_order_side(self.safe_string(order, 'orderType'))
            type = self.parse_order_type(self.safe_string(order, 'orderType'))
            
            price = self.safe_number(order, 'openPrice')
            amount = self.safe_number(order, 'lots')
            filled = self.safe_number(order, 'closeLots', 0)
            
            remaining = None
            if amount is not None and filled is not None:
                remaining = amount - filled
            
            cost = None
            if price is not None and filled is not None:
                cost = price * filled
            
            fee = None
            fee_cost = self.safe_number(order, 'commission', 0)
            if fee_cost != 0:
                fee = {
                    'cost': fee_cost,
                    'currency': None,
                }
                
            return self.safe_order({
                'id': id,
                'clientOrderId': None,
                'datetime': self.iso8601(timestamp),
                'timestamp': timestamp,
                'lastTradeTimestamp': last_trade_timestamp,
                'lastUpdateTimestamp': last_trade_timestamp,
                'status': status,
                'symbol': symbol,
                'type': type,
                'timeInForce': None,
                'postOnly': None,
                'side': side,
                'price': price,
                'stopLossPrice': self.safe_number(order, 'stopLoss'),
                'takeProfitPrice': self.safe_number(order, 'takeProfit'),
                'reduceOnly': None,
                'triggerPrice': None,
                'amount': amount,
                'filled': filled,
                'remaining': remaining,
                'cost': cost,
                'trades': None,
                'fee': fee,
                'info': order,
                'average': None,
            })
        except Exception as e:
            if self.verbose:
                print(f"解析订单失败: {e}, order: {order}")
            raise e

    def parse_order_status(self, status):
        statuses = {
            'Started': 'open',
            'Placed': 'open',
            'Cancelled': 'canceled',
            'Partial': 'open',
            'Filled': 'closed',
            'Rejected': 'rejected',
            'Expired': 'expired',
        }
        return self.safe_string(statuses, status, status)

    def parse_order_side(self, side):
        sides = {
            'Buy': 'buy',
            'Sell': 'sell',
            'BuyLimit': 'buy',
            'SellLimit': 'sell',
            'BuyStop': 'buy',
            'SellStop': 'sell',
        }
        return self.safe_string(sides, side, side)

    def parse_order_type(self, type):
        types = {
            'Buy': 'market',
            'Sell': 'market',
            'BuyLimit': 'limit',
            'SellLimit': 'limit',
            'BuyStop': 'stop',
            'SellStop': 'stop',
        }
        return self.safe_string(types, type, type)

    def create_order(self, symbol, type, side, amount, price=None, params={}):
        """创建订单"""
        self.load_token()
        market = self.market(symbol)
        
        request = {
            'id': self.token,
            'symbol': market['id'],
            'volume': amount,
        }
        
        operation_map = {
            'market': {
                'buy': 'Buy',
                'sell': 'Sell',
            },
            'limit': {
                'buy': 'BuyLimit',
                'sell': 'SellLimit',
            },
            'stop': {
                'buy': 'BuyStop',
                'sell': 'SellStop',
            },
        }
        
        if type in operation_map and side in operation_map[type]:
            request['operation'] = operation_map[type][side]
        else:
            raise InvalidOrder(self.id + ' createOrder does not support order type ' + type + ' and side ' + side)
        
        if type in ['limit', 'stop'] and price is not None:
            request['price'] = price
            
        stop_loss = self.safe_number(params, 'stopLoss')
        take_profit = self.safe_number(params, 'takeProfit')
        if stop_loss is not None:
            request['stoploss'] = stop_loss
        if take_profit is not None:
            request['takeprofit'] = take_profit
            
        response = self.private_get_ordersend(self.extend(request, params))
        return self.parse_order(response, market)

    def cancel_order(self, id, symbol=None, params={}):
        """取消订单"""
        self.load_token()
        request = {
            'id': self.token,
            'ticket': int(id),
        }
        response = self.private_get_orderclose(self.extend(request, params))
        return self.parse_order(response)

    def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
        """签名请求"""
        base_url = self.implode_hostname(self.urls['api'][api])
        url = base_url + '/' + path
        query = self.omit(params, self.extract_params(path))
        
        if method == 'GET' and query:
            url += '?' + self.urlencode(query)
        
        return {
            'url': url,
            'method': method,
            'body': body,
            'headers': headers
        }