text: # -*- 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.base.exchange import Exchange
  import json
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import AuthenticationError
  from ccxt.base.errors import BadSymbol
  from ccxt.base.errors import InsufficientFunds
  from ccxt.base.errors import OrderNotFound
  from ccxt.base.decimal_to_precision import TICK_SIZE
  
  
  class ndax(Exchange):
  
      def describe(self):
          return self.deep_extend(super(ndax, self).describe(), {
              'id': 'ndax',
              'name': 'NDAX',
              'countries': ['US'],  # United States
              'rateLimit': 1000,
              'pro': True,
              'has': {
                  'cancelAllOrders': True,
                  'cancelOrder': True,
                  'createDepositAddress': True,
                  'createOrder': True,
                  'editOrder': True,
                  'fetchAccounts': True,
                  'fetchBalance': True,
                  'fetchCurrencies': True,
                  'fetchDepositAddress': True,
                  'fetchDeposits': True,
                  'fetchLedger': True,
                  'fetchMarkets': True,
                  'fetchMyTrades': True,
                  'fetchOHLCV': True,
                  'fetchOpenOrders': True,
                  'fetchOrders': True,
                  'fetchOrder': True,
                  'fetchOrderBook': True,
                  'fetchOrderTrades': True,
                  'fetchTicker': True,
                  'fetchTrades': True,
              },
              'timeframes': {
                  '1m': '60',
                  '5m': '300',
                  '15m': '900',
                  '30m': '1800',
                  '1h': '3600',
                  '2h': '7200',
                  '4h': '14400',
                  '6h': '21600',
                  '12h': '43200',
                  '1d': '86400',
                  '1w': '604800',
                  '1M': '2419200',
                  '4M': '9676800',
              },
              'urls': {
                  'logo': 'https://user-images.githubusercontent.com/1294454/108623144-67a3ef00-744e-11eb-8140-75c6b851e945.jpg',
                  'test': {
                      'public': 'https://ndaxmarginstaging.cdnhop.net:8443/AP',
                      'private': 'https://ndaxmarginstaging.cdnhop.net:8443/AP',
                  },
                  'api': {
                      'public': 'https://api.ndax.io:8443/AP',
                      'private': 'https://api.ndax.io:8443/AP',
                  },
                  'www': 'https://ndax.io',
                  'doc': [
                      'https://apidoc.ndax.io/',
                  ],
                  'fees': 'https://ndax.io/fees',
                  'referral': 'https://one.ndax.io/bfQiSL',
              },
              'api': {
                  'public': {
                      'get': [
                          'Activate2FA',
                          'Authenticate2FA',
                          'AuthenticateUser',
                          'GetL2Snapshot',
                          'GetLevel1',
                          'GetValidate2FARequiredEndpoints',
                          'LogOut',
                          'GetTickerHistory',
                          'GetProduct',
                          'GetProducts',
                          'GetInstrument',
                          'GetInstruments',
                          'Ping',
                          'trades',  # undocumented
                          'GetLastTrades',  # undocumented
                          'SubscribeLevel1',
                          'SubscribeLevel2',
                          'SubscribeTicker',
                          'SubscribeTrades',
                          'SubscribeBlockTrades',
                          'UnsubscribeBlockTrades',
                          'UnsubscribeLevel1',
                          'UnsubscribeLevel2',
                          'UnsubscribeTicker',
                          'UnsubscribeTrades',
                          'Authenticate',  # undocumented
                      ],
                  },
                  'private': {
                      'get': [
                          'GetUserAccountInfos',
                          'GetUserAccounts',
                          'GetUserAffiliateCount',
                          'GetUserAffiliateTag',
                          'GetUserConfig',
                          'GetAllUnredactedUserConfigsForUser',
                          'GetUnredactedUserConfigByKey',
                          'GetUserDevices',
                          'GetUserReportTickets',
                          'GetUserReportWriterResultRecords',
                          'GetAccountInfo',
                          'GetAccountPositions',
                          'GetAllAccountConfigs',
                          'GetTreasuryProductsForAccount',
                          'GetAccountTrades',
                          'GetAccountTransactions',
                          'GetOpenTradeReports',
                          'GetAllOpenTradeReports',
                          'GetTradesHistory',
                          'GetOpenOrders',
                          'GetOpenQuotes',
                          'GetOrderFee',
                          'GetOrderHistory',
                          'GetOrdersHistory',
                          'GetOrderStatus',
                          'GetOmsFeeTiers',
                          'GetAccountDepositTransactions',
                          'GetAccountWithdrawTransactions',
                          'GetAllDepositRequestInfoTemplates',
                          'GetDepositInfo',
                          'GetDepositRequestInfoTemplate',
                          'GetDeposits',
                          'GetDepositTicket',
                          'GetDepositTickets',
                          'GetOMSWithdrawFees',
                          'GetWithdrawFee',
                          'GetWithdraws',
                          'GetWithdrawTemplate',
                          'GetWithdrawTemplateTypes',
                          'GetWithdrawTicket',
                          'GetWithdrawTickets',
                      ],
                      'post': [
                          'AddUserAffiliateTag',
                          'CancelUserReport',
                          'RegisterNewDevice',
                          'SubscribeAccountEvents',
                          'UpdateUserAffiliateTag',
                          'GenerateTradeActivityReport',
                          'GenerateTransactionActivityReport',
                          'GenerateTreasuryActivityReport',
                          'ScheduleTradeActivityReport',
                          'ScheduleTransactionActivityReport',
                          'ScheduleTreasuryActivityReport',
                          'CancelAllOrders',
                          'CancelOrder',
                          'CancelQuote',
                          'CancelReplaceOrder',
                          'CreateQuote',
                          'ModifyOrder',
                          'SendOrder',
                          'SubmitBlockTrade',
                          'UpdateQuote',
                          'CancelWithdraw',
                          'CreateDepositTicket',
                          'CreateWithdrawTicket',
                          'SubmitDepositTicketComment',
                          'SubmitWithdrawTicketComment',
                          'GetOrderHistoryByOrderId',
                      ],
                  },
              },
              'fees': {
                  'trading': {
                      'tierBased': False,
                      'percentage': True,
                      'maker': 0.2 / 100,
                      'taker': 0.25 / 100,
                  },
              },
              'requiredCredentials': {
                  'apiKey': True,
                  'secret': True,
                  'uid': True,
              },
              'precisionMode': TICK_SIZE,
              'exceptions': {
                  'exact': {
                      'Not_Enough_Funds': InsufficientFunds,  # {"status":"Rejected","errormsg":"Not_Enough_Funds","errorcode":101}
                      'Server Error': ExchangeError,  # {"result":false,"errormsg":"Server Error","errorcode":102,"detail":null}
                      'Resource Not Found': OrderNotFound,  # {"result":false,"errormsg":"Resource Not Found","errorcode":104,"detail":null}
                  },
                  'broad': {
                      'Invalid InstrumentId': BadSymbol,  # {"result":false,"errormsg":"Invalid InstrumentId: 10000","errorcode":100,"detail":null}
                  },
              },
              'options': {
                  'omsId': 1,
                  'orderTypes': {
                      'Market': 1,
                      'Limit': 2,
                      'StopMarket': 3,
                      'StopLimit': 4,
                      'TrailingStopMarket': 5,
                      'TrailingStopLimit': 6,
                      'BlockTrade': 7,
                  },
              },
          })
  
      def fetch_currencies(self, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          request = {
              'omsId': omsId,
          }
          response = self.publicGetGetProducts(self.extend(request, params))
          #
          #     [
          #         {
          #             "OMSId":1,
          #             "ProductId":1,
          #             "Product":"BTC",
          #             "ProductFullName":"Bitcoin",
          #             "ProductType":"CryptoCurrency",
          #             "DecimalPlaces":8,
          #             "TickSize":0.0000000100000000000000000000,
          #             "NoFees":false,
          #             "IsDisabled":false,
          #             "MarginEnabled":false
          #         },
          #     ]
          #
          result = {}
          for i in range(0, len(response)):
              currency = response[i]
              id = self.safe_string(currency, 'ProductId')
              name = self.safe_string(currency, 'ProductFullName')
              type = self.safe_string(currency, 'ProductType')
              code = self.safe_currency_code(self.safe_string(currency, 'Product'))
              precision = self.safe_number(currency, 'TickSize')
              isDisabled = self.safe_value(currency, 'IsDisabled')
              active = not isDisabled
              result[code] = {
                  'id': id,
                  'name': name,
                  'code': code,
                  'type': type,
                  'precision': precision,
                  'info': currency,
                  'active': active,
                  'fee': None,
                  'limits': self.limits,
              }
          return result
  
      def fetch_markets(self, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          request = {
              'omsId': omsId,
          }
          response = self.publicGetGetInstruments(self.extend(request, params))
          #
          #     [
          #         {
          #             "OMSId":1,
          #             "InstrumentId":3,
          #             "Symbol":"LTCBTC",
          #             "Product1":3,
          #             "Product1Symbol":"LTC",
          #             "Product2":1,
          #             "Product2Symbol":"BTC",
          #             "InstrumentType":"Standard",
          #             "VenueInstrumentId":3,
          #             "VenueId":1,
          #             "SortIndex":0,
          #             "SessionStatus":"Running",
          #             "PreviousSessionStatus":"Stopped",
          #             "SessionStatusDateTime":"2020-11-25T19:42:15.245Z",
          #             "SelfTradePrevention":true,
          #             "QuantityIncrement":0.0000000100000000000000000000,
          #             "PriceIncrement":0.0000000100000000000000000000,
          #             "MinimumQuantity":0.0100000000000000000000000000,
          #             "MinimumPrice":0.0000010000000000000000000000,
          #             "VenueSymbol":"LTCBTC",
          #             "IsDisable":false,
          #             "MasterDataId":0,
          #             "PriceCollarThreshold":0.0000000000000000000000000000,
          #             "PriceCollarPercent":0.0000000000000000000000000000,
          #             "PriceCollarEnabled":false,
          #             "PriceFloorLimit":0.0000000000000000000000000000,
          #             "PriceFloorLimitEnabled":false,
          #             "PriceCeilingLimit":0.0000000000000000000000000000,
          #             "PriceCeilingLimitEnabled":false,
          #             "CreateWithMarketRunning":true,
          #             "AllowOnlyMarketMakerCounterParty":false,
          #             "PriceCollarIndexDifference":0.0000000000000000000000000000,
          #             "PriceCollarConvertToOtcEnabled":false,
          #             "PriceCollarConvertToOtcClientUserId":0,
          #             "PriceCollarConvertToOtcAccountId":0,
          #             "PriceCollarConvertToOtcThreshold":0.0000000000000000000000000000,
          #             "OtcConvertSizeThreshold":0.0000000000000000000000000000,
          #             "OtcConvertSizeEnabled":false,
          #             "OtcTradesPublic":true,
          #             "PriceTier":0
          #         },
          #     ]
          #
          result = []
          for i in range(0, len(response)):
              market = response[i]
              id = self.safe_string(market, 'InstrumentId')
              # lowercaseId = self.safe_string_lower(market, 'symbol')
              baseId = self.safe_string(market, 'Product1')
              quoteId = self.safe_string(market, 'Product2')
              base = self.safe_currency_code(self.safe_string(market, 'Product1Symbol'))
              quote = self.safe_currency_code(self.safe_string(market, 'Product2Symbol'))
              symbol = base + '/' + quote
              precision = {
                  'amount': self.safe_number(market, 'QuantityIncrement'),
                  'price': self.safe_number(market, 'PriceIncrement'),
              }
              sessionStatus = self.safe_string(market, 'SessionStatus')
              isDisable = self.safe_value(market, 'IsDisable')
              sessionRunning = (sessionStatus == 'Running')
              active = True if (sessionRunning and not isDisable) else False
              result.append({
                  'id': id,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'info': market,
                  'active': active,
                  'precision': precision,
                  'limits': {
                      'amount': {
                          'min': self.safe_number(market, 'MinimumQuantity'),
                          'max': None,
                      },
                      'price': {
                          'min': self.safe_number(market, 'MinimumPrice'),
                          'max': None,
                      },
                      'cost': {
                          'min': None,
                          'max': None,
                      },
                  },
              })
          return result
  
      def parse_order_book(self, orderbook, timestamp=None, bidsKey='bids', asksKey='asks', priceKey=6, amountKey=8):
          nonce = None
          result = {
              'bids': [],
              'asks': [],
              'timestamp': None,
              'datetime': None,
              'nonce': None,
          }
          for i in range(0, len(orderbook)):
              level = orderbook[i]
              if timestamp is None:
                  timestamp = self.safe_integer(level, 2)
              else:
                  newTimestamp = self.safe_integer(level, 2)
                  timestamp = max(timestamp, newTimestamp)
              if nonce is None:
                  nonce = self.safe_integer(level, 0)
              else:
                  newNonce = self.safe_integer(level, 0)
                  nonce = max(nonce, newNonce)
              bidask = self.parse_bid_ask(level, priceKey, amountKey)
              levelSide = self.safe_value(level, 9)
              side = asksKey if levelSide else bidsKey
              result[side].append(bidask)
          result['bids'] = self.sort_by(result['bids'], 0, True)
          result['asks'] = self.sort_by(result['asks'], 0)
          result['timestamp'] = timestamp
          result['datetime'] = self.iso8601(timestamp)
          result['nonce'] = nonce
          return result
  
      def fetch_order_book(self, symbol, limit=None, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          market = self.market(symbol)
          limit = 100 if (limit is None) else limit  # default 100
          request = {
              'omsId': omsId,
              'InstrumentId': market['id'],
              'Depth': limit,  # default 100
          }
          response = self.publicGetGetL2Snapshot(self.extend(request, params))
          #
          #     [
          #         [
          #             0,   # 0 MDUpdateId
          #             1,   # 1 Number of Unique Accounts
          #             123,  # 2 ActionDateTime in Posix format X 1000
          #             0,   # 3 ActionType 0(New), 1(Update), 2(Delete)
          #             0.0,  # 4 LastTradePrice
          #             0,   # 5 Number of Orders
          #             0.0,  # 6 Price
          #             0,   # 7 ProductPairCode
          #             0.0,  # 8 Quantity
          #             0,   # 9 Side
          #         ],
          #         [97244115,1,1607456142963,0,19069.32,1,19069.31,8,0.140095,0],
          #         [97244115,0,1607456142963,0,19069.32,1,19068.64,8,0.0055,0],
          #         [97244115,0,1607456142963,0,19069.32,1,19068.26,8,0.021291,0],
          #         [97244115,1,1607456142964,0,19069.32,1,19069.32,8,0.099636,1],
          #         [97244115,0,1607456142964,0,19069.32,1,19069.98,8,0.1,1],
          #         [97244115,0,1607456142964,0,19069.32,1,19069.99,8,0.141604,1],
          #     ]
          #
          return self.parse_order_book(response)
  
      def parse_ticker(self, ticker, market=None):
          #
          # fetchTicker
          #
          #     {
          #         "OMSId":1,
          #         "InstrumentId":8,
          #         "BestBid":19069.31,
          #         "BestOffer":19069.32,
          #         "LastTradedPx":19069.32,
          #         "LastTradedQty":0.0001,
          #         "LastTradeTime":1607040406424,
          #         "SessionOpen":19069.32,
          #         "SessionHigh":19069.32,
          #         "SessionLow":19069.32,
          #         "SessionClose":19069.32,
          #         "Volume":0.0001,
          #         "CurrentDayVolume":0.0001,
          #         "CurrentDayNotional":1.906932,
          #         "CurrentDayNumTrades":1,
          #         "CurrentDayPxChange":0.00,
          #         "Rolling24HrVolume":0.000000000000000000000000000,
          #         "Rolling24HrNotional":0.00000000000000000000000,
          #         "Rolling24NumTrades":0,
          #         "Rolling24HrPxChange":0,
          #         "TimeStamp":"1607040406425",
          #         "BidQty":0,
          #         "AskQty":0,
          #         "BidOrderCt":0,
          #         "AskOrderCt":0,
          #         "Rolling24HrPxChangePercent":0,
          #     }
          #
          timestamp = self.safe_integer(ticker, 'TimeStamp')
          marketId = self.safe_string(ticker, 'InstrumentId')
          symbol = self.safe_symbol(marketId, market)
          last = self.safe_number(ticker, 'LastTradedPx')
          percentage = self.safe_number(ticker, 'Rolling24HrPxChangePercent')
          change = self.safe_number(ticker, 'Rolling24HrPxChange')
          open = self.safe_number(ticker, 'SessionOpen')
          average = None
          if (last is not None) and (change is not None):
              average = self.sum(last, open) / 2
          baseVolume = self.safe_number(ticker, 'Rolling24HrVolume')
          quoteVolume = self.safe_number(ticker, 'Rolling24HrNotional')
          vwap = self.vwap(baseVolume, quoteVolume)
          return {
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': self.safe_number(ticker, 'SessionHigh'),
              'low': self.safe_number(ticker, 'SessionLow'),
              'bid': self.safe_number(ticker, 'BestBid'),
              'bidVolume': None,  # self.safe_number(ticker, 'BidQty'), always shows 0
              'ask': self.safe_number(ticker, 'BestOffer'),
              'askVolume': None,  # self.safe_number(ticker, 'AskQty'), always shows 0
              'vwap': vwap,
              'open': open,
              'close': last,
              'last': last,
              'previousClose': None,
              'change': change,
              'percentage': percentage,
              'average': average,
              'baseVolume': baseVolume,
              'quoteVolume': quoteVolume,
              'info': ticker,
          }
  
      def fetch_ticker(self, symbol, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          market = self.market(symbol)
          request = {
              'omsId': omsId,
              'InstrumentId': market['id'],
          }
          response = self.publicGetGetLevel1(self.extend(request, params))
          #
          #     {
          #         "OMSId":1,
          #         "InstrumentId":8,
          #         "BestBid":19069.31,
          #         "BestOffer":19069.32,
          #         "LastTradedPx":19069.32,
          #         "LastTradedQty":0.0001,
          #         "LastTradeTime":1607040406424,
          #         "SessionOpen":19069.32,
          #         "SessionHigh":19069.32,
          #         "SessionLow":19069.32,
          #         "SessionClose":19069.32,
          #         "Volume":0.0001,
          #         "CurrentDayVolume":0.0001,
          #         "CurrentDayNotional":1.906932,
          #         "CurrentDayNumTrades":1,
          #         "CurrentDayPxChange":0.00,
          #         "Rolling24HrVolume":0.000000000000000000000000000,
          #         "Rolling24HrNotional":0.00000000000000000000000,
          #         "Rolling24NumTrades":0,
          #         "Rolling24HrPxChange":0,
          #         "TimeStamp":"1607040406425",
          #         "BidQty":0,
          #         "AskQty":0,
          #         "BidOrderCt":0,
          #         "AskOrderCt":0,
          #         "Rolling24HrPxChangePercent":0,
          #     }
          #
          return self.parse_ticker(response, market)
  
      def parse_ohlcv(self, ohlcv, market=None):
          #
          #     [
          #         1501603632000,  # 0 DateTime
          #         2700.33,       # 1 High
          #         2687.01,       # 2 Low
          #         2687.01,       # 3 Open
          #         2687.01,       # 4 Close
          #         24.86100992,   # 5 Volume
          #         0,             # 6 Inside Bid Price
          #         2870.95,       # 7 Inside Ask Price
          #         1              # 8 InstrumentId
          #     ]
          #
          return [
              self.safe_integer(ohlcv, 0),
              self.safe_number(ohlcv, 3),
              self.safe_number(ohlcv, 1),
              self.safe_number(ohlcv, 2),
              self.safe_number(ohlcv, 4),
              self.safe_number(ohlcv, 5),
          ]
  
      def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          market = self.market(symbol)
          request = {
              'omsId': omsId,
              'InstrumentId': market['id'],
              'Interval': self.timeframes[timeframe],
          }
          duration = self.parse_timeframe(timeframe)
          now = self.milliseconds()
          if since is None:
              if limit is not None:
                  request['FromDate'] = self.ymd(now - duration * limit * 1000)
                  request['ToDate'] = self.ymd(now)
          else:
              request['FromDate'] = self.ymd(since)
              if limit is None:
                  request['ToDate'] = self.ymd(now)
              else:
                  request['ToDate'] = self.ymd(self.sum(since, duration * limit * 1000))
          response = self.publicGetGetTickerHistory(self.extend(request, params))
          #
          #     [
          #         [1607299260000,19069.32,19069.32,19069.32,19069.32,0,19069.31,19069.32,8,1607299200000],
          #         [1607299320000,19069.32,19069.32,19069.32,19069.32,0,19069.31,19069.32,8,1607299260000],
          #         [1607299380000,19069.32,19069.32,19069.32,19069.32,0,19069.31,19069.32,8,1607299320000],
          #     ]
          #
          return self.parse_ohlcvs(response, market, timeframe, since, limit)
  
      def parse_trade(self, trade, market=None):
          #
          # fetchTrades(public)
          #
          #     [
          #         6913253,       #  0 TradeId
          #         8,             #  1 ProductPairCode
          #         0.03340802,    #  2 Quantity
          #         19116.08,      #  3 Price
          #         2543425077,    #  4 Order1
          #         2543425482,    #  5 Order2
          #         1606935922416,  #  6 Tradetime
          #         0,             #  7 Direction
          #         1,             #  8 TakerSide
          #         0,             #  9 BlockTrade
          #         0,             # 10 Either Order1ClientId or Order2ClientId
          #     ]
          #
          # fetchMyTrades(private)
          #
          #     {
          #         "OMSId":1,
          #         "ExecutionId":16916567,
          #         "TradeId":14476351,
          #         "OrderId":2543565231,
          #         "AccountId":449,
          #         "AccountName":"igor@ccxt.trade",
          #         "SubAccountId":0,
          #         "ClientOrderId":0,
          #         "InstrumentId":8,
          #         "Side":"Sell",
          #         "OrderType":"Market",
          #         "Quantity":0.1230000000000000000000000000,
          #         "RemainingQuantity":0.0000000000000000000000000000,
          #         "Price":19069.310000000000000000000000,
          #         "Value":2345.5251300000000000000000000,
          #         "CounterParty":"7",
          #         "OrderTradeRevision":1,
          #         "Direction":"NoChange",
          #         "IsBlockTrade":false,
          #         "Fee":1.1727625650000000000000000000,
          #         "FeeProductId":8,
          #         "OrderOriginator":446,
          #         "UserName":"igor@ccxt.trade",
          #         "TradeTimeMS":1607565031569,
          #         "MakerTaker":"Taker",
          #         "AdapterTradeId":0,
          #         "InsideBid":19069.310000000000000000000000,
          #         "InsideBidSize":0.2400950000000000000000000000,
          #         "InsideAsk":19069.320000000000000000000000,
          #         "InsideAskSize":0.0997360000000000000000000000,
          #         "IsQuote":false,
          #         "CounterPartyClientUserId":1,
          #         "NotionalProductId":2,
          #         "NotionalRate":1.0000000000000000000000000000,
          #         "NotionalValue":2345.5251300000000000000000000,
          #         "NotionalHoldAmount":0,
          #         "TradeTime":637431618315686826
          #     }
          #
          # fetchOrderTrades
          #
          #     {
          #         "Side":"Sell",
          #         "OrderId":2543565235,
          #         "Price":18600.000000000000000000000000,
          #         "Quantity":0.0000000000000000000000000000,
          #         "DisplayQuantity":0.0000000000000000000000000000,
          #         "Instrument":8,
          #         "Account":449,
          #         "AccountName":"igor@ccxt.trade",
          #         "OrderType":"Limit",
          #         "ClientOrderId":0,
          #         "OrderState":"FullyExecuted",
          #         "ReceiveTime":1607585844956,
          #         "ReceiveTimeTicks":637431826449564182,
          #         "LastUpdatedTime":1607585844959,
          #         "LastUpdatedTimeTicks":637431826449593893,
          #         "OrigQuantity":0.1230000000000000000000000000,
          #         "QuantityExecuted":0.1230000000000000000000000000,
          #         "GrossValueExecuted":2345.3947500000000000000000000,
          #         "ExecutableValue":0.0000000000000000000000000000,
          #         "AvgPrice":19068.250000000000000000000000,
          #         "CounterPartyId":0,
          #         "ChangeReason":"Trade",
          #         "OrigOrderId":2543565235,
          #         "OrigClOrdId":0,
          #         "EnteredBy":446,
          #         "UserName":"igor@ccxt.trade",
          #         "IsQuote":false,
          #         "InsideAsk":19069.320000000000000000000000,
          #         "InsideAskSize":0.0997360000000000000000000000,
          #         "InsideBid":19068.250000000000000000000000,
          #         "InsideBidSize":1.3300010000000000000000000000,
          #         "LastTradePrice":19068.250000000000000000000000,
          #         "RejectReason":"",
          #         "IsLockedIn":false,
          #         "CancelReason":"",
          #         "OrderFlag":"0",
          #         "UseMargin":false,
          #         "StopPrice":0.0000000000000000000000000000,
          #         "PegPriceType":"Unknown",
          #         "PegOffset":0.0000000000000000000000000000,
          #         "PegLimitOffset":0.0000000000000000000000000000,
          #         "IpAddress":"5.228.233.138",
          #         "ClientOrderIdUuid":null,
          #         "OMSId":1
          #     }
          #
          price = None
          amount = None
          cost = None
          timestamp = None
          id = None
          marketId = None
          side = None
          orderId = None
          takerOrMaker = None
          fee = None
          type = None
          if isinstance(trade, list):
              price = self.safe_number(trade, 3)
              amount = self.safe_number(trade, 2)
              if (price is not None) and (amount is not None):
                  cost = price * amount
              timestamp = self.safe_integer(trade, 6)
              id = self.safe_string(trade, 0)
              marketId = self.safe_integer(trade, 1)
              takerSide = self.safe_value(trade, 8)
              side = 'sell' if takerSide else 'buy'
              orderId = self.safe_string(trade, 4)
          else:
              timestamp = self.safe_integer_2(trade, 'TradeTimeMS', 'ReceiveTime')
              id = self.safe_string(trade, 'TradeId')
              orderId = self.safe_string_2(trade, 'OrderId', 'OrigOrderId')
              marketId = self.safe_string_2(trade, 'InstrumentId', 'Instrument')
              price = self.safe_number(trade, 'Price')
              amount = self.safe_number(trade, 'Quantity')
              cost = self.safe_number_2(trade, 'Value', 'GrossValueExecuted')
              takerOrMaker = self.safe_string_lower(trade, 'MakerTaker')
              side = self.safe_string_lower(trade, 'Side')
              type = self.safe_string_lower(trade, 'OrderType')
              feeCost = self.safe_number(trade, 'Fee')
              if feeCost is not None:
                  feeCurrencyId = self.safe_string(trade, 'FeeProductId')
                  feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
                  fee = {
                      'cost': feeCost,
                      'currency': feeCurrencyCode,
                  }
          symbol = self.safe_symbol(marketId, market)
          return {
              'info': trade,
              'id': id,
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'order': orderId,
              'type': type,
              'side': side,
              'takerOrMaker': takerOrMaker,
              'price': price,
              'amount': amount,
              'cost': cost,
              'fee': fee,
          }
  
      def fetch_trades(self, symbol, since=None, limit=None, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          market = self.market(symbol)
          request = {
              'omsId': omsId,
              'InstrumentId': market['id'],
          }
          if limit is not None:
              request['Count'] = limit
          response = self.publicGetGetLastTrades(self.extend(request, params))
          #
          #     [
          #         [6913253,8,0.03340802,19116.08,2543425077,2543425482,1606935922416,0,1,0,0],
          #         [6913254,8,0.01391671,19117.42,2543427510,2543427811,1606935927998,1,1,0,0],
          #         [6913255,8,0.000006,19107.81,2543430495,2543430793,1606935933881,2,0,0,0],
          #     ]
          #
          return self.parse_trades(response, market, since, limit)
  
      def fetch_accounts(self, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.check_required_credentials()
          request = {
              'omsId': omsId,
              'UserId': self.uid,
              'UserName': 'igor@ccxt.trade',
          }
          response = self.privateGetGetUserAccounts(self.extend(request, params))
          #
          #     [449]  # comma-separated list of account ids
          #
          result = []
          for i in range(0, len(response)):
              accountId = self.safe_string(response, i)
              result.append({
                  'id': accountId,
                  'type': None,
                  'currency': None,
                  'info': accountId,
              })
          return result
  
      def fetch_balance(self, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          self.load_accounts()
          defaultAccountId = self.safe_integer_2(self.options, 'accountId', 'AccountId', int(self.accounts[0]['id']))
          accountId = self.safe_integer_2(params, 'accountId', 'AccountId', defaultAccountId)
          params = self.omit(params, ['accountId', 'AccountId'])
          request = {
              'omsId': omsId,
              'AccountId': accountId,
          }
          response = self.privateGetGetAccountPositions(self.extend(request, params))
          #
          #     [
          #         {
          #             "OMSId":1,
          #             "AccountId":449,
          #             "ProductSymbol":"BTC",
          #             "ProductId":1,
          #             "Amount":10.000000000000000000000000000,
          #             "Hold":0,
          #             "PendingDeposits":0.0000000000000000000000000000,
          #             "PendingWithdraws":0.0000000000000000000000000000,
          #             "TotalDayDeposits":10.000000000000000000000000000,
          #             "TotalMonthDeposits":10.000000000000000000000000000,
          #             "TotalYearDeposits":10.000000000000000000000000000,
          #             "TotalDayDepositNotional":10.000000000000000000000000000,
          #             "TotalMonthDepositNotional":10.000000000000000000000000000,
          #             "TotalYearDepositNotional":10.000000000000000000000000000,
          #             "TotalDayWithdraws":0,
          #             "TotalMonthWithdraws":0,
          #             "TotalYearWithdraws":0,
          #             "TotalDayWithdrawNotional":0,
          #             "TotalMonthWithdrawNotional":0,
          #             "TotalYearWithdrawNotional":0,
          #             "NotionalProductId":8,
          #             "NotionalProductSymbol":"USDT",
          #             "NotionalValue":10.000000000000000000000000000,
          #             "NotionalHoldAmount":0,
          #             "NotionalRate":1
          #         },
          #     ]
          #
          result = {'info': response}
          for i in range(0, len(response)):
              balance = response[i]
              currencyId = self.safe_string(balance, 'ProductId')
              code = self.safe_currency_code(currencyId)
              account = self.account()
              account['total'] = self.safe_number(balance, 'Amount')
              account['used'] = self.safe_number(balance, 'Hold')
              result[code] = account
          return self.parse_balance(result)
  
      def parse_ledger_entry_type(self, type):
          types = {
              'Trade': 'trade',
              'Deposit': 'transaction',
              'Withdraw': 'transaction',
              'Transfer': 'transfer',
              'OrderHold': 'trade',
              'WithdrawHold': 'transaction',
              'DepositHold': 'transaction',
              'MarginHold': 'trade',
              'ManualHold': 'trade',
              'ManualEntry': 'trade',
              'MarginAcquisition': 'trade',
              'MarginRelinquish': 'trade',
              'MarginQuoteHold': 'trade',
          }
          return self.safe_string(types, type, type)
  
      def parse_ledger_entry(self, item, currency=None):
          #
          #     {
          #         "TransactionId":2663709493,
          #         "ReferenceId":68,
          #         "OMSId":1,
          #         "AccountId":449,
          #         "CR":10.000000000000000000000000000,
          #         "DR":0.0000000000000000000000000000,
          #         "Counterparty":3,
          #         "TransactionType":"Other",
          #         "ReferenceType":"Deposit",
          #         "ProductId":1,
          #         "Balance":10.000000000000000000000000000,
          #         "TimeStamp":1607532331591
          #     }
          #
          id = self.safe_string(item, 'TransactionId')
          account = self.safe_string(item, 'AccountId')
          referenceId = self.safe_string(item, 'ReferenceId')
          referenceAccount = self.safe_string(item, 'Counterparty')
          type = self.parse_ledger_entry_type(self.safe_string(item, 'ReferenceType'))
          currencyId = self.safe_string(item, 'ProductId')
          code = self.safe_currency_code(currencyId, currency)
          credit = self.safe_number(item, 'CR')
          debit = self.safe_number(item, 'DR')
          amount = None
          direction = None
          if credit > 0:
              amount = credit
              direction = 'in'
          elif debit > 0:
              amount = debit
              direction = 'out'
          timestamp = self.safe_integer(item, 'TimeStamp')
          before = None
          after = self.safe_number(item, 'Balance')
          if direction == 'out':
              before = self.sum(after, amount)
          elif direction == 'in':
              before = max(0, after - amount)
          status = 'ok'
          return {
              'info': item,
              'id': id,
              'direction': direction,
              'account': account,
              'referenceId': referenceId,
              'referenceAccount': referenceAccount,
              'type': type,
              'currency': code,
              'amount': amount,
              'before': before,
              'after': after,
              'status': status,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'fee': None,
          }
  
      def fetch_ledger(self, code=None, since=None, limit=None, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          self.load_accounts()
          defaultAccountId = self.safe_integer_2(self.options, 'accountId', 'AccountId', int(self.accounts[0]['id']))
          accountId = self.safe_integer_2(params, 'accountId', 'AccountId', defaultAccountId)
          params = self.omit(params, ['accountId', 'AccountId'])
          request = {
              'omsId': omsId,
              'AccountId': accountId,
          }
          if limit is not None:
              request['Depth'] = limit
          response = self.privateGetGetAccountTransactions(self.extend(request, params))
          #
          #     [
          #         {
          #             "TransactionId":2663709493,
          #             "ReferenceId":68,
          #             "OMSId":1,
          #             "AccountId":449,
          #             "CR":10.000000000000000000000000000,
          #             "DR":0.0000000000000000000000000000,
          #             "Counterparty":3,
          #             "TransactionType":"Other",
          #             "ReferenceType":"Deposit",
          #             "ProductId":1,
          #             "Balance":10.000000000000000000000000000,
          #             "TimeStamp":1607532331591
          #         },
          #     ]
          #
          currency = None
          if code is not None:
              currency = self.currency(code)
          return self.parse_ledger(response, currency, since, limit)
  
      def parse_order_status(self, status):
          statuses = {
              'Accepted': 'open',
              'Rejected': 'rejected',
              'Working': 'open',
              'Canceled': 'canceled',
              'Expired': 'expired',
              'FullyExecuted': 'closed',
          }
          return self.safe_string(statuses, status, status)
  
      def parse_order(self, order, market=None):
          #
          # createOrder
          #
          #     {
          #         "status":"Accepted",
          #         "errormsg":"",
          #         "OrderId": 2543565231
          #     }
          #
          # editOrder
          #
          #     {
          #         "ReplacementOrderId": 1234,
          #         "ReplacementClOrdId": 1561,
          #         "OrigOrderId": 5678,
          #         "OrigClOrdId": 91011,
          #     }
          #
          # fetchOpenOrders, fetchClosedOrders
          #
          #     {
          #         "Side":"Buy",
          #         "OrderId":2543565233,
          #         "Price":19010,
          #         "Quantity":0.345,
          #         "DisplayQuantity":0.345,
          #         "Instrument":8,
          #         "Account":449,
          #         "AccountName":"igor@ccxt.trade",
          #         "OrderType":"Limit",
          #         "ClientOrderId":0,
          #         "OrderState":"Working",
          #         "ReceiveTime":1607579326003,
          #         "ReceiveTimeTicks":637431761260028981,
          #         "LastUpdatedTime":1607579326005,
          #         "LastUpdatedTimeTicks":637431761260054714,
          #         "OrigQuantity":0.345,
          #         "QuantityExecuted":0,
          #         "GrossValueExecuted":0,
          #         "ExecutableValue":0,
          #         "AvgPrice":0,
          #         "CounterPartyId":0,
          #         "ChangeReason":"NewInputAccepted",
          #         "OrigOrderId":2543565233,
          #         "OrigClOrdId":0,
          #         "EnteredBy":446,
          #         "UserName":"igor@ccxt.trade",
          #         "IsQuote":false,
          #         "InsideAsk":19069.32,
          #         "InsideAskSize":0.099736,
          #         "InsideBid":19068.25,
          #         "InsideBidSize":1.330001,
          #         "LastTradePrice":19068.25,
          #         "RejectReason":"",
          #         "IsLockedIn":false,
          #         "CancelReason":"",
          #         "OrderFlag":"AddedToBook",
          #         "UseMargin":false,
          #         "StopPrice":0,
          #         "PegPriceType":"Unknown",
          #         "PegOffset":0,
          #         "PegLimitOffset":0,
          #         "IpAddress":null,
          #         "ClientOrderIdUuid":null,
          #         "OMSId":1
          #     }
          #
          id = self.safe_string_2(order, 'ReplacementOrderId', 'OrderId')
          timestamp = self.safe_integer(order, 'ReceiveTime')
          lastTradeTimestamp = self.safe_integer(order, 'LastUpdatedTime')
          marketId = self.safe_string(order, 'Instrument')
          symbol = self.safe_symbol(marketId, market)
          side = self.safe_string_lower(order, 'Side')
          type = self.safe_string_lower(order, 'OrderType')
          clientOrderId = self.safe_string_2(order, 'ReplacementClOrdId', 'ClientOrderId')
          price = self.safe_number(order, 'Price', 0.0)
          price = price if (price > 0.0) else None
          amount = self.safe_number(order, 'OrigQuantity')
          filled = self.safe_number(order, 'QuantityExecuted')
          cost = self.safe_number(order, 'GrossValueExecuted')
          average = self.safe_number(order, 'AvgPrice', 0.0)
          average = average if (average > 0) else None
          stopPrice = self.safe_number(order, 'StopPrice', 0.0)
          stopPrice = stopPrice if (stopPrice > 0.0) else None
          timeInForce = None
          status = self.parse_order_status(self.safe_string(order, 'OrderState'))
          fee = None
          trades = None
          return self.safe_order({
              'id': id,
              'clientOrderId': clientOrderId,
              'info': order,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': lastTradeTimestamp,
              'status': status,
              'symbol': symbol,
              'type': type,
              'timeInForce': timeInForce,
              'postOnly': None,
              'side': side,
              'price': price,
              'stopPrice': stopPrice,
              'cost': cost,
              'amount': amount,
              'filled': filled,
              'average': average,
              'remaining': None,
              'fee': fee,
              'trades': trades,
          })
  
      def create_order(self, symbol, type, side, amount, price=None, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          self.load_accounts()
          defaultAccountId = self.safe_integer_2(self.options, 'accountId', 'AccountId', int(self.accounts[0]['id']))
          accountId = self.safe_integer_2(params, 'accountId', 'AccountId', defaultAccountId)
          clientOrderId = self.safe_integer_2(params, 'ClientOrderId', 'clientOrderId')
          params = self.omit(params, ['accountId', 'AccountId', 'clientOrderId', 'ClientOrderId'])
          market = self.market(symbol)
          orderSide = 0 if (side == 'buy') else 1
          request = {
              'InstrumentId': int(market['id']),
              'omsId': omsId,
              'AccountId': accountId,
              'TimeInForce': 1,  # 0 Unknown, 1 GTC by default, 2 OPG execute as close to opening price as possible, 3 IOC immediate or canceled,  4 FOK fill-or-kill, 5 GTX good 'til executed, 6 GTD good 'til date
              # 'ClientOrderId': clientOrderId,  # defaults to 0
              # If self order is order A, OrderIdOCO refers to the order ID of an order B(which is not the order being created by self call).
              # If order B executes, then order A created by self call is canceled.
              # You can also set up order B to watch order A in the same way, but that may require an update to order B to make it watch self one, which could have implications for priority in the order book.
              # See CancelReplaceOrder and ModifyOrder.
              # 'OrderIdOCO': 0,  # The order ID if One Cancels the Other.
              # 'UseDisplayQuantity': False,  # If you enter a Limit order with a reserve, you must set UseDisplayQuantity to True
              'Side': orderSide,  # 0 Buy, 1 Sell, 2 Short, 3 unknown an error condition
              'Quantity': float(self.amount_to_precision(symbol, amount)),
              'OrderType': self.safe_integer(self.options['orderTypes'], self.capitalize(type)),  # 0 Unknown, 1 Market, 2 Limit, 3 StopMarket, 4 StopLimit, 5 TrailingStopMarket, 6 TrailingStopLimit, 7 BlockTrade
              # 'PegPriceType': 3,  # 1 Last, 2 Bid, 3 Ask, 4 Midpoint
              # 'LimitPrice': float(self.price_to_precision(symbol, price)),
          }
          # If OrderType=1(Market), Side=0(Buy), and LimitPrice is supplied, the Market order will execute up to the value specified
          if price is not None:
              request['LimitPrice'] = float(self.price_to_precision(symbol, price))
          if clientOrderId is not None:
              request['ClientOrderId'] = clientOrderId
          response = self.privatePostSendOrder(self.extend(request, params))
          #
          #     {
          #         "status":"Accepted",
          #         "errormsg":"",
          #         "OrderId": 2543565231
          #     }
          #
          return self.parse_order(response, market)
  
      def edit_order(self, id, symbol, type, side, amount, price=None, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          self.load_accounts()
          defaultAccountId = self.safe_integer_2(self.options, 'accountId', 'AccountId', int(self.accounts[0]['id']))
          accountId = self.safe_integer_2(params, 'accountId', 'AccountId', defaultAccountId)
          clientOrderId = self.safe_integer_2(params, 'ClientOrderId', 'clientOrderId')
          params = self.omit(params, ['accountId', 'AccountId', 'clientOrderId', 'ClientOrderId'])
          market = self.market(symbol)
          orderSide = 0 if (side == 'buy') else 1
          request = {
              'OrderIdToReplace': int(id),
              'InstrumentId': int(market['id']),
              'omsId': omsId,
              'AccountId': accountId,
              'TimeInForce': 1,  # 0 Unknown, 1 GTC by default, 2 OPG execute as close to opening price as possible, 3 IOC immediate or canceled,  4 FOK fill-or-kill, 5 GTX good 'til executed, 6 GTD good 'til date
              # 'ClientOrderId': clientOrderId,  # defaults to 0
              # If self order is order A, OrderIdOCO refers to the order ID of an order B(which is not the order being created by self call).
              # If order B executes, then order A created by self call is canceled.
              # You can also set up order B to watch order A in the same way, but that may require an update to order B to make it watch self one, which could have implications for priority in the order book.
              # See CancelReplaceOrder and ModifyOrder.
              # 'OrderIdOCO': 0,  # The order ID if One Cancels the Other.
              # 'UseDisplayQuantity': False,  # If you enter a Limit order with a reserve, you must set UseDisplayQuantity to True
              'Side': orderSide,  # 0 Buy, 1 Sell, 2 Short, 3 unknown an error condition
              'Quantity': float(self.amount_to_precision(symbol, amount)),
              'OrderType': self.safe_integer(self.options['orderTypes'], self.capitalize(type)),  # 0 Unknown, 1 Market, 2 Limit, 3 StopMarket, 4 StopLimit, 5 TrailingStopMarket, 6 TrailingStopLimit, 7 BlockTrade
              # 'PegPriceType': 3,  # 1 Last, 2 Bid, 3 Ask, 4 Midpoint
              # 'LimitPrice': float(self.price_to_precision(symbol, price)),
          }
          # If OrderType=1(Market), Side=0(Buy), and LimitPrice is supplied, the Market order will execute up to the value specified
          if price is not None:
              request['LimitPrice'] = float(self.price_to_precision(symbol, price))
          if clientOrderId is not None:
              request['ClientOrderId'] = clientOrderId
          response = self.privatePostCancelReplaceOrder(self.extend(request, params))
          #
          #     {
          #         "replacementOrderId": 1234,
          #         "replacementClOrdId": 1561,
          #         "origOrderId": 5678,
          #         "origClOrdId": 91011,
          #     }
          #
          return self.parse_order(response, market)
  
      def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          self.load_accounts()
          defaultAccountId = self.safe_integer_2(self.options, 'accountId', 'AccountId', int(self.accounts[0]['id']))
          accountId = self.safe_integer_2(params, 'accountId', 'AccountId', defaultAccountId)
          params = self.omit(params, ['accountId', 'AccountId'])
          request = {
              'omsId': omsId,
              'AccountId': accountId,
              # 'InstrumentId': market['id'],
              # 'TradeId': 123,  # If you specify TradeId, GetTradesHistory can return all states for a single trade
              # 'OrderId': 456,  # If specified, the call returns all trades associated with the order
              # 'UserId': integer. The ID of the logged-in user. If not specified, the call returns trades associated with the users belonging to the default account for the logged-in user of self OMS.
              # 'StartTimeStamp': long integer. The historical date and time at which to begin the trade report, in POSIX format. If not specified, reverts to the start date of self account on the trading venue.
              # 'EndTimeStamp': long integer. Date at which to end the trade report, in POSIX format.
              # 'Depth': integer. In self case, the count of trades to return, counting from the StartIndex. If Depth is not specified, returns all trades between BeginTimeStamp and EndTimeStamp, beginning at StartIndex.
              # 'StartIndex': 0  # from the most recent trade 0 and moving backwards in time
              # 'ExecutionId': 123,  # The ID of the individual buy or sell execution. If not specified, returns all.
          }
          market = None
          if symbol is not None:
              market = self.market(symbol)
              request['InstrumentId'] = market['id']
          if since is not None:
              request['StartTimeStamp'] = since
          if limit is not None:
              request['Depth'] = limit
          response = self.privateGetGetTradesHistory(self.extend(request, params))
          #
          #     [
          #         {
          #             "OMSId":1,
          #             "ExecutionId":16916567,
          #             "TradeId":14476351,
          #             "OrderId":2543565231,
          #             "AccountId":449,
          #             "AccountName":"igor@ccxt.trade",
          #             "SubAccountId":0,
          #             "ClientOrderId":0,
          #             "InstrumentId":8,
          #             "Side":"Sell",
          #             "OrderType":"Market",
          #             "Quantity":0.1230000000000000000000000000,
          #             "RemainingQuantity":0.0000000000000000000000000000,
          #             "Price":19069.310000000000000000000000,
          #             "Value":2345.5251300000000000000000000,
          #             "CounterParty":"7",
          #             "OrderTradeRevision":1,
          #             "Direction":"NoChange",
          #             "IsBlockTrade":false,
          #             "Fee":1.1727625650000000000000000000,
          #             "FeeProductId":8,
          #             "OrderOriginator":446,
          #             "UserName":"igor@ccxt.trade",
          #             "TradeTimeMS":1607565031569,
          #             "MakerTaker":"Taker",
          #             "AdapterTradeId":0,
          #             "InsideBid":19069.310000000000000000000000,
          #             "InsideBidSize":0.2400950000000000000000000000,
          #             "InsideAsk":19069.320000000000000000000000,
          #             "InsideAskSize":0.0997360000000000000000000000,
          #             "IsQuote":false,
          #             "CounterPartyClientUserId":1,
          #             "NotionalProductId":2,
          #             "NotionalRate":1.0000000000000000000000000000,
          #             "NotionalValue":2345.5251300000000000000000000,
          #             "NotionalHoldAmount":0,
          #             "TradeTime":637431618315686826
          #         }
          #     ]
          #
          return self.parse_trades(response, market, since, limit)
  
      def cancel_all_orders(self, symbol=None, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          self.load_accounts()
          defaultAccountId = self.safe_integer_2(self.options, 'accountId', 'AccountId', int(self.accounts[0]['id']))
          accountId = self.safe_integer_2(params, 'accountId', 'AccountId', defaultAccountId)
          params = self.omit(params, ['accountId', 'AccountId'])
          request = {
              'omsId': omsId,
              'AccountId': accountId,
          }
          if symbol is not None:
              market = self.market(symbol)
              request['IntrumentId'] = market['id']
          response = self.privatePostCancelAllOrders(self.extend(request, params))
          #
          #     {
          #         "result":true,
          #         "errormsg":null,
          #         "errorcode":0,
          #         "detail":null
          #     }
          #
          return response
  
      def cancel_order(self, id, symbol=None, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          self.load_accounts()
          # defaultAccountId = self.safe_integer_2(self.options, 'accountId', 'AccountId', int(self.accounts[0]['id']))
          # accountId = self.safe_integer_2(params, 'accountId', 'AccountId', defaultAccountId)
          # params = self.omit(params, ['accountId', 'AccountId'])
          market = None
          if symbol is not None:
              market = self.market(symbol)
          request = {
              'omsId': omsId,
              # 'AccountId': accountId,
          }
          clientOrderId = self.safe_integer_2(params, 'clientOrderId', 'ClOrderId')
          if clientOrderId is not None:
              request['ClOrderId'] = clientOrderId
          else:
              request['OrderId'] = int(id)
          params = self.omit(params, ['clientOrderId', 'ClOrderId'])
          response = self.privatePostCancelOrder(self.extend(request, params))
          order = self.parse_order(response, market)
          return self.extend(order, {
              'id': id,
              'clientOrderId': clientOrderId,
          })
  
      def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          self.load_accounts()
          defaultAccountId = self.safe_integer_2(self.options, 'accountId', 'AccountId', int(self.accounts[0]['id']))
          accountId = self.safe_integer_2(params, 'accountId', 'AccountId', defaultAccountId)
          params = self.omit(params, ['accountId', 'AccountId'])
          market = None
          if symbol is not None:
              market = self.market(symbol)
          request = {
              'omsId': omsId,
              'AccountId': accountId,
          }
          response = self.privateGetGetOpenOrders(self.extend(request, params))
          #
          #     [
          #         {
          #             "Side":"Buy",
          #             "OrderId":2543565233,
          #             "Price":19010,
          #             "Quantity":0.345,
          #             "DisplayQuantity":0.345,
          #             "Instrument":8,
          #             "Account":449,
          #             "AccountName":"igor@ccxt.trade",
          #             "OrderType":"Limit",
          #             "ClientOrderId":0,
          #             "OrderState":"Working",
          #             "ReceiveTime":1607579326003,
          #             "ReceiveTimeTicks":637431761260028981,
          #             "LastUpdatedTime":1607579326005,
          #             "LastUpdatedTimeTicks":637431761260054714,
          #             "OrigQuantity":0.345,
          #             "QuantityExecuted":0,
          #             "GrossValueExecuted":0,
          #             "ExecutableValue":0,
          #             "AvgPrice":0,
          #             "CounterPartyId":0,
          #             "ChangeReason":"NewInputAccepted",
          #             "OrigOrderId":2543565233,
          #             "OrigClOrdId":0,
          #             "EnteredBy":446,
          #             "UserName":"igor@ccxt.trade",
          #             "IsQuote":false,
          #             "InsideAsk":19069.32,
          #             "InsideAskSize":0.099736,
          #             "InsideBid":19068.25,
          #             "InsideBidSize":1.330001,
          #             "LastTradePrice":19068.25,
          #             "RejectReason":"",
          #             "IsLockedIn":false,
          #             "CancelReason":"",
          #             "OrderFlag":"AddedToBook",
          #             "UseMargin":false,
          #             "StopPrice":0,
          #             "PegPriceType":"Unknown",
          #             "PegOffset":0,
          #             "PegLimitOffset":0,
          #             "IpAddress":null,
          #             "ClientOrderIdUuid":null,
          #             "OMSId":1
          #         }
          #     ]
          #
          return self.parse_orders(response, market, since, limit)
  
      def fetch_orders(self, symbol=None, since=None, limit=None, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          self.load_accounts()
          defaultAccountId = self.safe_integer_2(self.options, 'accountId', 'AccountId', int(self.accounts[0]['id']))
          accountId = self.safe_integer_2(params, 'accountId', 'AccountId', defaultAccountId)
          params = self.omit(params, ['accountId', 'AccountId'])
          request = {
              'omsId': omsId,
              'AccountId': accountId,
              # 'ClientOrderId': clientOrderId,
              # 'OriginalOrderId': id,
              # 'OriginalClientOrderId': long integer,
              # 'UserId': integer,
              # 'InstrumentId': market['id'],
              # 'StartTimestamp': since,
              # 'EndTimestamp': self.milliseconds(),
              # 'Depth': limit,
              # 'StartIndex': 0,
          }
          market = None
          if symbol is not None:
              market = self.market(symbol)
              request['InstrumentId'] = market['id']
          if since is not None:
              request['StartTimeStamp'] = since
          if limit is not None:
              request['Depth'] = limit
          response = self.privateGetGetOrdersHistory(self.extend(request, params))
          #
          #     [
          #         {
          #             "Side":"Buy",
          #             "OrderId":2543565233,
          #             "Price":19010.000000000000000000000000,
          #             "Quantity":0.0000000000000000000000000000,
          #             "DisplayQuantity":0.3450000000000000000000000000,
          #             "Instrument":8,
          #             "Account":449,
          #             "AccountName":"igor@ccxt.trade",
          #             "OrderType":"Limit",
          #             "ClientOrderId":0,
          #             "OrderState":"Canceled",
          #             "ReceiveTime":1607579326003,
          #             "ReceiveTimeTicks":637431761260028981,
          #             "LastUpdatedTime":1607580965346,
          #             "LastUpdatedTimeTicks":637431777653463754,
          #             "OrigQuantity":0.3450000000000000000000000000,
          #             "QuantityExecuted":0.0000000000000000000000000000,
          #             "GrossValueExecuted":0.0000000000000000000000000000,
          #             "ExecutableValue":0.0000000000000000000000000000,
          #             "AvgPrice":0.0000000000000000000000000000,
          #             "CounterPartyId":0,
          #             "ChangeReason":"UserModified",
          #             "OrigOrderId":2543565233,
          #             "OrigClOrdId":0,
          #             "EnteredBy":446,
          #             "UserName":"igor@ccxt.trade",
          #             "IsQuote":false,
          #             "InsideAsk":19069.320000000000000000000000,
          #             "InsideAskSize":0.0997360000000000000000000000,
          #             "InsideBid":19068.250000000000000000000000,
          #             "InsideBidSize":1.3300010000000000000000000000,
          #             "LastTradePrice":19068.250000000000000000000000,
          #             "RejectReason":"",
          #             "IsLockedIn":false,
          #             "CancelReason":"UserModified",
          #             "OrderFlag":"AddedToBook, RemovedFromBook",
          #             "UseMargin":false,
          #             "StopPrice":0.0000000000000000000000000000,
          #             "PegPriceType":"Unknown",
          #             "PegOffset":0.0000000000000000000000000000,
          #             "PegLimitOffset":0.0000000000000000000000000000,
          #             "IpAddress":"5.228.233.138",
          #             "ClientOrderIdUuid":null,
          #             "OMSId":1
          #         },
          #     ]
          #
          return self.parse_orders(response, market, since, limit)
  
      def fetch_order(self, id, symbol=None, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          self.load_accounts()
          defaultAccountId = self.safe_integer_2(self.options, 'accountId', 'AccountId', int(self.accounts[0]['id']))
          accountId = self.safe_integer_2(params, 'accountId', 'AccountId', defaultAccountId)
          params = self.omit(params, ['accountId', 'AccountId'])
          market = None
          if symbol is not None:
              market = self.market(symbol)
          request = {
              'omsId': omsId,
              'AccountId': accountId,
              'OrderId': int(id),
          }
          response = self.privateGetGetOrderStatus(self.extend(request, params))
          #
          #     {
          #         "Side":"Sell",
          #         "OrderId":2543565232,
          #         "Price":0.0000000000000000000000000000,
          #         "Quantity":0.0000000000000000000000000000,
          #         "DisplayQuantity":0.0000000000000000000000000000,
          #         "Instrument":8,
          #         "Account":449,
          #         "AccountName":"igor@ccxt.trade",
          #         "OrderType":"Market",
          #         "ClientOrderId":0,
          #         "OrderState":"FullyExecuted",
          #         "ReceiveTime":1607569475591,
          #         "ReceiveTimeTicks":637431662755912377,
          #         "LastUpdatedTime":1607569475596,
          #         "LastUpdatedTimeTicks":637431662755960902,
          #         "OrigQuantity":1.0000000000000000000000000000,
          #         "QuantityExecuted":1.0000000000000000000000000000,
          #         "GrossValueExecuted":19068.270478610000000000000000,
          #         "ExecutableValue":0.0000000000000000000000000000,
          #         "AvgPrice":19068.270478610000000000000000,
          #         "CounterPartyId":0,
          #         "ChangeReason":"Trade",
          #         "OrigOrderId":2543565232,
          #         "OrigClOrdId":0,
          #         "EnteredBy":446,
          #         "UserName":"igor@ccxt.trade",
          #         "IsQuote":false,
          #         "InsideAsk":19069.320000000000000000000000,
          #         "InsideAskSize":0.0997360000000000000000000000,
          #         "InsideBid":19069.310000000000000000000000,
          #         "InsideBidSize":0.2400950000000000000000000000,
          #         "LastTradePrice":19069.310000000000000000000000,
          #         "RejectReason":"",
          #         "IsLockedIn":false,
          #         "CancelReason":"",
          #         "OrderFlag":"0",
          #         "UseMargin":false,
          #         "StopPrice":0.0000000000000000000000000000,
          #         "PegPriceType":"Unknown",
          #         "PegOffset":0.0000000000000000000000000000,
          #         "PegLimitOffset":0.0000000000000000000000000000,
          #         "IpAddress":"5.228.233.138",
          #         "ClientOrderIdUuid":null,
          #         "OMSId":1
          #     }
          #
          return self.parse_order(response, market)
  
      def fetch_order_trades(self, id, symbol=None, since=None, limit=None, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          self.load_accounts()
          # defaultAccountId = self.safe_integer_2(self.options, 'accountId', 'AccountId', int(self.accounts[0]['id']))
          # accountId = self.safe_integer_2(params, 'accountId', 'AccountId', defaultAccountId)
          # params = self.omit(params, ['accountId', 'AccountId'])
          market = None
          if symbol is not None:
              market = self.market(symbol)
          request = {
              'OMSId': int(omsId),
              # 'AccountId': accountId,
              'OrderId': id,
          }
          response = self.privatePostGetOrderHistoryByOrderId(self.extend(request, params))
          #
          #     [
          #         {
          #             "Side":"Sell",
          #             "OrderId":2543565235,
          #             "Price":18600.000000000000000000000000,
          #             "Quantity":0.0000000000000000000000000000,
          #             "DisplayQuantity":0.0000000000000000000000000000,
          #             "Instrument":8,
          #             "Account":449,
          #             "AccountName":"igor@ccxt.trade",
          #             "OrderType":"Limit",
          #             "ClientOrderId":0,
          #             "OrderState":"FullyExecuted",
          #             "ReceiveTime":1607585844956,
          #             "ReceiveTimeTicks":637431826449564182,
          #             "LastUpdatedTime":1607585844959,
          #             "LastUpdatedTimeTicks":637431826449593893,
          #             "OrigQuantity":0.1230000000000000000000000000,
          #             "QuantityExecuted":0.1230000000000000000000000000,
          #             "GrossValueExecuted":2345.3947500000000000000000000,
          #             "ExecutableValue":0.0000000000000000000000000000,
          #             "AvgPrice":19068.250000000000000000000000,
          #             "CounterPartyId":0,
          #             "ChangeReason":"Trade",
          #             "OrigOrderId":2543565235,
          #             "OrigClOrdId":0,
          #             "EnteredBy":446,
          #             "UserName":"igor@ccxt.trade",
          #             "IsQuote":false,
          #             "InsideAsk":19069.320000000000000000000000,
          #             "InsideAskSize":0.0997360000000000000000000000,
          #             "InsideBid":19068.250000000000000000000000,
          #             "InsideBidSize":1.3300010000000000000000000000,
          #             "LastTradePrice":19068.250000000000000000000000,
          #             "RejectReason":"",
          #             "IsLockedIn":false,
          #             "CancelReason":"",
          #             "OrderFlag":"0",
          #             "UseMargin":false,
          #             "StopPrice":0.0000000000000000000000000000,
          #             "PegPriceType":"Unknown",
          #             "PegOffset":0.0000000000000000000000000000,
          #             "PegLimitOffset":0.0000000000000000000000000000,
          #             "IpAddress":"5.228.233.138",
          #             "ClientOrderIdUuid":null,
          #             "OMSId":1
          #         },
          #     ]
          #
          grouped = self.group_by(response, 'ChangeReason')
          trades = self.safe_value(grouped, 'Trade', [])
          return self.parse_trades(trades, market, since, limit)
  
      def fetch_deposit_address(self, code, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          self.load_accounts()
          defaultAccountId = self.safe_integer_2(self.options, 'accountId', 'AccountId', int(self.accounts[0]['id']))
          accountId = self.safe_integer_2(params, 'accountId', 'AccountId', defaultAccountId)
          params = self.omit(params, ['accountId', 'AccountId'])
          currency = self.currency(code)
          request = {
              'omsId': omsId,
              'AccountId': accountId,
              'ProductId': currency['id'],
              'GenerateNewKey': False,
          }
          response = self.privateGetGetDepositInfo(self.extend(request, params))
          #
          #     {
          #         "result":true,
          #         "errormsg":null,
          #         "statuscode":0,
          #         "AssetManagerId":1,
          #         "AccountId":57922,
          #         "AssetId":16,
          #         "ProviderId":23,
          #         "DepositInfo":"[\"0x8A27564b5c30b91C93B1591821642420F323a210\"]"
          #     }
          #
          return self.parse_deposit_address(response, currency)
  
      def parse_deposit_address(self, depositAddress, currency=None):
          #
          # fetchDepositAddress, createDepositAddress
          #
          #     {
          #         "result":true,
          #         "errormsg":null,
          #         "statuscode":0,
          #         "AssetManagerId":1,
          #         "AccountId":449,
          #         "AssetId":1,
          #         "ProviderId":1,
          #         "DepositInfo":"[\"r3e95RwVsLH7yCbnMfyh7SA8FdwUJCB4S2?memo=241452010\"]"
          #     }
          #
          depositInfoString = self.safe_string(depositAddress, 'DepositInfo')
          depositInfo = json.loads(depositInfoString)
          depositInfoLength = len(depositInfo)
          lastString = self.safe_string(depositInfo, depositInfoLength - 1)
          parts = lastString.split('?memo=')
          address = self.safe_string(parts, 0)
          tag = self.safe_string(parts, 1)
          code = None
          if currency is not None:
              code = currency['code']
          self.check_address(address)
          return {
              'currency': code,
              'address': address,
              'tag': tag,
              'info': depositAddress,
          }
  
      def create_deposit_address(self, code, params={}):
          request = {
              'GenerateNewKey': True,
          }
          return self.fetch_deposit_address(code, self.extend(request, params))
  
      def fetch_deposits(self, code=None, since=None, limit=None, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          self.load_accounts()
          defaultAccountId = self.safe_integer_2(self.options, 'accountId', 'AccountId', int(self.accounts[0]['id']))
          accountId = self.safe_integer_2(params, 'accountId', 'AccountId', defaultAccountId)
          params = self.omit(params, ['accountId', 'AccountId'])
          currency = None
          if code is not None:
              currency = self.currency(code)
          request = {
              'omsId': omsId,
              'AccountId': accountId,
          }
          response = self.privateGetGetDeposits(self.extend(request, params))
          #
          #     [
          #         {
          #             "OMSId":1,
          #             "DepositId":44,
          #             "AccountId":449,
          #             "SubAccountId":0,
          #             "ProductId":4,
          #             "Amount":200.00000000000000000000000000,
          #             "LastUpdateTimeStamp":637431291261187806,
          #             "ProductType":"CryptoCurrency",
          #             "TicketStatus":"FullyProcessed",
          #             "DepositInfo":"{}",
          #             "DepositCode":"ab0e23d5-a9ce-4d94-865f-9ab464fb1de3",
          #             "TicketNumber":71,
          #             "NotionalProductId":13,
          #             "NotionalValue":200.00000000000000000000000000,
          #             "FeeAmount":0.0000000000000000000000000000,
          #         },
          #     ]
          #
          return self.parse_transactions(response, currency, since, limit)
  
      def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
          omsId = self.safe_integer(self.options, 'omsId', 1)
          self.load_markets()
          self.load_accounts()
          defaultAccountId = self.safe_integer_2(self.options, 'accountId', 'AccountId', int(self.accounts[0]['id']))
          accountId = self.safe_integer_2(params, 'accountId', 'AccountId', defaultAccountId)
          params = self.omit(params, ['accountId', 'AccountId'])
          currency = None
          if code is not None:
              currency = self.currency(code)
          request = {
              'omsId': omsId,
              'AccountId': accountId,
          }
          response = self.privateGetGetWithdraws(self.extend(request, params))
          #
          #     [
          #         {
          #             "Amount": 0.0,
          #             "FeeAmount": 0.0,
          #             "NotionalValue": 0.0,
          #             "WithdrawId": 0,
          #             "AssetManagerId": 0,
          #             "AccountId": 0,
          #             "AssetId": 0,
          #             "TemplateForm": "{\"TemplateType\": \"TetherRPCWithdraw\",\"Comment\": \"TestWithdraw\",\"ExternalAddress\": \"ms6C3pKAAr8gRCcnVebs8VRkVrjcvqNYv3\"}",
          #             "TemplateFormType": "TetherRPCWithdraw",
          #             "omsId": 0,
          #             "TicketStatus": 0,
          #             "TicketNumber": 0,
          #             "WithdrawTransactionDetails": "",
          #             "WithdrawType": "",
          #             "WithdrawCode": "490b4fa3-53fc-44f4-bd29-7e16be86fba3",
          #             "AssetType": 0,
          #             "Reaccepted": True,
          #             "NotionalProductId": 0
          #         },
          #     ]
          #
          return self.parse_transactions(response, currency, since, limit)
  
      def parse_transaction_status_by_type(self, status, type=None):
          statusesByType = {
              'deposit': {
                  'New': 'pending',  # new ticket awaiting operator review
                  'AdminProcessing': 'pending',  # an admin is looking at the ticket
                  'Accepted': 'pending',  # an admin accepts the ticket
                  'Rejected': 'rejected',  # admin rejects the ticket
                  'SystemProcessing': 'pending',  # automatic processing; an unlikely status for a deposit
                  'FullyProcessed': 'ok',  # the deposit has concluded
                  'Failed': 'failed',  # the deposit has failed for some reason
                  'Pending': 'pending',  # Account Provider has set status to pending
                  'Confirmed': 'pending',  # Account Provider confirms the deposit
                  'AmlProcessing': 'pending',  # anti-money-laundering process underway
                  'AmlAccepted': 'pending',  # anti-money-laundering process successful
                  'AmlRejected': 'rejected',  # deposit did not stand up to anti-money-laundering process
                  'AmlFailed': 'failed',  # anti-money-laundering process failed/did not complete
                  'LimitsAccepted': 'pending',  # deposit meets limits for fiat or crypto asset
                  'LimitsRejected': 'rejected',  # deposit does not meet limits for fiat or crypto asset
              },
              'withdrawal': {
                  'New': 'pending',  # awaiting operator review
                  'AdminProcessing': 'pending',  # An admin is looking at the ticket
                  'Accepted': 'pending',  # withdrawal will proceed
                  'Rejected': 'rejected',  # admin or automatic rejection
                  'SystemProcessing': 'pending',  # automatic processing underway
                  'FullyProcessed': 'ok',  # the withdrawal has concluded
                  'Failed': 'failed',  # the withdrawal failed for some reason
                  'Pending': 'pending',  # the admin has placed the withdrawal in pending status
                  'Pending2Fa': 'pending',  # user must click 2-factor authentication confirmation link
                  'AutoAccepted': 'pending',  # withdrawal will be automatically processed
                  'Delayed': 'pending',  # waiting for funds to be allocated for the withdrawal
                  'UserCanceled': 'canceled',  # withdraw canceled by user or Superuser
                  'AdminCanceled': 'canceled',  # withdraw canceled by Superuser
                  'AmlProcessing': 'pending',  # anti-money-laundering process underway
                  'AmlAccepted': 'pending',  # anti-money-laundering process complete
                  'AmlRejected': 'rejected',  # withdrawal did not stand up to anti-money-laundering process
                  'AmlFailed': 'failed',  # withdrawal did not complete anti-money-laundering process
                  'LimitsAccepted': 'pending',  # withdrawal meets limits for fiat or crypto asset
                  'LimitsRejected': 'rejected',  # withdrawal does not meet limits for fiat or crypto asset
                  'Submitted': 'pending',  # withdrawal sent to Account Provider; awaiting blockchain confirmation
                  'Confirmed': 'pending',  # Account Provider confirms that withdrawal is on the blockchain
                  'ManuallyConfirmed': 'pending',  # admin has sent withdrawal via wallet or admin function directly; marks ticket as FullyProcessed; debits account
                  'Confirmed2Fa': 'pending',  # user has confirmed withdraw via 2-factor authentication.
              },
          }
          statuses = self.safe_value(statusesByType, type, {})
          return self.safe_string(statuses, status, status)
  
      def parse_transaction(self, transaction, currency=None):
          #
          # fetchDeposits
          #
          #     {
          #         "OMSId":1,
          #         "DepositId":44,
          #         "AccountId":449,
          #         "SubAccountId":0,
          #         "ProductId":4,
          #         "Amount":200.00000000000000000000000000,
          #         "LastUpdateTimeStamp":637431291261187806,
          #         "ProductType":"CryptoCurrency",
          #         "TicketStatus":"FullyProcessed",
          #         "DepositInfo":"{}",
          #         "DepositCode":"ab0e23d5-a9ce-4d94-865f-9ab464fb1de3",
          #         "TicketNumber":71,
          #         "NotionalProductId":13,
          #         "NotionalValue":200.00000000000000000000000000,
          #         "FeeAmount":0.0000000000000000000000000000,
          #     }
          #
          # fetchWithdrawals
          #
          #     {
          #         "Amount": 0.0,
          #         "FeeAmount": 0.0,
          #         "NotionalValue": 0.0,
          #         "WithdrawId": 0,
          #         "AssetManagerId": 0,
          #         "AccountId": 0,
          #         "AssetId": 0,
          #         "TemplateForm": "{\"TemplateType\": \"TetherRPCWithdraw\",\"Comment\": \"TestWithdraw\",\"ExternalAddress\": \"ms6C3pKAAr8gRCcnVebs8VRkVrjcvqNYv3\"}",
          #         "TemplateFormType": "TetherRPCWithdraw",
          #         "omsId": 0,
          #         "TicketStatus": 0,
          #         "TicketNumber": 0,
          #         "WithdrawTransactionDetails": "",
          #         "WithdrawType": "",
          #         "WithdrawCode": "490b4fa3-53fc-44f4-bd29-7e16be86fba3",
          #         "AssetType": 0,
          #         "Reaccepted": True,
          #         "NotionalProductId": 0
          #     }
          #
          id = self.safe_string(transaction, 'DepositId')
          txid = None
          currencyId = self.safe_string(transaction, 'ProductId')
          code = self.safe_currency_code(currencyId, currency)
          timestamp = None
          type = None
          if 'DepositId' in transaction:
              type = 'deposit'
          elif 'WithdrawId' in transaction:
              type = 'withdrawal'
          templateFormString = self.safe_string(transaction, 'TemplateForm')
          address = None
          updated = self.safe_integer(transaction, 'LastUpdateTimeStamp')
          if templateFormString is not None:
              templateForm = json.loads(templateFormString)
              address = self.safe_string(templateForm, 'ExternalAddress')
              txid = self.safe_string(templateForm, 'TxId')
              timestamp = self.safe_integer(templateForm, 'TimeSubmitted')
              updated = self.safe_integer(templateForm, 'LastUpdated', updated)
          addressTo = address
          status = self.parse_transaction_status_by_type(self.safe_string(transaction, 'TicketStatus'), type)
          amount = self.safe_number(transaction, 'Amount')
          feeCost = self.safe_number(transaction, 'FeeAmount')
          fee = None
          if feeCost is not None:
              fee = {'currency': code, 'cost': feeCost}
          return {
              'info': transaction,
              'id': id,
              'txid': txid,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'address': address,
              'addressTo': addressTo,
              'addressFrom': None,
              'tag': None,
              'tagTo': None,
              'tagFrom': None,
              'type': type,
              'amount': amount,
              'currency': code,
              'status': status,
              'updated': updated,
              'fee': fee,
          }
  
      def nonce(self):
          return self.milliseconds()
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          url = self.urls['api'][api] + '/' + self.implode_params(path, params)
          query = self.omit(params, self.extract_params(path))
          if api == 'public':
              if query:
                  url += '?' + self.urlencode(query)
          elif api == 'private':
              self.check_required_credentials()
              nonce = str(self.nonce())
              auth = nonce + self.uid + self.apiKey
              signature = self.hmac(self.encode(auth), self.encode(self.secret))
              headers = {
                  'Nonce': nonce,
                  'APIKey': self.apiKey,
                  'Signature': signature,
                  'UserId': self.uid,
              }
              if method == 'POST':
                  headers['Content-Type'] = 'application/json'
                  body = self.json(query)
              else:
                  if query:
                      url += '?' + self.urlencode(query)
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  
      def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
          if code == 404:
              raise AuthenticationError(self.id + ' ' + body)
          if response is None:
              return
          #
          #     {"status":"Rejected","errormsg":"Not_Enough_Funds","errorcode":101}
          #     {"result":false,"errormsg":"Server Error","errorcode":102,"detail":null}
          #
          message = self.safe_string(response, 'errormsg')
          if (message is not None) and (message != ''):
              feedback = self.id + ' ' + body
              self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
              self.throw_broadly_matched_exception(self.exceptions['broad'], body, feedback)
              raise ExchangeError(feedback)
  