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

# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code

from ccxt.async_support.base.exchange import Exchange
import base64
import hashlib
import math
from ccxt.base.errors import ExchangeError
from ccxt.base.errors import AuthenticationError
from ccxt.base.errors import BadRequest
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 ExchangeNotAvailable


class anxpro (Exchange):

    def describe(self):
        return self.deep_extend(super(anxpro, self).describe(), {
            'id': 'anxpro',
            'name': 'ANXPro',
            'countries': ['JP', 'SG', 'HK', 'NZ'],
            'rateLimit': 1500,
            'userAgent': self.userAgents['chrome'],
            'has': {
                'CORS': False,
                'fetchCurrencies': True,
                'fetchOHLCV': False,
                'fetchTrades': False,
                'fetchOpenOrders': True,
                'fetchDepositAddress': True,
                'fetchTransactions': True,
                'fetchMyTrades': True,
                'createDepositAddress': False,
                'withdraw': True,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/27765983-fd8595da-5ec9-11e7-82e3-adb3ab8c2612.jpg',
                'api': {
                    'public': 'https://anxpro.com/api/2',
                    'private': 'https://anxpro.com/api/2',
                    'v3public': 'https://anxpro.com/api/3',
                    'v3private': 'https://anxpro.com/api/3',
                },
                'www': 'https://anxpro.com',
                'doc': [
                    'https://anxv2.docs.apiary.io',
                    'https://anxv3.docs.apiary.io',
                    'https://anxpro.com/pages/api',
                ],
            },
            'api': {
                'v3public': {
                    'get': [
                        'currencyStatic',
                    ],
                },
                'v3private': {
                    'post': [
                        'register/register',
                        'register/verifyRegistration',
                        'register/resendVerification',
                        'register/autoRegister',
                        'account',
                        'subaccount/new',
                        'transaction/list',
                        'order/list',
                        'trade/list',
                        'send',
                        'receive',
                        'receive/create',
                        'batch/new',
                        'batch/add',
                        'batch/list',
                        'batch/info',
                        'batch/closeForSend',
                        'order/new',
                        'order/info',
                        'order/cancel',
                        'retail/quote',
                        'retail/trade',
                        'validateAddress',
                        'address/check',
                        'alert/create',
                        'alert/delete',
                        'alert/list',
                        'kyc/personal',
                        'kyc/document',
                        'kyc/status',
                        'kyc/verifyCode',
                        'news/list',
                        'press/list',
                        'announcements/list',
                        'apiDoc/list',
                    ],
                },
                'public': {
                    'get': [
                        '{currency_pair}/money/ticker',
                        '{currency_pair}/money/depth/full',
                        '{currency_pair}/money/trade/fetch',  # disabled by ANXPro
                    ],
                },
                'private': {
                    'post': [
                        '{currency_pair}/money/order/add',
                        '{currency_pair}/money/order/cancel',
                        '{currency_pair}/money/order/quote',
                        '{currency_pair}/money/order/result',
                        '{currency_pair}/money/orders',
                        'money/{currency}/address',
                        'money/{currency}/send_simple',
                        'money/info',
                        'money/trade/list',
                        'money/wallet/history',
                    ],
                },
            },
            'httpExceptions': {
                '403': AuthenticationError,
            },
            'exceptions': {
                'exact': {
                    # v2
                    'Insufficient Funds': InsufficientFunds,
                    'Trade value too small': InvalidOrder,
                    'The currency pair is not supported': BadRequest,
                    'Order amount is too low': InvalidOrder,
                    'Order amount is too high': InvalidOrder,
                    'order rate is too low': InvalidOrder,
                    'order rate is too high': InvalidOrder,
                    'Too many open orders': InvalidOrder,
                    'Unexpected error': ExchangeError,
                    'Order Engine is offline': ExchangeNotAvailable,
                    'No executed order with that identifer found': OrderNotFound,
                    'Unknown server error, please contact support.': ExchangeError,
                },
            },
            'fees': {
                'trading': {
                    'tierBased': False,
                    'percentage': True,
                    'maker': 0.1 / 100,
                    'taker': 0.2 / 100,
                },
            },
            'options': {
                'fetchMyTradesMethod': 'private_post_money_trade_list',  # or 'v3private_post_trade_list'
            },
        })

    async def fetch_transactions(self, code=None, since=None, limit=None, params={}):
        # todo: migrate self to fetchLedger
        await self.load_markets()
        request = {}
        if since is not None:
            request['from'] = since
        if limit is not None:
            request['max'] = limit
        currency = None if (code is None) else self.currency(code)
        if currency is not None:
            request['ccy'] = currency['id']
        response = await self.v3privatePostTransactionList(self.extend(request, params))
        #
        #     {
        #         transactions: [
        #             {
        #                 transactionClass: 'COIN',
        #                 uuid: '7896857b-2ed6-4c62-ba4c-619837438d9c',
        #                 userUuid: '82027ee9-cb59-4f29-80d6-f7e793f39ad4',
        #                 amount: -17865.72689976,
        #                 fee: 1,
        #                 balanceBefore: 17865.72689976,
        #                 balanceAfter: 17865.72689976,
        #                 ccy: 'XRP',
        #                 transactionState: 'PROCESSED',
        #                 transactionType: 'WITHDRAWAL',
        #                 received: '1551357946000',
        #                 processed: '1551357946000',
        #                 timestampMillis: '1557441435932',
        #                 displayTitle: 'Coin Withdrawal',
        #                 displayDescription: 'Withdraw to: rw2ciyaNshpHe7bCHo4bRWq6pqqynnWKQg?dt=3750180345',
        #                 coinAddress: 'rw2ciyaNshpHe7bCHo4bRWq6pqqynnWKQg?dt=3750180345',
        #                 coinTransactionId: '68444611753E9D8F5C33DCBBF43F01391070F79CAFCF7625397D1CEFA519064A',
        #                 subAccount: [
        #                     Object
        #                 ]
        #             },
        #             {
        #                 transactionClass: 'FILL',
        #                 uuid: 'a5ae54de-c14a-4ef8-842d-56000c9dc7ab',
        #                 userUuid: '82027ee9-cb59-4f29-80d6-f7e793f39ad4',
        #                 amount: 0.09006364,
        #                 fee: 0.00018013,
        #                 balanceBefore: 0.3190001,
        #                 balanceAfter: 0.40888361,
        #                 ccy: 'BTC',
        #                 transactionState: 'PROCESSED',
        #                 transactionType: 'FILL_CREDIT',
        #                 received: '1551357057000',
        #                 processed: '1551357057000',
        #                 timestampMillis: '1557441435956',
        #                 displayTitle: 'Order Fill',
        #                 displayDescription: 'Buy BTC @ 3008.53930 EUR/BTC'
        #             }
        #         ],
        #         count: ...,
        #         timestamp: '1557441435971',
        #         resultCode: 'OK'
        #     }
        #
        transactions = self.safe_value(response, 'transactions', [])
        grouped = self.group_by(transactions, 'transactionType', [])
        depositsAndWithdrawals = self.array_concat(self.safe_value(grouped, 'DEPOSIT', []), self.safe_value(grouped, 'WITHDRAWAL', []))
        return self.parseTransactions(depositsAndWithdrawals, currency, since, limit)

    def parse_transaction(self, transaction, currency=None):
        #
        # withdrawal
        #
        #     {
        #         transactionClass: 'COIN',
        #         uuid: 'bff91938-4dad-4c48-9db6-468324ce96c1',
        #         userUuid: '82027ee9-cb59-4f29-80d6-f7e793f39ad4',
        #         amount: -0.40888361,
        #         fee: 0.002,
        #         balanceBefore: 0.40888361,
        #         balanceAfter: 0.40888361,
        #         ccy: 'BTC',
        #         transactionState: 'PROCESSED',
        #         transactionType: 'WITHDRAWAL',
        #         received: '1551357156000',
        #         processed: '1551357156000',
        #         timestampMillis: '1557441846213',
        #         displayTitle: 'Coin Withdrawal',
        #         displayDescription: 'Withdraw to: 1AHnhqbvbYx3rnZx8uC7NbFZaTe4tafFHX',
        #         coinAddress: '1AHnhqbvbYx3rnZx8uC7NbFZaTe4tafFHX',
        #         coinTransactionId:
        #         'ab80abcb62bf6261ebc827c73dd59a4ce15d740b6ba734af6542f43b6485b923',
        #         subAccount: {
        #             uuid: '652e1add-0d0b-462c-a03c-d6197c825c1a',
        #             name: 'DEFAULT'
        #         }
        #     }
        #
        # deposit
        #
        #     {
        #         "transactionClass": "COIN",
        #         "uuid": "eb65576f-c1a8-423c-8e2f-fa50109b2eab",
        #         "userUuid": "82027ee9-cb59-4f29-80d6-f7e793f39ad4",
        #         "amount": 3.99287184,
        #         "fee": 0,
        #         "balanceBefore": 8.39666034,
        #         "balanceAfter": 12.38953218,
        #         "ccy": "ETH",
        #         "transactionState": "PROCESSED",
        #         "transactionType": "DEPOSIT",
        #         "received": "1529420056000",
        #         "processed": "1529420766000",
        #         "timestampMillis": "1557442743854",
        #         "displayTitle": "Coin Deposit",
        #         "displayDescription": "Deposit to: 0xf123aa44fadea913a7da99cc2ee202db684ce0e3",
        #         "coinTransactionId": "0x33a3e5ea7c034dc5324a88aa313962df0a5d571ab4bcc3cb00b876b1bdfc54f7",
        #         "coinConfirmations": 51,
        #         "coinConfirmationsRequired": 45,
        #         "subAccount": {"uuid": "aba1de05-c7c6-49d7-84ab-a6aca0e827b6", "name": "DEFAULT"}
        #     }
        #
        timestamp = self.safe_integer(transaction, 'received')
        updated = self.safe_integer(transaction, 'processed')
        transactionType = self.safe_string(transaction, 'transactionType')
        type = None
        amount = self.safe_float(transaction, 'amount')
        address = self.safe_string(transaction, 'coinAddress')
        tag = None
        if transactionType == 'WITHDRAWAL':
            type = 'withdrawal'
            amount = -amount
            if address:
                #  xrp: "coinAddress": "rw2ciyaNshpHe7bCHo4bRWq6pqqynnWKQg?dt=3750180345",
                if address.find('?dt=') >= 0:
                    parts = address.split('?dt=')
                    address = parts[0]
                    tag = parts[1]
        elif transactionType == 'DEPOSIT':
            if not address:
                displayDescription = self.safe_string(transaction, 'displayDescription')
                addressText = displayDescription.replace('Deposit to: ', '')
                if len(addressText) > 0:
                    #  eth: "displayDescription": "Deposit to: 0xf123aa44fadea913a7da99cc2ee202db684ce0e3",
                    #  xrp: "displayDescription": "Deposit to: rUjxty1WWLwX1evhKf3C2XNZDMcXEZ9ToJ?dt=504562345",
                    if addressText.find('?dt=') >= 0:
                        parts = addressText.split('?dt=')
                        address = parts[0]
                        tag = parts[1]
                    else:
                        address = addressText
            type = 'deposit'
        currencyId = self.safe_string(transaction, 'ccy')
        code = self.safe_currency_code(currencyId)
        transactionState = self.safe_string(transaction, 'transactionState')
        status = self.parse_transaction_status(transactionState)
        feeCost = self.safe_float(transaction, 'fee')
        netAmount = amount - feeCost
        return {
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'id': self.safe_string(transaction, 'uuid'),
            'currency': code,
            'amount': netAmount,
            'address': address,
            'tag': tag,
            'status': status,
            'type': type,
            'updated': updated,
            'txid': self.safe_string(transaction, 'coinTransactionId'),
            'fee': {
                'cost': feeCost,
                'currency': code,
            },
            'info': transaction,
        }

    def parse_transaction_status(self, status):
        statuses = {
            'PROCESSED': 'ok',
            'REVERSED': 'canceled',
            'CANCELLED_INSUFFICIENT_FUNDS': 'canceled',
            'CANCELLED_LIMIT_BREACH': 'canceled',
        }
        return self.safe_string(statuses, status, status)

    async def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
        await self.load_markets()
        #
        # v2
        #
        #     {
        #         result: 'success',
        #         data: [
        #             {
        #                 tradeId: 'c2ed821d-717a-4b7e-beb0-a9ba60e8f5a0',
        #                 orderId: '5a65ae21-c7a8-4009-b3af-306c2ad21a02',
        #                 timestamp: '1551357057000',
        #                 tradedCurrencyFillAmount: '0.09006364',
        #                 settlementCurrencyFillAmount: '270.96',
        #                 settlementCurrencyFillAmountUnrounded: '270.96000000',
        #                 price: '3008.53930',
        #                 ccyPair: 'BTCEUR',
        #                 side: 'BUY'  # missing in v3
        #             },
        #             {
        #                 tradeId: 'fc0d3a9d-8b0b-4dff-b2e9-edd160785210',
        #                 orderId: '8161ae6e-251a-4eed-a56f-d3d6555730c1',
        #                 timestamp: '1551357033000',
        #                 tradedCurrencyFillAmount: '0.06521746',
        #                 settlementCurrencyFillAmount: '224.09',
        #                 settlementCurrencyFillAmountUnrounded: '224.09000000',
        #                 price: '3436.04305',
        #                 ccyPair: 'BTCUSD',
        #                 side: 'BUY'  # missing in v3
        #             },
        #         ]
        #     }
        #
        # v3
        #
        #     {
        #         trades: [
        #             {
        #                 tradeId: 'c2ed821d-717a-4b7e-beb0-a9ba60e8f5a0',
        #                 orderId: '5a65ae21-c7a8-4009-b3af-306c2ad21a02',
        #                 timestamp: '1551357057000',
        #                 tradedCurrencyFillAmount: '0.09006364',
        #                 settlementCurrencyFillAmount: '270.96',
        #                 settlementCurrencyFillAmountUnrounded: '270.96000000',
        #                 price: '3008.53930',
        #                 ccyPair: 'BTCEUR'
        #             },
        #             {
        #                 tradeId: 'fc0d3a9d-8b0b-4dff-b2e9-edd160785210',
        #                 orderId: '8161ae6e-251a-4eed-a56f-d3d6555730c1',
        #                 timestamp: '1551357033000',
        #                 tradedCurrencyFillAmount: '0.06521746',
        #                 settlementCurrencyFillAmount: '224.09',
        #                 settlementCurrencyFillAmountUnrounded: '224.09000000',
        #                 price: '3436.04305',
        #                 ccyPair: 'BTCUSD'
        #             },
        #         ],
        #         count: 3,
        #         timestamp: '1557438456732',
        #         resultCode: 'OK'
        #     }
        #
        request = {}
        if limit is not None:
            request['max'] = limit
        method = self.safe_string(self.options, 'fetchMyTradesMethod', 'private_post_money_trade_list')
        response = await getattr(self, method)(self.extend(request, params))
        trades = self.safe_value_2(response, 'trades', 'data', [])
        market = None if (symbol is None) else self.market(symbol)
        return self.parse_trades(trades, market, since, limit)

    def parse_trade(self, trade, market=None):
        #
        # v2
        #
        #     {
        #         tradeId: 'fc0d3a9d-8b0b-4dff-b2e9-edd160785210',
        #         orderId: '8161ae6e-251a-4eed-a56f-d3d6555730c1',
        #         timestamp: '1551357033000',
        #         tradedCurrencyFillAmount: '0.06521746',
        #         settlementCurrencyFillAmount: '224.09',
        #         settlementCurrencyFillAmountUnrounded: '224.09000000',
        #         price: '3436.04305',
        #         ccyPair: 'BTCUSD',
        #         side: 'BUY',  # missing in v3
        #     }
        #
        # v3
        #
        #     {
        #         tradeId: 'fc0d3a9d-8b0b-4dff-b2e9-edd160785210',
        #         orderId: '8161ae6e-251a-4eed-a56f-d3d6555730c1',
        #         timestamp: '1551357033000',
        #         tradedCurrencyFillAmount: '0.06521746',
        #         settlementCurrencyFillAmount: '224.09',
        #         settlementCurrencyFillAmountUnrounded: '224.09000000',
        #         price: '3436.04305',
        #         ccyPair: 'BTCUSD'
        #     }
        #
        id = self.safe_string(trade, 'tradeId')
        orderId = self.safe_string(trade, 'orderId')
        timestamp = self.safe_integer(trade, 'timestamp')
        price = self.safe_float(trade, 'price')
        amount = self.safe_float(trade, 'tradedCurrencyFillAmount')
        cost = self.safe_float(trade, 'settlementCurrencyFillAmount')
        side = self.safe_string_lower(trade, 'side')
        return {
            'id': id,
            'order': orderId,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'symbol': self.find_symbol(self.safe_string(trade, 'ccyPair')),
            'type': None,
            'side': side,
            'price': price,
            'amount': amount,
            'cost': cost,
            'fee': None,
            'info': trade,
        }

    async def fetch_currencies(self, params={}):
        response = await self.v3publicGetCurrencyStatic(params)
        #
        #   {
        #     "currencyStatic": {
        #       "currencies": {
        #         "HKD": {
        #           "decimals": 2,
        #           "minOrderSize": 1.00000000,
        #           "maxOrderSize": 10000000000.00000000,
        #           "displayDenominator": 1,
        #           "summaryDecimals": 0,
        #           "displayUnit": "HKD",
        #           "symbol": "$",
        #           "type": "FIAT",
        #           "engineSettings": {
        #             "depositsEnabled": False,
        #             "withdrawalsEnabled": True,
        #             "displayEnabled": True,
        #             "mobileAccessEnabled": True
        #           },
        #           "minOrderValue": 1.00000000,
        #           "maxOrderValue": 10000000000.00000000,
        #           "maxMarketOrderValue": 36000.00000000,
        #           "maxMarketOrderSize": 36000.00000000,
        #           "assetDivisibility": 0
        #         },
        #         "ETH": {
        #           "decimals": 8,
        #           "minOrderSize": 0.00010000,
        #           "maxOrderSize": 1000000000.00000000,
        #           "type": "CRYPTO",
        #           "confirmationThresholds": [
        #             {"confosRequired": 30, "threshold": 0.50000000},
        #             {"confosRequired": 45, "threshold": 10.00000000},
        #             {"confosRequired": 70}
        #           ],
        #           "networkFee": 0.00500000,
        #           "engineSettings": {
        #             "depositsEnabled": True,
        #             "withdrawalsEnabled": True,
        #             "displayEnabled": True,
        #             "mobileAccessEnabled": True
        #           },
        #           "minOrderValue": 0.00010000,
        #           "maxOrderValue": 10000000000.00000000,
        #           "maxMarketOrderValue": 10000000000.00000000,
        #           "maxMarketOrderSize": 1000000000.00000000,
        #           "digitalCurrencyType": "ETHEREUM",
        #           "assetDivisibility": 0,
        #           "assetIcon": "/images/currencies/crypto/ETH.svg"
        #         },
        #       },
        #       "currencyPairs": {
        #         "ETHUSD": {
        #           "priceDecimals": 5,
        #           "engineSettings": {
        #             "tradingEnabled": True,
        #             "displayEnabled": True,
        #             "cancelOnly": True,
        #             "verifyRequired": False,
        #             "restrictedBuy": False,
        #             "restrictedSell": False
        #           },
        #           "minOrderRate": 10.00000000,
        #           "maxOrderRate": 10000.00000000,
        #           "displayPriceDecimals": 5,
        #           "tradedCcy": "ETH",
        #           "settlementCcy": "USD",
        #           "preferredMarket": "ANX",
        #           "chartEnabled": True,
        #           "simpleTradeEnabled": False
        #         },
        #       },
        #     },
        #     "timestamp": "1549840691039",
        #     "resultCode": "OK"
        #   }
        #
        currencyStatic = self.safe_value(response, 'currencyStatic', {})
        currencies = self.safe_value(currencyStatic, 'currencies', {})
        result = {}
        ids = list(currencies.keys())
        for i in range(0, len(ids)):
            id = ids[i]
            currency = currencies[id]
            code = self.safe_currency_code(id)
            engineSettings = self.safe_value(currency, 'engineSettings')
            depositsEnabled = self.safe_value(engineSettings, 'depositsEnabled')
            withdrawalsEnabled = self.safe_value(engineSettings, 'withdrawalsEnabled')
            displayEnabled = self.safe_value(engineSettings, 'displayEnabled')
            active = depositsEnabled and withdrawalsEnabled and displayEnabled
            precision = self.safe_integer(currency, 'decimals')
            fee = self.safe_float(currency, 'networkFee')
            type = self.safe_string_lower(currency, 'type')
            result[code] = {
                'id': id,
                'code': code,
                'info': currency,
                'name': code,
                'type': type,
                'active': active,
                'precision': precision,
                'fee': fee,
                'limits': {
                    'amount': {
                        'min': self.safe_float(currency, 'minOrderSize'),
                        'max': self.safe_float(currency, 'maxOrderSize'),
                    },
                    'price': {
                        'min': None,
                        'max': None,
                    },
                    'cost': {
                        'min': self.safe_float(currency, 'minOrderValue'),
                        'max': self.safe_float(currency, 'maxOrderValue'),
                    },
                    'withdraw': {
                        'min': None,
                        'max': None,
                    },
                },
            }
        return result

    async def fetch_markets(self, params={}):
        response = await self.v3publicGetCurrencyStatic(params)
        #
        #   {
        #     "currencyStatic": {
        #       "currencies": {
        #         "HKD": {
        #           "decimals": 2,
        #           "minOrderSize": 1.00000000,
        #           "maxOrderSize": 10000000000.00000000,
        #           "displayDenominator": 1,
        #           "summaryDecimals": 0,
        #           "displayUnit": "HKD",
        #           "symbol": "$",
        #           "type": "FIAT",
        #           "engineSettings": {
        #             "depositsEnabled": False,
        #             "withdrawalsEnabled": True,
        #             "displayEnabled": True,
        #             "mobileAccessEnabled": True
        #           },
        #           "minOrderValue": 1.00000000,
        #           "maxOrderValue": 10000000000.00000000,
        #           "maxMarketOrderValue": 36000.00000000,
        #           "maxMarketOrderSize": 36000.00000000,
        #           "assetDivisibility": 0
        #         },
        #         "ETH": {
        #           "decimals": 8,
        #           "minOrderSize": 0.00010000,
        #           "maxOrderSize": 1000000000.00000000,
        #           "type": "CRYPTO",
        #           "confirmationThresholds": [
        #             {"confosRequired": 30, "threshold": 0.50000000},
        #             {"confosRequired": 45, "threshold": 10.00000000},
        #             {"confosRequired": 70}
        #           ],
        #           "networkFee": 0.00500000,
        #           "engineSettings": {
        #             "depositsEnabled": True,
        #             "withdrawalsEnabled": True,
        #             "displayEnabled": True,
        #             "mobileAccessEnabled": True
        #           },
        #           "minOrderValue": 0.00010000,
        #           "maxOrderValue": 10000000000.00000000,
        #           "maxMarketOrderValue": 10000000000.00000000,
        #           "maxMarketOrderSize": 1000000000.00000000,
        #           "digitalCurrencyType": "ETHEREUM",
        #           "assetDivisibility": 0,
        #           "assetIcon": "/images/currencies/crypto/ETH.svg"
        #         },
        #       },
        #       "currencyPairs": {
        #         "ETHUSD": {
        #           "priceDecimals": 5,
        #           "engineSettings": {
        #             "tradingEnabled": True,
        #             "displayEnabled": True,
        #             "cancelOnly": True,
        #             "verifyRequired": False,
        #             "restrictedBuy": False,
        #             "restrictedSell": False
        #           },
        #           "minOrderRate": 10.00000000,
        #           "maxOrderRate": 10000.00000000,
        #           "displayPriceDecimals": 5,
        #           "tradedCcy": "ETH",
        #           "settlementCcy": "USD",
        #           "preferredMarket": "ANX",
        #           "chartEnabled": True,
        #           "simpleTradeEnabled": False
        #         },
        #       },
        #     },
        #     "timestamp": "1549840691039",
        #     "resultCode": "OK"
        #   }
        #
        currencyStatic = self.safe_value(response, 'currencyStatic', {})
        currencies = self.safe_value(currencyStatic, 'currencies', {})
        currencyPairs = self.safe_value(currencyStatic, 'currencyPairs', {})
        result = []
        ids = list(currencyPairs.keys())
        for i in range(0, len(ids)):
            id = ids[i]
            market = currencyPairs[id]
            #
            #     "ETHUSD": {
            #       "priceDecimals": 5,
            #       "engineSettings": {
            #         "tradingEnabled": True,
            #         "displayEnabled": True,
            #         "cancelOnly": True,
            #         "verifyRequired": False,
            #         "restrictedBuy": False,
            #         "restrictedSell": False
            #       },
            #       "minOrderRate": 10.00000000,
            #       "maxOrderRate": 10000.00000000,
            #       "displayPriceDecimals": 5,
            #       "tradedCcy": "ETH",
            #       "settlementCcy": "USD",
            #       "preferredMarket": "ANX",
            #       "chartEnabled": True,
            #       "simpleTradeEnabled": False
            #     },
            #
            baseId = self.safe_string(market, 'tradedCcy')
            quoteId = self.safe_string(market, 'settlementCcy')
            base = self.safe_currency_code(baseId)
            quote = self.safe_currency_code(quoteId)
            symbol = base + '/' + quote
            baseCurrency = self.safe_value(currencies, baseId, {})
            quoteCurrency = self.safe_value(currencies, quoteId, {})
            precision = {
                'price': self.safe_integer(market, 'priceDecimals'),
                'amount': self.safe_integer(baseCurrency, 'decimals'),
            }
            engineSettings = self.safe_value(market, 'engineSettings')
            displayEnabled = self.safe_value(engineSettings, 'displayEnabled')
            tradingEnabled = self.safe_value(engineSettings, 'tradingEnabled')
            active = displayEnabled and tradingEnabled
            result.append({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'baseId': baseId,
                'quoteId': quoteId,
                'precision': precision,
                'active': active,
                'limits': {
                    'price': {
                        'min': self.safe_float(market, 'minOrderRate'),
                        'max': self.safe_float(market, 'maxOrderRate'),
                    },
                    'amount': {
                        'min': self.safe_float(baseCurrency, 'minOrderSize'),
                        'max': self.safe_float(baseCurrency, 'maxOrderSize'),
                    },
                    'cost': {
                        'min': self.safe_float(quoteCurrency, 'minOrderValue'),
                        'max': self.safe_float(quoteCurrency, 'maxOrderValue'),
                    },
                },
                'info': market,
            })
        return result

    async def fetch_balance(self, params={}):
        await self.load_markets()
        response = await self.privatePostMoneyInfo(params)
        balance = self.safe_value(response, 'data', {})
        wallets = self.safe_value(balance, 'Wallets', {})
        currencyIds = list(wallets.keys())
        result = {'info': balance}
        for c in range(0, len(currencyIds)):
            currencyId = currencyIds[c]
            code = self.safe_currency_code(currencyId)
            account = self.account()
            wallet = self.safe_value(wallets, currencyId)
            account['free'] = self.safe_float(wallet['Available_Balance'], 'value')
            account['total'] = self.safe_float(wallet['Balance'], 'value')
            result[code] = account
        return self.parse_balance(result)

    async def fetch_order_book(self, symbol, limit=None, params={}):
        await self.load_markets()
        request = {
            'currency_pair': self.market_id(symbol),
        }
        response = await self.publicGetCurrencyPairMoneyDepthFull(self.extend(request, params))
        orderbook = self.safe_value(response, 'data', {})
        timestamp = self.safe_integer_product(orderbook, 'dataUpdateTime', 0.001)
        return self.parse_order_book(orderbook, timestamp, 'bids', 'asks', 'price', 'amount')

    async def fetch_ticker(self, symbol, params={}):
        await self.load_markets()
        request = {
            'currency_pair': self.market_id(symbol),
        }
        response = await self.publicGetCurrencyPairMoneyTicker(self.extend(request, params))
        ticker = self.safe_value(response, 'data', {})
        timestamp = self.safe_integer_product(ticker, 'dataUpdateTime', 0.001)
        bid = self.safe_float(ticker['buy'], 'value')
        ask = self.safe_float(ticker['sell'], 'value')
        baseVolume = self.safe_float(ticker['vol'], 'value')
        last = self.safe_float(ticker['last'], 'value')
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'high': self.safe_float(ticker['high'], 'value'),
            'low': self.safe_float(ticker['low'], 'value'),
            'bid': bid,
            'bidVolume': None,
            'ask': ask,
            'askVolume': None,
            'vwap': None,
            'open': None,
            'close': last,
            'last': last,
            'previousClose': None,
            'change': None,
            'percentage': None,
            'average': self.safe_float(ticker['avg'], 'value'),
            'baseVolume': baseVolume,
            'quoteVolume': None,
            'info': ticker,
        }

    async def fetch_trades(self, symbol, since=None, limit=None, params={}):
        raise NotSupported(self.id + ' switched off the trades endpoint, see their docs at https://docs.anxv2.apiary.io')

    async def fetch_orders(self, symbol=None, since=None, limit=None, params={}):
        await self.load_markets()
        request = {}
        if limit is not None:
            request['max'] = limit
        response = await self.v3privatePostOrderList(self.extend(request, params))
        orders = self.safe_value(response, 'orders', [])
        market = None if (symbol is None) else self.market(symbol)
        return self.parse_orders(orders, market, since, limit)

    async def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'currency_pair': market['id'],
        }
        # ANXPro will return all symbol pairs regardless of what is specified in request
        response = await self.privatePostCurrencyPairMoneyOrders(self.extend(request, params))
        #
        #     {
        #         "result": "success",
        #         "data": [
        #             {
        #                 "oid": "e74305c7-c424-4fbc-a8a2-b41d8329deb0",
        #                 "currency": "HKD",
        #                 "item": "BTC",
        #                 "type": "offer",
        #                 "amount": {
        #                     "currency": "BTC",
        #                     "display": "10.00000000 BTC",
        #                     "display_short": "10.00 BTC",
        #                     "value": "10.00000000",
        #                     "value_int": "1000000000"
        #                 },
        #                 "effective_amount": {
        #                     "currency": "BTC",
        #                     "display": "10.00000000 BTC",
        #                     "display_short": "10.00 BTC",
        #                     "value": "10.00000000",
        #                     "value_int": "1000000000"
        #                 },
        #                 "price": {
        #                     "currency": "HKD",
        #                     "display": "412.34567 HKD",
        #                     "display_short": "412.35 HKD",
        #                     "value": "412.34567",
        #                     "value_int": "41234567"
        #                 },
        #                 "status": "open",
        #                 "date": 1393411075000,
        #                 "priority": 1393411075000000,
        #                 "actions": []
        #             },
        #            ...
        #         ]
        #     }
        #
        return self.parse_orders(self.safe_value(response, 'data', {}), market, since, limit)

    def parse_order(self, order, market=None):
        if 'orderId' in order:
            return self.parse_order_v3(order, market)
        else:
            return self.parse_order_v2(order, market)

    def parse_order_status(self, status):
        statuses = {
            'ACTIVE': 'open',
            'FULL_FILL': 'closed',
            'CANCEL': 'canceled',
        }
        return self.safe_string(statuses, status, status)

    def parse_order_v3(self, order, market=None):
        #
        # v3
        #
        #     {
        #         orderType: 'LIMIT',
        #         tradedCurrency: 'XRP',
        #         settlementCurrency: 'BTC',
        #         tradedCurrencyAmount: '400.00000000',
        #         buyTradedCurrency: True,
        #         limitPriceInSettlementCurrency: '0.00007129',
        #         timestamp: '1522547850000',
        #         orderId: '62a8be4d-73c6-4469-90cd-28b4726effe0',
        #         tradedCurrencyAmountOutstanding: '0.00000000',
        #         orderStatus: 'FULL_FILL',
        #         executedAverageRate: '0.00007127',
        #         trades: [
        #             {
        #                 tradeId: 'fe16b796-df57-41a2-b6d9-3489f189749e',
        #                 orderId: '62a8be4d-73c6-4469-90cd-28b4726effe0',
        #                 timestamp: '1522547850000',
        #                 tradedCurrencyFillAmount: '107.91298639',
        #                 settlementCurrencyFillAmount: '0.00768772',
        #                 settlementCurrencyFillAmountUnrounded: '0.00768772',
        #                 price: '0.00007124',
        #                 ccyPair: 'XRPBTC'
        #             },
        #             {
        #                 tradeId: 'e2962f67-c094-4243-8b88-0cdc70a1b1c7',
        #                 orderId: '62a8be4d-73c6-4469-90cd-28b4726effe0',
        #                 timestamp: '1522547851000',
        #                 tradedCurrencyFillAmount: '292.08701361',
        #                 settlementCurrencyFillAmount: '0.02082288',
        #                 settlementCurrencyFillAmountUnrounded: '0.02082288',
        #                 price: '0.00007129',
        #                 ccyPair: 'XRPBTC'
        #             }
        #         ]
        #     }
        #
        tradedCurrency = self.safe_string(order, 'tradedCurrency')
        orderStatus = self.safe_string(order, 'orderStatus')
        status = self.parse_order_status(orderStatus)
        settlementCurrency = self.safe_string(order, 'settlementCurrency')
        symbol = self.find_symbol(tradedCurrency + '/' + settlementCurrency)
        buyTradedCurrency = self.safe_string(order, 'buyTradedCurrency')
        side = buyTradedCurrency == 'buy' if 'true' else 'sell'
        timestamp = self.safe_integer(order, 'timestamp')
        lastTradeTimestamp = None
        trades = []
        filled = 0
        type = self.safe_string_lower(order, 'orderType')
        for i in range(0, len(order['trades'])):
            trade = order['trades'][i]
            tradeTimestamp = self.safe_integer(trade, 'timestamp')
            if not lastTradeTimestamp or lastTradeTimestamp < tradeTimestamp:
                lastTradeTimestamp = tradeTimestamp
            parsedTrade = self.extend(self.parse_trade(trade), {'side': side, 'type': type})
            trades.append(parsedTrade)
            filled = self.sum(filled, parsedTrade['amount'])
        price = self.safe_float(order, 'limitPriceInSettlementCurrency')
        executedAverageRate = self.safe_float(order, 'executedAverageRate')
        remaining = type == 0 if 'market' else self.safe_float(order, 'tradedCurrencyAmountOutstanding')
        amount = self.safe_float(order, 'tradedCurrencyAmount')
        if not amount:
            settlementCurrencyAmount = self.safe_float(order, 'settlementCurrencyAmount')
            amount = settlementCurrencyAmount / executedAverageRate
        cost = executedAverageRate * filled
        return {
            'id': self.safe_string(order, 'orderId'),
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastTradeTimestamp': lastTradeTimestamp,
            'type': type,
            'side': side,
            'price': price,
            'cost': cost,
            'amount': amount,
            'remaining': remaining,
            'filled': filled,
            'status': status,
            'fee': None,
            'trades': trades,
            'info': order,
        }

    def parse_order_v2(self, order, market=None):
        #
        # v2
        #
        #     {
        #         "oid": "e74305c7-c424-4fbc-a8a2-b41d8329deb0",
        #         "currency": "HKD",
        #         "item": "BTC",
        #         "type": "offer",  <-- bid/offer
        #         "amount": {
        #             "currency": "BTC",
        #             "display": "10.00000000 BTC",
        #             "display_short": "10.00 BTC",
        #             "value": "10.00000000",
        #             "value_int": "1000000000"
        #         },
        #         "effective_amount": {
        #             "currency": "BTC",
        #             "display": "10.00000000 BTC",
        #             "display_short": "10.00 BTC",
        #             "value": "10.00000000",
        #             "value_int": "1000000000"
        #         },
        #         "price": {
        #             "currency": "HKD",
        #             "display": "412.34567 HKD",
        #             "display_short": "412.35 HKD",
        #             "value": "412.34567",
        #             "value_int": "41234567"
        #         },
        #         "status": "open",
        #         "date": 1393411075000,
        #         "priority": 1393411075000000,
        #         "actions": []
        #     }
        #
        id = self.safe_string(order, 'oid')
        status = self.safe_string(order, 'status')
        timestamp = self.safe_integer(order, 'date')
        baseId = self.safe_string(order, 'item')
        quoteId = self.safe_string(order, 'currency')
        marketId = baseId + '/' + quoteId
        market = self.safe_value(self.markets_by_id, marketId)
        symbol = None
        if market is not None:
            symbol = market['symbol']
        amount_info = self.safe_value(order, 'amount', {})
        effective_info = self.safe_value(order, 'effective_amount', {})
        price_info = self.safe_value(order, 'price', {})
        remaining = self.safe_float(effective_info, 'value')
        amount = self.safe_float(amount_info, 'volume')
        price = self.safe_float(price_info, 'value')
        filled = None
        cost = None
        if amount is not None:
            if remaining is not None:
                filled = amount - remaining
                cost = price * filled
        orderType = 'limit'
        side = self.safe_string(order, 'type')
        if side == 'offer':
            side = 'sell'
        else:
            side = 'buy'
        fee = None
        trades = None  # todo parse trades
        lastTradeTimestamp = None
        return {
            'info': order,
            'id': id,
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastTradeTimestamp': lastTradeTimestamp,
            'type': orderType,
            'side': side,
            'price': price,
            'cost': cost,
            'amount': amount,
            'remaining': remaining,
            'filled': filled,
            'status': status,
            'fee': fee,
            'trades': trades,
        }

    async def create_order(self, symbol, type, side, amount, price=None, params={}):
        await self.load_markets()
        market = self.market(symbol)
        amountMultiplier = math.pow(10, market['precision']['amount'])
        request = {
            'currency_pair': market['id'],
            'amount_int': int(amount * amountMultiplier),  # 10^8
        }
        if type == 'limit':
            priceMultiplier = math.pow(10, market['precision']['price'])
            request['price_int'] = int(price * priceMultiplier)  # 10^5 or 10^8
        request['type'] = 'bid' if (side == 'buy') else 'ask'
        response = await self.privatePostCurrencyPairMoneyOrderAdd(self.extend(request, params))
        return {
            'info': response,
            'id': response['data'],
        }

    async def cancel_order(self, id, symbol=None, params={}):
        return await self.privatePostCurrencyPairMoneyOrderCancel({'oid': id})

    def get_amount_multiplier(self, code):
        multipliers = {
            'BTC': 100000000,
            'LTC': 100000000,
            'STR': 100000000,
            'XRP': 100000000,
            'DOGE': 100000000,
        }
        defaultValue = 100
        return self.safe_integer(multipliers, code, defaultValue)

    async def withdraw(self, code, amount, address, tag=None, params={}):
        self.check_address(address)
        await self.load_markets()
        currency = self.currency(code)
        multiplier = self.get_amount_multiplier(code)
        request = {
            'currency': currency,
            'amount_int': int(amount * multiplier),
            'address': address,
        }
        if tag is not None:
            request['destinationTag'] = tag
        response = await self.privatePostMoneyCurrencySendSimple(self.extend(request, params))
        return {
            'info': response,
            'id': response['data']['transactionId'],
        }

    async def fetch_deposit_address(self, code, params={}):
        await self.load_markets()
        currency = self.currency(code)
        request = {
            'currency': currency['id'],
        }
        response = await self.privatePostMoneyCurrencyAddress(self.extend(request, params))
        data = self.safe_value(response, 'data', {})
        address = self.safe_string(data, 'addr')
        self.check_address(address)
        return {
            'currency': code,
            'address': address,
            'info': response,
        }

    def nonce(self):
        return self.milliseconds()

    def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
        request = self.implode_params(path, params)
        query = self.omit(params, self.extract_params(path))
        url = self.urls['api'][api] + '/' + request
        if api == 'public' or api == 'v3public':
            if query:
                url += '?' + self.urlencode(query)
        else:
            self.check_required_credentials()
            nonce = self.nonce()
            auth = None
            contentType = None
            if api == 'v3private':
                body = self.json(self.extend({'tonce': nonce * 1000}, query))
                path = url.replace('https://anxpro.com/', '')
                auth = path + '\0' + body
                contentType = 'application/json'
            else:
                body = self.urlencode(self.extend({'nonce': nonce}, query))
                # eslint-disable-next-line quotes
                auth = request + "\0" + body
                contentType = 'application/x-www-form-urlencoded'
            secret = base64.b64decode(self.secret)
            signature = self.hmac(self.encode(auth), secret, hashlib.sha512, 'base64')
            headers = {
                'Content-Type': contentType,
                'Rest-Key': self.apiKey,
                'Rest-Sign': self.decode(signature),
            }
        return {'url': url, 'method': method, 'body': body, 'headers': headers}

    def handle_errors(self, httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody):
        if response is None or response == '':
            return
        result = self.safe_string(response, 'result')
        code = self.safe_string(response, 'resultCode')
        if ((result is not None) and(result != 'success')) or ((code is not None) and(code != 'OK')):
            message = self.safe_string(response, 'error')
            feedback = self.id + ' ' + body
            exact = self.exceptions['exact']
            if code in exact:
                raise exact[code](feedback)
            elif message in exact:
                raise exact[message](feedback)
            broad = self.safe_value(self.exceptions, 'broad', {})
            broadKey = self.findBroadlyMatchedKey(broad, message)
            if broadKey is not None:
                raise broad[broadKey](feedback)
            raise ExchangeError(feedback)  # unknown message
