# -*- 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
from ccxt.base.errors import ExchangeError
from ccxt.base.errors import AuthenticationError
from ccxt.base.errors import PermissionDenied
from ccxt.base.errors import AccountSuspended
from ccxt.base.errors import ArgumentsRequired
from ccxt.base.errors import BadRequest
from ccxt.base.errors import BadSymbol
from ccxt.base.errors import InsufficientFunds
from ccxt.base.errors import InvalidOrder
from ccxt.base.errors import OrderNotFound
from ccxt.base.errors import DDoSProtection
from ccxt.base.decimal_to_precision import TICK_SIZE
from ccxt.base.precise import Precise


class stex(Exchange):

    def describe(self):
        return self.deep_extend(super(stex, self).describe(), {
            'id': 'stex',
            'name': 'STEX',  # formerly known as stocks.exchange
            'countries': ['EE'],  # Estonia
            'rateLimit': 1000 / 3,  # https://help.stex.com/en/articles/2815043-api-3-rate-limits
            'certified': False,
            # new metainfo interface
            'has': {
                'CORS': None,
                'spot': True,
                'margin': False,
                'swap': False,
                'future': False,
                'option': False,
                'addMargin': False,
                'cancelAllOrders': True,
                'cancelOrder': True,
                'createDepositAddress': True,
                'createMarketOrder': False,
                'createOrder': True,
                'createReduceOnlyOrder': False,
                'fetchBalance': True,
                'fetchBorrowRate': False,
                'fetchBorrowRateHistories': False,
                'fetchBorrowRateHistory': False,
                'fetchBorrowRates': False,
                'fetchBorrowRatesPerSymbol': False,
                'fetchClosedOrder': True,
                'fetchCurrencies': True,
                'fetchDeposit': True,
                'fetchDepositAddress': True,
                'fetchDeposits': True,
                'fetchDepositWithdrawFee': 'emulated',
                'fetchDepositWithdrawFees': True,
                'fetchFundingHistory': False,
                'fetchFundingRate': False,
                'fetchFundingRateHistory': False,
                'fetchFundingRates': False,
                'fetchIndexOHLCV': False,
                'fetchLeverage': False,
                'fetchLeverageTiers': False,
                'fetchMarginMode': False,
                'fetchMarkets': True,
                'fetchMarkOHLCV': False,
                'fetchMyTrades': True,
                'fetchOHLCV': True,
                'fetchOpenInterestHistory': False,
                'fetchOpenOrders': True,
                'fetchOrder': True,
                'fetchOrderBook': True,
                'fetchOrderTrades': True,
                'fetchPosition': False,
                'fetchPositionMode': False,
                'fetchPositions': False,
                'fetchPositionsRisk': False,
                'fetchPremiumIndexOHLCV': False,
                'fetchTicker': True,
                'fetchTickers': True,
                'fetchTime': True,
                'fetchTrades': True,
                'fetchTradingFee': True,
                'fetchTradingFees': False,
                'fetchTransactionFees': True,
                'fetchWithdrawal': True,
                'fetchWithdrawals': True,
                'reduceMargin': False,
                'setLeverage': False,
                'setMarginMode': False,
                'setPositionMode': False,
                'transfer': True,
                'withdraw': True,
            },
            'version': 'v3',
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/69680782-03fd0b80-10bd-11ea-909e-7f603500e9cc.jpg',
                'api': {
                    'rest': 'https://api3.stex.com',
                },
                'www': 'https://www.stex.com',
                'doc': [
                    'https://apidocs.stex.com/',
                    'https://help.stex.com/en/collections/1593608-api-v3-documentation',
                ],
                'fees': 'https://app.stex.com/en/pairs-specification',
                'referral': 'https://app.stex.com?ref=36416021',
            },
            'requiredCredentials': {
                'apiKey': False,
                'secret': False,
                'token': True,
            },
            'timeframes': {
                '1m': '1',
                '5m': '5',
                '30m': '30',
                '1h': '60',
                '4h': '240',
                '12h': '720',
                '1d': '1D',  # default
            },
            'api': {
                'public': {
                    'get': {
                        'currencies': 1,  # Available Currencies
                        'currencies/{currencyId}': 1,  # Get currency info
                        'markets': 1,  # Available markets
                        'pairs-groups': 1,  # Available currency pairs groups(as displayed at stex trading page)
                        'currency_pairs/list/{code}': 1,  # Available currency pairs
                        'currency_pairs/group/{currencyPairGroupId}': 1,  # Available currency pairs for a given group
                        'currency_pairs/{currencyPairId}': 1,  # Get currency pair information
                        'ticker': 1,  # Tickers list for all currency pairs
                        'ticker/{currencyPairId}': 1,  # Ticker for currency pair
                        'trades/{currencyPairId}': 1,  # Trades for given currency pair
                        'orderbook/{currencyPairId}': 1,  # Orderbook for given currency pair
                        'chart/{currencyPairId}/{candlesType}': 1,  # A list of candles for given currency pair
                        'deposit-statuses': 1,  # Available Deposit Statuses
                        'deposit-statuses/{statusId}': 1,  # Get deposit status info
                        'withdrawal-statuses': 1,  # Available Withdrawal Statuses
                        'withdrawal-statuses/{statusId}': 1,  # Get status info
                        'ping': 1,  # Test API is working and get server time
                        'mobile-versions': 1,  # Shows the official mobile applications data
                        'twitter': 1,  # Get the last 20 posts(stex.com) on Twitter
                    },
                },
                'trading': {
                    'get': {
                        'fees/{currencyPairId}': 1,  # Returns the user's fees for a given currency pair
                        'orders': 12,  # List your currently open orders
                        'orders/{currencyPairId}': 6,  # List your currently open orders for given currency pair
                        'order/{orderId}': 12,  # Get a single order
                    },
                    'post': {
                        'orders/{currencyPairId}': 1.5,  # Create new order and put it to the orders processing queue
                        'orders/bulk/{currencyPairId}': 12,  # Create new orders in a bulk and put it to the orders processing queue
                    },
                    'delete': {
                        'orders': 30,  # Delete all active orders
                        'orders/{currencyPairId}': 12,  # Delete active orders for given currency pair
                        'order/{orderId}': 1.5,  # Cancel order
                    },
                },
                'reports': {
                    'get': {
                        'currencies': 12,  # Get a list of currencies user had any activity in
                        'currency_pairs': 12,  # Gets the list of currency pairs the user had orders in for all the time
                        'orders': 12,  # Get past orders
                        'orders/{orderId}': 12,  # Get specified order details
                        'trades/{currencyPairId}': 12,  # Get a list of user trades according to request parameters
                        'background/{listMode}': 12,  # Get reports list for category
                        'background/{id}': 12,  # Get some report info
                        'background/download/{id}': 12,  # Get file by id
                    },
                    'post': {
                        'background/create': 12,  # Create new report
                    },
                    'delete': {
                        'background/{id}': 12,  # Remove report by id
                    },
                },
                'profile': {
                    'get': {
                        'info': 3,  # Account information
                        'wallets': 3,  # Get a list of user wallets
                        'wallets/{walletId}': 3,  # Single wallet information
                        'wallets/address/{walletId}': 3,  # Get deposit address for given wallet
                        'deposits': 3,  # Get a list of deposits made by user
                        'deposits/{id}': 3,  # Get deposit by id
                        'rewards': 3,  # Get a list of rewards obtained by user(e.g. in trading competitions)
                        'rewards/{id}': 3,  # Get reward by id
                        'addressbook': 3,  # Get a list of user address book items
                        'addressbook/{itemId}': 3,  # Single address book item
                        'withdrawals': 3,  # Get a list of withdrawals made by user
                        'withdrawals/{id}': 3,  # Get withdrawal by id
                        'notifications': 3,  # Get notifications
                        'notifications/price': 3,  # Get a list of active price alerts
                        'favorite/currency_pairs': 3,  # Get favorite currency pairs
                        'token-scopes': 3,  # Get current token scopes
                    },
                    'post': {
                        'wallets/burn/{walletId}': 3,  # Burns the given wallet
                        'wallets/{walletId}/hold_amount': 3,  # Move a part of the funds on the wallet to the "hold" to keep it safe from trading
                        'wallets/{currencyId}': 3,  # Create a wallet for given currency
                        'wallets/address/{walletId}': 3,  # Create new deposit address
                        'addressbook/disable_item/{itemId}': 3,  # Disables the address book item
                        'addressbook/enable_item/{itemId}': 3,  # Enable the address book item
                        'addressbook/enable_strict_wd': 3,  # Restrict the withdrawals to only addresses that are active in addressbook
                        'addressbook/disable_strict_wd': 3,  # Remove restriction to withdraw to only addresses that are active in addressbook. E.g. allow to withdraw to any address.
                        'withdraw': 30,  # Create withdrawal request
                        'notifications/price': 3,  # Create new price alert
                        'referral/program': 3,  # Create referral program
                        'referral/insert/{code}': 3,  # Insert referral code
                        'referral/bonus_transfer/{currencyId}': 3,  # Transfer referral bonuses balance to main balance for given currency
                    },
                    'put': {
                        'favorite/currency_pairs/set': 3,  # Set favorite currency pairs
                    },
                    'delete': {
                        'addressbook/{itemId}': 3,  # Deletes address book item
                        'withdraw/{withdrawalId}': 30,  # Cancel unconfirmed withdrawal
                        'notifications/price/{priceAlertId}': 3,  # Delete the price alert by ID
                    },
                },
                'verification': {
                    'get': {
                        'countries': 1,  # Countries list, beta
                        'status': 1,  # Get status verify
                        'fractal/url': 1,  # Generate verify url from Fractal
                        'smart-id': 1,  # Check Smart-ID verify
                        'stex': 1,  # Get information about your KYC, beta
                        'cryptonomica/code': 1,  # Get Discount code for Cryptonomica
                    },
                    'post': {
                        'smart-id': 1,  # Initialization Smart-ID verify(Send request to Smart-ID App)
                        'stex': 1,  # Update information regarding of your KYC verification, beta
                        'cryptonomica': 1,  # Add verification from Cryptonomica
                    },
                },
                'settings': {
                    'get': {
                        'notifications/{event}': 1,  # User event notification settings
                        'notifications': 1,  # User events notification settings
                    },
                    'put': {
                        'notifications': 1,  # Set notification settings
                        'notifications/set': 1,
                    },
                },
            },
            'fees': {
                'trading': {
                    'tierBased': False,
                    'percentage': True,
                    'taker': self.parse_number('0.002'),
                    'maker': self.parse_number('0.002'),
                },
            },
            'commonCurrencies': {
                'BC': 'Bitcoin Confidential',
                'BITS': 'Bitcoinus',
                'BITSW': 'BITS',
                'BHD': 'Bithold',
                'BTH': 'Bithereum',
                'MPH': 'Chasyr Token',
                'SBTC': 'SBTCT',  # SiamBitcoin
            },
            'options': {
                'parseOrderToPrecision': False,
                'networks': {
                    'ERC20': 5,
                    'ETH': 5,
                    'OMNI': 10,
                    'XLM': 20,
                    'BEP2': 22,
                    'TRC20': 24,
                    'TRX': 24,
                    'SOL': 25,
                    'BEP20': 501,
                },
                'accountsByType': {
                    'spot': 'spot',
                    'hold': 'hold',
                    'funding': 'funding',
                    'referal': 'referal',
                },
                'transfer': {
                    'fillResponseFromRequest': True,
                },
            },
            'precisionMode': TICK_SIZE,
            'exceptions': {
                'exact': {
                    # {"success":false,"message":"Wrong parameters","errors":{"candleType":["Invalid Candle Type!"]}}
                    # {"success":false,"message":"Wrong parameters","errors":{"time":["timeStart or timeEnd is less then 1"]}}
                    'Wrong parameters': BadRequest,
                    'Unauthenticated.': AuthenticationError,  # {"message":"Unauthenticated."}
                    'Server Error': ExchangeError,  # {"message": "Server Error"}
                    'This feature is only enabled for users verifies by Cryptonomica': PermissionDenied,  # {"success":false,"message":"This feature is only enabled for users verifies by Cryptonomica"}
                    'Too Many Attempts.': DDoSProtection,  # {"message": "Too Many Attempts."}
                    'Selected Pair is disabled': BadSymbol,  # {"success":false,"message":"Selected Pair is disabled"}
                    'Invalid scope(s) provided.': PermissionDenied,  # {"message": "Invalid scope(s) provided."}
                    'The maximum amount of open orders with the same price cannot exceed 10': InvalidOrder,  # {"success":false,"message":"The maximum amount of open orders with the same price cannot exceed 10"}
                    'Your account not verified!': AccountSuspended,  # {"success":false,"message":"Your account not verified!","unified_message":{"message_id":"verification_required_to_continue","substitutions":null},"notice":"Please be informed that parameter `message` is deprecated and will be removed. Use unified_message instead."}
                },
                'broad': {
                    'Not enough': InsufficientFunds,  # {"success":false,"message":"Not enough  ETH"}
                },
            },
        })

    def fetch_currencies(self, params={}):
        """
        fetches all available currencies on an exchange
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: an associative dictionary of currencies
        """
        response = self.publicGetCurrencies(params)
        #
        #     {
        #         "success":true,
        #         "data":[
        #             {
        #                 "id":1,
        #                 "code":"BTC",
        #                 "name":"Bitcoin",
        #                 "active":true,
        #                 "delisted":false,
        #                 "precision":8,
        #                 "minimum_tx_confirmations":1,
        #                 "minimum_withdrawal_amount":"0.00200000",
        #                 "minimum_deposit_amount":"0.00000000",
        #                 "deposit_fee_currency_id":1,
        #                 "deposit_fee_currency_code":"BTC",
        #                 "deposit_fee_const":"0.00000000",
        #                 "deposit_fee_percent":"0.00000000",
        #                 "withdrawal_fee_currency_id":1,
        #                 "withdrawal_fee_currency_code":"BTC",
        #                 "withdrawal_fee_const":"0.00100000",
        #                 "withdrawal_fee_percent":"0.00000000",
        #                 "block_explorer_url":"https:\/\/blockchain.info\/tx\/",
        #                 "protocol_specific_settings":null
        #             },
        #         ]
        #     }
        #
        result = {}
        currencies = self.safe_value(response, 'data', [])
        for i in range(0, len(currencies)):
            currency = currencies[i]
            id = self.safe_string(currency, 'id')
            numericId = self.safe_integer(currency, 'id')
            # todo: will need to rethink the fees
            # to add support for multiple withdrawal/deposit methods and
            # differentiated fees for each particular method
            code = self.safe_currency_code(self.safe_string(currency, 'code'))
            precision = self.parse_number(self.parse_precision(self.safe_string(currency, 'precision')))
            fee = self.safe_number(currency, 'withdrawal_fee_const')  # todo: redesign
            active = self.safe_value(currency, 'active', True)
            result[code] = {
                'id': id,
                'numericId': numericId,
                'code': code,
                'info': currency,
                'type': None,
                'name': self.safe_string(currency, 'name'),
                'active': active,
                'deposit': None,
                'withdraw': None,
                'fee': fee,
                'precision': precision,
                'limits': {
                    'amount': {
                        'min': precision,
                        'max': None,
                    },
                    'deposit': {
                        'min': self.safe_number(currency, 'minimum_deposit_amount'),
                        'max': None,
                    },
                    'withdraw': {
                        'min': self.safe_number(currency, 'minimum_withdrawal_amount'),
                        'max': None,
                    },
                },
            }
        return result

    def fetch_markets(self, params={}):
        """
        retrieves data on all markets for stex
        :param dict params: extra parameters specific to the exchange api endpoint
        :returns [dict]: an array of objects representing market data
        """
        request = {
            'code': 'ALL',
        }
        response = self.publicGetCurrencyPairsListCode(self.extend(request, params))
        #
        #     {
        #         "success":true,
        #         "data":[
        #             {
        #                 "id":935,
        #                 "currency_id":662,
        #                 "currency_code":"ABET",
        #                 "currency_name":"Altbet",
        #                 "market_currency_id":1,
        #                 "market_code":"BTC",
        #                 "market_name":"Bitcoin",
        #                 "min_order_amount":"0.00000010",
        #                 "min_buy_price":"0.00000001",
        #                 "min_sell_price":"0.00000001",
        #                 "buy_fee_percent":"0.20000000",
        #                 "sell_fee_percent":"0.20000000",
        #                 "active":true,
        #                 "delisted":false,
        #                 "pair_message":"",
        #                 "currency_precision":8,
        #                 "market_precision":8,
        #                 "symbol":"ABET_BTC",
        #                 "group_name":"BTC",
        #                 "group_id":1
        #             }
        #         ]
        #     }
        #
        result = []
        markets = self.safe_value(response, 'data', [])
        for i in range(0, len(markets)):
            market = markets[i]
            id = self.safe_string(market, 'id')
            numericId = self.safe_integer(market, 'id')
            baseId = self.safe_string(market, 'currency_id')
            quoteId = self.safe_string(market, 'market_currency_id')
            baseNumericId = self.safe_integer(market, 'currency_id')
            quoteNumericId = self.safe_integer(market, 'market_currency_id')
            base = self.safe_currency_code(self.safe_string(market, 'currency_code'))
            quote = self.safe_currency_code(self.safe_string(market, 'market_code'))
            minBuyPrice = self.safe_string(market, 'min_buy_price')
            minSellPrice = self.safe_string(market, 'min_sell_price')
            minPrice = Precise.string_max(minBuyPrice, minSellPrice)
            buyFee = Precise.string_div(self.safe_string(market, 'buy_fee_percent'), '100')
            sellFee = Precise.string_div(self.safe_string(market, 'sell_fee_percent'), '100')
            fee = Precise.string_max(buyFee, sellFee)
            result.append({
                'id': id,
                'numericId': numericId,
                'symbol': base + '/' + quote,
                'base': base,
                'quote': quote,
                'settle': None,
                'baseId': baseId,
                'quoteId': quoteId,
                'settleId': None,
                'baseNumericId': baseNumericId,
                'quoteNumericId': quoteNumericId,
                'type': 'spot',
                'spot': True,
                'margin': False,
                'swap': False,
                'future': False,
                'option': False,
                'active': self.safe_value(market, 'active'),
                'contract': False,
                'linear': None,
                'inverse': None,
                'taker': fee,
                'maker': fee,
                'contractSize': None,
                'expiry': None,
                'expiryDatetime': None,
                'strike': None,
                'optionType': None,
                'precision': {
                    'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'currency_precision'))),
                    'price': self.parse_number(self.parse_precision(self.safe_string(market, 'market_precision'))),
                },
                'limits': {
                    'leverage': {
                        'min': None,
                        'max': None,
                    },
                    'amount': {
                        'min': self.safe_number(market, 'min_order_amount'),
                        'max': None,
                    },
                    'price': {
                        'min': minPrice,
                        'max': None,
                    },
                    'cost': {
                        'min': None,
                        'max': None,
                    },
                },
                'info': market,
            })
        return result

    def fetch_ticker(self, symbol, params={}):
        """
        fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
        :param str symbol: unified symbol of the market to fetch the ticker for
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: a `ticker structure <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request = {
            'currencyPairId': market['id'],
        }
        response = self.publicGetTickerCurrencyPairId(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": {
        #             "id": 2,
        #             "amount_multiplier": 1,
        #             "currency_code": "ETH",
        #             "market_code": "BTC",
        #             "currency_name": "Ethereum",
        #             "market_name": "Bitcoin",
        #             "symbol": "ETH_BTC",
        #             "group_name": "BTC",
        #             "group_id": 1,
        #             "ask": "0.02069998",
        #             "bid": "0.02028622",
        #             "last": "0.02049224",
        #             "open": "0.02059605",
        #             "low": "0.01977744",
        #             "high": "0.02097005",
        #             "volume": "480.43248971",
        #             "volumeQuote": "23491.29826130",
        #             "count": "7384",
        #             "fiatsRate": {
        #                 "USD": 7230.86,
        #                 "EUR": 6590.79,
        #                 "UAH": 173402,
        #                 "AUD": 10595.51,
        #                 "IDR": 101568085,
        #                 "CNY": 50752,
        #                 "KRW": 8452295,
        #                 "JPY": 784607,
        #                 "VND": 167315119,
        #                 "INR": 517596,
        #                 "GBP": 5607.25,
        #                 "CAD": 9602.63,
        #                 "BRL": 30472,
        #                 "RUB": 460718
        #             },
        #             "timestamp": 1574698235601
        #         }
        #     }
        #
        ticker = self.safe_value(response, 'data', {})
        return self.parse_ticker(ticker, market)

    def fetch_time(self, params={}):
        """
        fetches the current integer timestamp in milliseconds from the exchange server
        :param dict params: extra parameters specific to the stex api endpoint
        :returns int: the current integer timestamp in milliseconds from the exchange server
        """
        response = self.publicGetPing(params)
        #
        #     {
        #         "success": True,
        #         "data": {
        #             "server_datetime": {
        #                 "date": "2019-01-22 15:13:34.233796",
        #                 "timezone_type": 3,
        #                 "timezone": "UTC"
        #             },
        #             "server_timestamp": 1548170014
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        serverDatetime = self.safe_value(data, 'server_datetime', {})
        return self.parse8601(self.safe_string(serverDatetime, 'date'))

    def fetch_order_book(self, symbol, limit=None, params={}):
        """
        fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
        :param str symbol: unified symbol of the market to fetch the order book for
        :param int|None limit: the maximum amount of order book entries to return
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/en/latest/manual.html#order-book-structure>` indexed by market symbols
        """
        self.load_markets()
        market = self.market(symbol)
        request = {
            'currencyPairId': market['id'],
        }
        if limit is not None:
            request['limit_bids'] = limit  # returns all if set to 0, default 100
            request['limit_asks'] = limit  # returns all if set to 0, default 100
        response = self.publicGetOrderbookCurrencyPairId(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": {
        #             "ask": [
        #                 {"currency_pair_id": 2, "amount": "2.17865373", "price": "0.02062917", "amount2": "0.04494382", "count": 1, "cumulative_amount": 2.17865373},
        #                 {"currency_pair_id": 2, "amount": "2.27521743", "price": "0.02062918", "amount2": "0.04693587", "count": 1, "cumulative_amount": 4.45387116},
        #                 {"currency_pair_id": 2, "amount": "1.26980049", "price": "0.02063170", "amount2": "0.02619814", "count": 1, "cumulative_amount": 5.72367165},
        #             ],
        #             "bid": [
        #                 {"currency_pair_id": 2, "amount": "0.00978005", "price": "0.02057000", "amount2": "0.00020118", "count": 1, "cumulative_amount": 0.00978005},
        #                 {"currency_pair_id": 2, "amount": "0.00500000", "price": "0.02056000", "amount2": "0.00010280", "count": 1, "cumulative_amount": 0.01478005},
        #                 {"currency_pair_id": 2, "amount": "0.77679882", "price": "0.02054001", "amount2": "0.01595546", "count": 1, "cumulative_amount": 0.79157887},
        #             ],
        #             "ask_total_amount": 2555.749174609999,
        #             "bid_total_amount": 29.180037330000005
        #         }
        #     }
        #
        orderbook = self.safe_value(response, 'data', {})
        return self.parse_order_book(orderbook, symbol, None, 'bid', 'ask', 'price', 'amount')

    def parse_ticker(self, ticker, market=None):
        #
        #     {
        #         "id": 2,
        #         "amount_multiplier": 1,
        #         "currency_code": "ETH",
        #         "market_code": "BTC",
        #         "currency_name": "Ethereum",
        #         "market_name": "Bitcoin",
        #         "symbol": "ETH_BTC",
        #         "group_name": "BTC",
        #         "group_id": 1,
        #         "ask": "0.02069998",
        #         "bid": "0.02028622",
        #         "last": "0.02049224",
        #         "open": "0.02059605",
        #         "low": "0.01977744",
        #         "high": "0.02097005",
        #         "volume": "480.43248971",
        #         "volumeQuote": "23491.29826130",
        #         "count": "7384",
        #         "fiatsRate": {
        #             "USD": 7230.86,
        #             "EUR": 6590.79,
        #             "UAH": 173402,
        #             "AUD": 10595.51,
        #             "IDR": 101568085,
        #             "CNY": 50752,
        #             "KRW": 8452295,
        #             "JPY": 784607,
        #             "VND": 167315119,
        #             "INR": 517596,
        #             "GBP": 5607.25,
        #             "CAD": 9602.63,
        #             "BRL": 30472,
        #             "RUB": 460718
        #         },
        #         "timestamp": 1574698235601
        #     }
        #
        timestamp = self.safe_integer(ticker, 'timestamp')
        marketId = self.safe_string_2(ticker, 'id', 'symbol')
        symbol = self.safe_symbol(marketId, market, '_')
        last = self.safe_string(ticker, 'last')
        open = self.safe_string(ticker, 'open')
        return self.safe_ticker({
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'high': self.safe_string(ticker, 'high'),
            'low': self.safe_string(ticker, 'low'),
            'bid': self.safe_string(ticker, 'bid'),
            'bidVolume': None,
            'ask': self.safe_string(ticker, 'ask'),
            'askVolume': None,
            'vwap': None,
            'open': open,
            'close': last,
            'last': last,
            'previousClose': None,  # previous day close
            'change': None,
            'percentage': None,
            'average': None,
            'baseVolume': self.safe_string(ticker, 'volumeQuote'),
            'quoteVolume': self.safe_string(ticker, 'volume'),
            'info': ticker,
        }, market)

    def fetch_tickers(self, symbols=None, params={}):
        """
        fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market
        :param [str]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
        """
        self.load_markets()
        response = self.publicGetTicker(params)
        #
        #     {
        #         "success":true,
        #         "data":[
        #             {
        #                 "id":262,
        #                 "amount_multiplier":1,
        #                 "currency_code":"ARDR",
        #                 "market_code":"BTC",
        #                 "currency_name":"ARDOR",
        #                 "market_name":"Bitcoin",
        #                 "symbol":"ARDR_BTC",
        #                 "group_name":"BTC",
        #                 "group_id":1,
        #                 "ask":"0.00000630",
        #                 "bid":"0.00000613",
        #                 "last":"0.00000617",
        #                 "open":"0.00000620",
        #                 "low":"0.00000614",
        #                 "high":"0.00000630",
        #                 "volume":"30.37795305",
        #                 "volumeQuote":"4911487.01996544",
        #                 "count":"710",
        #                 "fiatsRate":{
        #                     "USD":7230.86,
        #                     "EUR":6590.79,
        #                     "UAH":173402,
        #                     "AUD":10744.52,
        #                     "IDR":101568085,
        #                     "CNY":50752,
        #                     "KRW":8452295,
        #                     "JPY":784607,
        #                     "VND":167315119,
        #                     "INR":517596,
        #                     "GBP":5607.25,
        #                     "CAD":9602.63,
        #                     "BRL":30472,
        #                     "RUB":467358
        #                 },
        #                 "timestamp":1574698617304,
        #                 "group_position":1
        #             },
        #         ]
        #     }
        #
        tickers = self.safe_value(response, 'data', [])
        return self.parse_tickers(tickers, symbols)

    def parse_ohlcv(self, ohlcv, market=None):
        #
        #     {
        #         "time": 1566086400000,
        #         "close": 0.01895,
        #         "open": 0.01812427,
        #         "high": 0.0191588,
        #         "low": 0.01807001,
        #         "volume": 2588.597813750006
        #     }
        #
        return [
            self.safe_integer(ohlcv, 'time'),
            self.safe_number(ohlcv, 'open'),
            self.safe_number(ohlcv, 'high'),
            self.safe_number(ohlcv, 'low'),
            self.safe_number(ohlcv, 'close'),
            self.safe_number(ohlcv, 'volume'),
        ]

    def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
        """
        fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
        :param str symbol: unified symbol of the market to fetch OHLCV data for
        :param str timeframe: the length of time each candle represents
        :param int|None since: timestamp in ms of the earliest candle to fetch
        :param int|None limit: the maximum amount of candles to fetch
        :param dict params: extra parameters specific to the stex api endpoint
        :returns [[int]]: A list of candles ordered as timestamp, open, high, low, close, volume
        """
        self.load_markets()
        market = self.market(symbol)
        request = {
            'currencyPairId': market['id'],
            'candlesType': self.safe_string(self.timeframes, timeframe, timeframe),  # default 1d
            # 'timeStart': 1574709092,  # unix timestamp in seconds, required
            # 'timeEnd': 1574709092,  # unix timestamp in seconds, required
            # 'limit': 100,  # default 100, optional
            # 'offset' 100,  # optional, pagination within timerange
        }
        if limit is None:
            limit = 100
        else:
            request['limit'] = limit
        duration = self.parse_timeframe(timeframe)
        timerange = limit * duration
        if since is None:
            request['timeEnd'] = self.seconds()
            request['timeStart'] = request['timeEnd'] - timerange
        else:
            request['timeStart'] = int(since / 1000)
            request['timeEnd'] = self.sum(request['timeStart'], timerange)
        response = self.publicGetChartCurrencyPairIdCandlesType(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": [
        #             {
        #                 "time": 1566086400000,
        #                 "close": 0.01895,
        #                 "open": 0.01812427,
        #                 "high": 0.0191588,
        #                 "low": 0.01807001,
        #                 "volume": 2588.597813750006
        #             },
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        return self.parse_ohlcvs(data, market, timeframe, since, limit)

    def parse_trade(self, trade, market=None):
        #
        # public fetchTrades
        #
        #     {
        #         "id": 35989317,
        #         "price": "0.02033813",
        #         "amount": "3.60000000",
        #         "type": "BUY",
        #         "timestamp": "1574713503"
        #     }
        #
        # private fetchMyTrades, fetchClosedOrder, fetchOrderTrades
        #
        #     {
        #         "id": 658745,
        #         "buy_order_id": 6587453,
        #         "sell_order_id": 6587459,
        #         "price": 0.012285,
        #         "amount": 6.35,
        #         "trade_type": "SELL",
        #         "timestamp": "1538737692"
        #     }
        #
        id = self.safe_string(trade, 'id')
        timestamp = self.safe_timestamp(trade, 'timestamp')
        priceString = self.safe_string(trade, 'price')
        amountString = self.safe_string(trade, 'amount')
        symbol = None
        if (symbol is None) and (market is not None):
            symbol = market['symbol']
        side = self.safe_string_lower_2(trade, 'type', 'trade_type')
        return self.safe_trade({
            'info': trade,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'symbol': symbol,
            'id': id,
            'order': None,
            'type': None,
            'takerOrMaker': None,
            'side': side,
            'price': priceString,
            'amount': amountString,
            'cost': None,
            'fee': None,
        }, market)

    def fetch_trades(self, symbol, since=None, limit=None, params={}):
        """
        get the list of most recent trades for a particular symbol
        :param str symbol: unified symbol of the market to fetch trades for
        :param int|None since: timestamp in ms of the earliest trade to fetch
        :param int|None limit: the maximum amount of trades to fetch
        :param dict params: extra parameters specific to the stex api endpoint
        :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
        """
        self.load_markets()
        market = self.market(symbol)
        request = {
            'currencyPairId': market['id'],
            # 'sort': 'ASC',  # ASC or DESC, default DESC
            # 'from': 1574709092,  # unix timestamp, optional
            # 'till': 1574709092,  # unix timestamp, optional
            # 'limit': 100,  # default 100, optional
            # 'offset': 100,  # optional
        }
        if limit is not None:
            request['limit'] = limit  # currently limited to 100 or fewer
        if since is not None:
            request['sort'] = 'ASC'  # needed to make the from param work
            request['from'] = int(since / 1000)
        response = self.publicGetTradesCurrencyPairId(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": [
        #             {
        #                 "id": 35989317,
        #                 "price": "0.02033813",
        #                 "amount": "3.60000000",
        #                 "type": "BUY",
        #                 "timestamp": "1574713503"
        #             },
        #         ]
        #     }
        #
        trades = self.safe_value(response, 'data', [])
        return self.parse_trades(trades, market, since, limit)

    def fetch_trading_fee(self, symbol, params={}):
        """
        fetch the trading fees for a market
        :param str symbol: unified market symbol
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: a `fee structure <https://docs.ccxt.com/en/latest/manual.html#fee-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request = {
            'currencyPairId': market['id'],
        }
        response = self.tradingGetFeesCurrencyPairId(self.extend(request, params))
        #
        #     {
        #         success: True,
        #         data: {buy_fee: '0.00200000', sell_fee: '0.00200000'},
        #         unified_message: {message_id: 'operation_successful', substitutions: []}
        #      }
        #
        data = self.safe_value(response, 'data')
        return {
            'info': response,
            'symbol': market['symbol'],
            'maker': self.safe_number(data, 'sell_fee'),
            'taker': self.safe_number(data, 'buy_fee'),
            'percentage': True,
            'tierBased': True,
        }

    def parse_balance(self, response):
        result = {
            'info': response,
            'timestamp': None,
            'datetime': None,
        }
        balances = self.safe_value(response, 'data', [])
        for i in range(0, len(balances)):
            balance = balances[i]
            code = self.safe_currency_code(self.safe_string(balance, 'currency_id'))
            account = self.account()
            account['free'] = self.safe_string(balance, 'balance')
            account['used'] = self.safe_string(balance, 'frozen_balance')
            result[code] = account
        return self.safe_balance(result)

    def fetch_balance(self, params={}):
        """
        query for balance and get the amount of funds available for trading or funds locked in orders
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: a `balance structure <https://docs.ccxt.com/en/latest/manual.html?#balance-structure>`
        """
        self.load_markets()
        # self.load_accounts()
        response = self.profileGetWallets(params)
        #
        #     {
        #         "success": True,
        #         "data": [
        #             {
        #                 "id": null,
        #                 "currency_id": 665,
        #                 "delisted": False,
        #                 "disabled": False,
        #                 "disable_deposits": False,
        #                 "currency_code": "ORM",
        #                 "currency_name": "Orium",
        #                 "currency_type_id": 5,
        #                 "balance": "0",
        #                 "frozen_balance": "0",
        #                 "bonus_balance": "0",
        #                 "total_balance": "0",
        #                 "protocol_specific_settings": null,
        #                 "rates": {"BTC": "0.00000000020", "USD": "0.00000147"},
        #             },
        #             {
        #                 "id": null,
        #                 "currency_id": 272,
        #                 "delisted": False,
        #                 "disabled": False,
        #                 "disable_deposits": False,
        #                 "currency_code": "USDT",
        #                 "currency_name": "TetherUSD",
        #                 "currency_type_id": 23,
        #                 "balance": "0",
        #                 "frozen_balance": "0",
        #                 "bonus_balance": "0",
        #                 "total_balance": "0",
        #                 "protocol_specific_settings": [
        #                     {"protocol_name": "OMNI", "protocol_id": 10, "active": True, "withdrawal_fee_currency_id": 272, "withdrawal_fee_const": 10, "withdrawal_fee_percent": 0, "block_explorer_url": "https://omniexplorer.info/search/"},
        #                     {"protocol_name": "ERC20", "protocol_id": 5, "active": True, "withdrawal_fee_const": 1.2, "withdrawal_fee_percent": 0, "block_explorer_url": "https://etherscan.io/tx/"},
        #                     {"protocol_name": "TRON", "protocol_id": 24, "active": True, "withdrawal_fee_currency_id": 272, "withdrawal_fee_const": 0.2, "withdrawal_fee_percent": 0, "block_explorer_url": "https://tronscan.org/#/transaction/"}
        #                 ],
        #                 "rates": {"BTC": "0.00013893", "USD": "1"},
        #             },
        #         ]
        #     }
        #
        return self.parse_balance(response)

    def parse_order_status(self, status):
        statuses = {
            'PROCESSING': 'open',
            'PENDING': 'open',
            'PARTIAL': 'open',
            'FINISHED': 'closed',
            'CANCELLED': 'canceled',
        }
        return self.safe_string(statuses, status, status)

    def parse_order(self, order, market=None):
        #
        # createOrder, fetchOpenOrders, fetchClosedOrders, cancelOrder, fetchOrder, fetchClosedOrder
        #
        #     {
        #         "id": 828680665,
        #         "currency_pair_id": 1,
        #         "currency_pair_name": "NXT_BTC",
        #         "price": "0.011384",
        #         "trigger_price": 0.011385,
        #         "initial_amount": "13.942",
        #         "processed_amount": "3.724",  # missing in fetchClosedOrder
        #         "type": "SELL",
        #         "original_type": "STOP_LIMIT_SELL",
        #         "created": "2019-01-17 10:14:48",
        #         "timestamp": "1547720088",
        #         "status": "PARTIAL"
        #         # fetchClosedOrder only
        #         "trades": [
        #             {
        #                 "id": 658745,
        #                 "buy_order_id": 658745,
        #                 "sell_order_id": 828680665,
        #                 "price": 0.012285,
        #                 "amount": 6.35,
        #                 "trade_type": "SELL",
        #                 "timestamp": "1538737692"
        #             }
        #         ],
        #         # fetchClosedOrder only
        #         "fees": [
        #             {
        #                 "id": 1234567,
        #                 "currency_id": 1,
        #                 "amount": 0.00025,
        #                 "timestamp": "1548149238"
        #             }
        #         ]
        #     }
        #
        id = self.safe_string(order, 'id')
        status = self.parse_order_status(self.safe_string(order, 'status'))
        marketId = self.safe_string_2(order, 'currency_pair_id', 'currency_pair_name')
        symbol = self.safe_symbol(marketId, market, '_')
        timestamp = self.safe_timestamp(order, 'timestamp')
        price = self.safe_string(order, 'price')
        amount = self.safe_string(order, 'initial_amount')
        filled = self.safe_string(order, 'processed_amount')
        remaining = None
        cost = None
        if filled is not None:
            if amount is not None:
                remaining = Precise.string_sub(amount, filled)
                if self.options['parseOrderToPrecision']:
                    remaining = self.amount_to_precision(symbol, remaining)
                remaining = Precise.string_max(remaining, '0.0')
            if price is not None:
                if cost is None:
                    cost = Precise.string_mul(price, filled)
        type = self.safe_string(order, 'original_type')
        if (type == 'BUY') or (type == 'SELL'):
            type = None
        side = self.safe_string_lower(order, 'type')
        trades = self.safe_value(order, 'trades')
        stopPrice = self.safe_number(order, 'trigger_price')
        result = {
            'info': order,
            'id': id,
            'clientOrderId': None,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastTradeTimestamp': None,
            'symbol': symbol,
            'type': type,
            'timeInForce': None,
            'postOnly': None,
            'side': side,
            'price': price,
            'stopPrice': stopPrice,
            'triggerPrice': stopPrice,
            'amount': amount,
            'cost': cost,
            'average': None,
            'filled': filled,
            'remaining': remaining,
            'status': status,
            'trades': trades,
        }
        fees = self.safe_value(order, 'fees')
        if fees is None:
            result['fee'] = None
        else:
            numFees = len(fees)
            if numFees > 0:
                result['fees'] = []
                for i in range(0, len(fees)):
                    feeCost = self.safe_string(fees[i], 'amount')
                    if feeCost is not None:
                        feeCurrencyId = self.safe_string(fees[i], 'currency_id')
                        feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
                        result['fees'].append({
                            'cost': feeCost,
                            'currency': feeCurrencyCode,
                        })
            else:
                result['fee'] = None
        return self.safe_order(result, market)

    def create_order(self, symbol, type, side, amount, price=None, params={}):
        """
        create a trade order
        :param str symbol: unified symbol of the market to create an order in
        :param str type: 'market' or 'limit'
        :param str side: 'buy' or 'sell'
        :param float amount: how much of currency you want to trade in units of base currency
        :param float|None price: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: an `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        if type == 'market':
            raise ExchangeError(self.id + ' createOrder() allows limit orders only')
        self.load_markets()
        market = self.market(symbol)
        if type == 'limit':
            type = side
        request = {
            'currencyPairId': market['id'],
            'type': type.upper(),  # 'BUY', 'SELL', 'STOP_LIMIT_BUY', 'STOP_LIMIT_SELL'
            'amount': float(self.amount_to_precision(symbol, amount)),  # required
            'price': float(self.price_to_precision(symbol, price)),  # required
            # 'trigger_price': 123.45  # required for STOP_LIMIT_BUY or STOP_LIMIT_SELL
        }
        response = self.tradingPostOrdersCurrencyPairId(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": {
        #             "id": 828680665,
        #             "currency_pair_id": 1,
        #             "currency_pair_name": "NXT_BTC",
        #             "price": "0.011384",
        #             "trigger_price": 0.011385,
        #             "initial_amount": "13.942",
        #             "processed_amount": "3.724",
        #             "type": "SELL",
        #             "original_type": "STOP_LIMIT_SELL",
        #             "created": "2019-01-17 10:14:48",
        #             "timestamp": "1547720088",
        #             "status": "PARTIAL"
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        return self.parse_order(data, market)

    def fetch_order(self, id, symbol=None, params={}):
        """
        fetches information on an order made by the user
        :param str|None symbol: unified symbol of the market the order was made in
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        self.load_markets()
        request = {
            'orderId': id,
        }
        response = self.tradingGetOrderOrderId(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": {
        #             "id": 828680665,
        #             "currency_pair_id": 1,
        #             "currency_pair_name": "NXT_BTC",
        #             "price": "0.011384",
        #             "trigger_price": 0.011385,
        #             "initial_amount": "13.942",
        #             "processed_amount": "3.724",
        #             "type": "SELL",
        #             "original_type": "STOP_LIMIT_SELL",
        #             "created": "2019-01-17 10:14:48",
        #             "timestamp": "1547720088",
        #             "status": "PARTIAL"
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        market = None
        if symbol is not None:
            market = self.market(symbol)
        return self.parse_order(data, market)

    def fetch_closed_order(self, id, symbol=None, params={}):
        """
        fetch an open order by it's id
        :param str id: order id
        :param str|None symbol: unified market symbol, default is None
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: an `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        self.load_markets()
        request = {
            'orderId': id,
        }
        response = self.reportsGetOrdersOrderId(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": {
        #             "id": 5478965,
        #             "currency_pair_id": 1,
        #             "currency_pair_name": "NXT_BTC",
        #             "price": "0.00013800",
        #             "initial_amount": "1.00000000",
        #             "type": "BUY",
        #             "created": "2019-01-22 09:27:17",
        #             "timestamp": 1548149237,
        #             "status": "FINISHED",
        #             "trades": [
        #                 {
        #                     "id": 658745,
        #                     "buy_order_id": 6587453,
        #                     "sell_order_id": 6587459,
        #                     "price": 0.012285,
        #                     "amount": 6.35,
        #                     "trade_type": "SELL",
        #                     "timestamp": "1538737692"
        #                 }
        #             ],
        #             "fees": [
        #                 {
        #                     "id": 1234567,
        #                     "currency_id": 1,
        #                     "amount": 0.00025,
        #                     "timestamp": "1548149238"
        #                 }
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        market = None
        if symbol is not None:
            market = self.market(symbol)
        return self.parse_order(data, market)

    def fetch_order_trades(self, id, symbol=None, since=None, limit=None, params={}):
        """
        fetch all the trades made from a single order
        :param str id: order id
        :param str|None symbol: unified market symbol
        :param int|None since: the earliest time in ms to fetch trades for
        :param int|None limit: the maximum number of trades to retrieve
        :param dict params: extra parameters specific to the stex api endpoint
        :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html#trade-structure>`
        """
        order = self.fetch_closed_order(id, symbol, params)
        return order['trades']

    def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
        """
        fetch all unfilled currently open orders
        :param str|None symbol: unified market symbol
        :param int|None since: the earliest time in ms to fetch open orders for
        :param int|None limit: the maximum number of  open orders structures to retrieve
        :param dict params: extra parameters specific to the stex api endpoint
        :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        self.load_markets()
        market = None
        method = 'tradingGetOrders'
        request = {
            # 'limit': 100,  # default 100
            # 'offset': 100,
        }
        if symbol is not None:
            method = 'tradingGetOrdersCurrencyPairId'
            market = self.market(symbol)
            request['currencyPairId'] = market['id']
        if limit is not None:
            request['limit'] = limit
        response = getattr(self, method)(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": [
        #             {
        #                 "id": 828680665,
        #                 "currency_pair_id": 1,
        #                 "currency_pair_name": "NXT_BTC",
        #                 "price": "0.011384",
        #                 "trigger_price": 0.011385,
        #                 "initial_amount": "13.942",
        #                 "processed_amount": "3.724",
        #                 "type": "SELL",
        #                 "original_type": "STOP_LIMIT_SELL",
        #                 "created": "2019-01-17 10:14:48",
        #                 "timestamp": "1547720088",
        #                 "status": "PARTIAL"
        #             }
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        return self.parse_orders(data, market, since, limit)

    def cancel_order(self, id, symbol=None, params={}):
        """
        cancels an open order
        :param str id: order id
        :param str|None symbol: not used by stex cancelOrder()
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        self.load_markets()
        request = {
            'orderId': id,
        }
        response = self.tradingDeleteOrderOrderId(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": {
        #             "put_into_processing_queue": [
        #                 {
        #                     "id": 828680665,
        #                     "currency_pair_id": 1,
        #                     "currency_pair_name": "NXT_BTC",
        #                     "price": "0.011384",
        #                     "trigger_price": 0.011385,
        #                     "initial_amount": "13.942",
        #                     "processed_amount": "3.724",
        #                     "type": "SELL",
        #                     "original_type": "STOP_LIMIT_SELL",
        #                     "created": "2019-01-17 10:14:48",
        #                     "timestamp": "1547720088",
        #                     "status": "PARTIAL"
        #                 }
        #             ],
        #             "not_put_into_processing_queue": [
        #                 {
        #                     "id": 828680665,
        #                     "currency_pair_id": 1,
        #                     "currency_pair_name": "NXT_BTC",
        #                     "price": "0.011384",
        #                     "trigger_price": 0.011385,
        #                     "initial_amount": "13.942",
        #                     "processed_amount": "3.724",
        #                     "type": "SELL",
        #                     "original_type": "STOP_LIMIT_SELL",
        #                     "created": "2019-01-17 10:14:48",
        #                     "timestamp": "1547720088",
        #                     "status": "PARTIAL"
        #                 }
        #             ],
        #             "message": "string"
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        acceptedOrders = self.safe_value(data, 'put_into_processing_queue', [])
        rejectedOrders = self.safe_value(data, 'not_put_into_processing_queue', [])
        numAcceptedOrders = len(acceptedOrders)
        numRejectedOrders = len(rejectedOrders)
        if numAcceptedOrders < 1:
            if numRejectedOrders < 1:
                raise OrderNotFound(self.id + ' cancelOrder() received an empty response: ' + self.json(response))
            else:
                return self.parse_order(rejectedOrders[0])
        else:
            if numRejectedOrders < 1:
                return self.parse_order(acceptedOrders[0])
            else:
                raise OrderNotFound(self.id + ' cancelOrder() received an empty response: ' + self.json(response))

    def cancel_all_orders(self, symbol=None, params={}):
        """
        cancel all open orders
        :param str|None symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
        :param dict params: extra parameters specific to the stex api endpoint
        :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        self.load_markets()
        request = {}
        method = 'tradingDeleteOrders'
        if symbol is not None:
            market = self.market(symbol)
            request['currencyPairId'] = market['id']
            method = 'tradingDeleteOrdersCurrencyPairId'
        response = getattr(self, method)(self.extend(request, params))
        #
        #     {
        #         "success":true,
        #         "data":{
        #             "put_into_processing_queue":[],
        #             "not_put_into_processing_queue":[],
        #             "message":"Orders operations are handled in processing queue, therefore cancelling is not immediate."
        #         }
        #     }
        #
        return response

    def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
        """
        fetch all trades made by the user
        :param str symbol: unified market symbol
        :param int|None since: the earliest time in ms to fetch trades for
        :param int|None limit: the maximum number of trades structures to retrieve
        :param dict params: extra parameters specific to the stex api endpoint
        :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html#trade-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        request = {
            'currencyPairId': market['id'],
            # 'timeStart': '2019-11-26T19:54:55.901Z',  # datetime in iso format
            # 'timeEnd': '2019-11-26T19:54:55.901Z',  # datetime in iso format
            # 'limit': 100,  # default 100
            # 'offset': 100,
        }
        if since is not None:
            request['timeStart'] = self.iso8601(since)
        if limit is not None:
            request['limit'] = limit
        response = self.reportsGetTradesCurrencyPairId(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": [
        #             {
        #                 "id": 658745,
        #                 "buy_order_id": 6587453,
        #                 "sell_order_id": 6587459,
        #                 "price": 0.012285,
        #                 "amount": 6.35,
        #                 "trade_type": "SELL",
        #                 "timestamp": "1538737692"
        #             }
        #         ]
        #     }
        #
        trades = self.safe_value(response, 'data', [])
        return self.parse_trades(trades, market, since, limit)

    def create_deposit_address(self, code, params={}):
        """
        create a currency deposit address
        :param str code: unified currency code of the currency for the deposit address
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: an `address structure <https://docs.ccxt.com/en/latest/manual.html#address-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        request = {
            'currencyId': currency['id'],
            # Default value is the value that represents legacy protocol.
            # In case of USDT it is 10 as Tether OMNI was the default previously.
            # The list of protocols can be obtained from the /public/currencies/{currencyId}
            # 'protocol_id': 10,
        }
        response = self.profilePostWalletsCurrencyId(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": {
        #             "id": 45875,
        #             "currency_id": 1,
        #             "delisted": False,
        #             "disabled": False,
        #             "disable_deposits": False,
        #             "code": "BTC",
        #             "balance": "0.198752",
        #             "frozen_balance": "1.5784",
        #             "bonus_balance": "0.000",
        #             "deposit_address": {
        #                 "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
        #                 "address_name": "Address",
        #                 "additional_address_parameter": "qwertyuiopasdfghjkl",
        #                 "additional_address_parameter_name": "Destination Tag",
        #                 "notification": "",
        #                 "protocol_id": 10,
        #                 "protocol_name": "Tether OMNI",
        #                 "supports_new_address_creation": False
        #                 },
        #             "multi_deposit_addresses": [
        #                 {
        #                     "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
        #                     "address_name": "Address",
        #                     "additional_address_parameter": "qwertyuiopasdfghjkl",
        #                     "additional_address_parameter_name": "Destination Tag",
        #                     "notification": "",
        #                     "protocol_id": 10,
        #                     "protocol_name": "Tether OMNI",
        #                     "supports_new_address_creation": False
        #                 }
        #             ],
        #             "withdrawal_additional_field_name": "Payment ID(optional)",
        #             "rates": {"BTC": 0.000001},
        #             "protocol_specific_settings": [
        #                 {
        #                     "protocol_name": "Tether OMNI",
        #                     "protocol_id": 10,
        #                     "active": True,
        #                     "withdrawal_fee_currency_id": 1,
        #                     "withdrawal_fee_const": 0.002,
        #                     "withdrawal_fee_percent": 0,
        #                     "block_explorer_url": "https://omniexplorer.info/search/"
        #                 }
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        depositAddress = self.safe_value(data, 'deposit_address', {})
        address = self.safe_string(depositAddress, 'address')
        tag = self.safe_string(depositAddress, 'additional_address_parameter')
        self.check_address(address)
        return {
            'currency': code,
            'address': address,
            'tag': tag,
            'info': response,
        }

    def fetch_deposit_address(self, code, params={}):
        """
        fetch the deposit address for a currency associated with self account
        :param str code: unified currency code
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: an `address structure <https://docs.ccxt.com/en/latest/manual.html#address-structure>`
        """
        self.load_markets()
        balance = self.fetch_balance()
        wallets = self.safe_value(balance['info'], 'data', [])
        walletsByCurrencyId = self.index_by(wallets, 'currency_id')
        currency = self.currency(code)
        wallet = self.safe_value(walletsByCurrencyId, currency['id'])
        if wallet is None:
            raise ExchangeError(self.id + ' fetchDepositAddress() could not find the wallet id for currency code ' + code + ', try to call createDepositAddress() first')
        walletId = self.safe_integer(wallet, 'id')
        if walletId is None:
            raise ExchangeError(self.id + ' fetchDepositAddress() could not find the wallet id for currency code ' + code + ', try to call createDepositAddress() first')
        request = {
            'walletId': walletId,
        }
        response = self.profileGetWalletsWalletId(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": {
        #             "id": 45875,
        #             "currency_id": 1,
        #             "delisted": False,
        #             "disabled": False,
        #             "disable_deposits": False,
        #             "code": "BTC",
        #             "balance": "0.198752",
        #             "frozen_balance": "1.5784",
        #             "bonus_balance": "0.000",
        #             "deposit_address": {
        #                 "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
        #                 "address_name": "Address",
        #                 "additional_address_parameter": "qwertyuiopasdfghjkl",
        #                 "additional_address_parameter_name": "Destination Tag",
        #                 "notification": "",
        #                 "protocol_id": 10,
        #                 "protocol_name": "Tether OMNI",
        #                 "supports_new_address_creation": False
        #             },
        #             "multi_deposit_addresses": [
        #                 {
        #                     "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
        #                     "address_name": "Address",
        #                     "additional_address_parameter": "qwertyuiopasdfghjkl",
        #                     "additional_address_parameter_name": "Destination Tag",
        #                     "notification": "",
        #                     "protocol_id": 10,
        #                     "protocol_name": "Tether OMNI",
        #                     "supports_new_address_creation": False
        #                 }
        #             ],
        #             "withdrawal_additional_field_name": "Payment ID(optional)",
        #             "rates": {"BTC": 0.000001},
        #             "protocol_specific_settings": [
        #                 {
        #                     "protocol_name": "Tether OMNI",
        #                     "protocol_id": 10,
        #                     "active": True,
        #                     "withdrawal_fee_currency_id": 1,
        #                     "withdrawal_fee_const": 0.002,
        #                     "withdrawal_fee_percent": 0,
        #                     "block_explorer_url": "https://omniexplorer.info/search/"
        #                 }
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', [])
        depositAddress = self.safe_value(data, 'deposit_address', {})
        address = self.safe_string(depositAddress, 'address')
        tag = self.safe_string(depositAddress, 'additional_address_parameter')
        self.check_address(address)
        return {
            'currency': code,
            'address': address,
            'tag': tag,
            'network': None,
            'info': response,
        }

    def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
        url = self.urls['api']['rest'] + '/' + api + '/' + self.implode_params(path, params)
        query = self.omit(params, self.extract_params(path))
        if api == 'public':
            if query:
                url += '?' + self.urlencode(query)
        else:
            self.check_required_credentials()
            headers = {
                'Authorization': 'Bearer ' + self.token,
            }
            if method == 'GET' or method == 'DELETE':
                if query:
                    url += '?' + self.urlencode(query)
            else:
                body = self.json(query)
                if query:
                    headers['Content-Type'] = 'application/json'
        return {'url': url, 'method': method, 'body': body, 'headers': headers}

    def parse_transaction_status(self, status):
        statuses = {
            'processing': 'pending',
            'checking by system': 'pending',
            'hodl': 'pending',
            'amount too low': 'failed',
            'not confirmed': 'pending',
            'cancelled by user': 'canceled',
            'approved': 'pending',
            'finished': 'ok',
            'withdrawal error': 'failed',
            'deposit error': 'failed',
            'cancelled by admin': 'canceled',
            'awaiting': 'pending',
        }
        return self.safe_string(statuses, status, status)

    def parse_transaction(self, transaction, currency=None):
        #
        # fetchDeposit & fetchDeposits
        #
        #     {
        #         "id": 123654789,
        #         "currency_id": 1,
        #         "currency_code": "BTC",
        #         "deposit_fee_currency_id": 1,
        #         "deposit_fee_currency_code": "BTC",
        #         "amount": 0.25,
        #         "fee": 0.00025,
        #         "txid": "qwertyuhgfdsasdfgh",
        #         "protocol_id": 0,
        #         "deposit_status_id": 1,
        #         "status": "PROCESSING",
        #         "status_color": "#BC3D51",
        #         "created_at": "2018-11-28 12:32:08",
        #         "timestamp": "1543409389",
        #         "confirmations": "1 of 2"
        #     }
        #
        # fetchWithdrawal and fetchWithdrawals
        #
        #     {
        #         "id": 65899,
        #         "amount": "0.00600000",
        #         "currency_id": 1,
        #         "currency_code": "BTC",
        #         "fee": "0.00400000",
        #         "fee_currency_id": 1,
        #         "fee_currency_code": "BTC",
        #         "withdrawal_status_id": 1,
        #         "status": "Not Confirmed",
        #         "status_color": "#BC3D51",
        #         "created_at": "2019-01-21 09:36:05",
        #         "created_ts": "1548063365",
        #         "updated_at": "2019-01-21 09:36:05",
        #         "updated_ts": "1548063365",
        #         "txid": null,
        #         "protocol_id": 0,
        #         "withdrawal_address": {
        #             "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
        #             "address_name": "Address",
        #             "additional_address_parameter": "qwertyuiopasdfghjkl",
        #             "additional_address_parameter_name": "Destination Tag",
        #             "notification": "",
        #             "protocol_id": 10,
        #             "protocol_name": "Tether OMNI",
        #             "supports_new_address_creation": False
        #         }
        #     }
        #
        id = self.safe_string(transaction, 'id')
        withdrawalAddress = self.safe_value(transaction, 'withdrawal_address', {})
        address = self.safe_string(withdrawalAddress, 'address')
        tag = self.safe_string(withdrawalAddress, 'additional_address_parameter')
        currencyId = self.safe_string(transaction, 'currency_id')
        code = None
        if currencyId in self.currencies_by_id:
            currency = self.currencies_by_id[currencyId]
        else:
            code = self.common_currency_code(self.safe_string(transaction, 'currency_code'))
        if (code is None) and (currency is not None):
            code = currency['code']
        type = 'deposit' if ('deposit_status_id' in transaction) else 'withdrawal'
        amount = self.safe_number(transaction, 'amount')
        status = self.parse_transaction_status(self.safe_string_lower(transaction, 'status'))
        timestamp = self.safe_timestamp_2(transaction, 'timestamp', 'created_ts')
        updated = self.safe_timestamp(transaction, 'updated_ts')
        txid = self.safe_string(transaction, 'txid')
        fee = None
        feeCost = self.safe_number(transaction, 'fee')
        if feeCost is not None:
            feeCurrencyId = self.safe_string_2(transaction, 'fee_currency_id', 'deposit_fee_currency_id')
            feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
            fee = {
                'cost': feeCost,
                'currency': feeCurrencyCode,
            }
        network = self.safe_string(withdrawalAddress, 'protocol_name')
        return {
            'info': transaction,
            'id': id,
            'txid': txid,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'network': network,
            'addressFrom': None,
            'address': address,
            'addressTo': address,
            'tagFrom': None,
            'tag': tag,
            'tagTo': tag,
            'type': type,
            'amount': amount,
            'currency': code,
            'status': status,
            'updated': updated,
            'fee': fee,
        }

    def fetch_deposit(self, id, code=None, params={}):
        """
        fetch information on a deposit
        :param str id: deposit id
        :param str|None code: not used by stex fetchDeposit()
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: a `transaction structure <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        self.load_markets()
        request = {
            'id': id,
        }
        response = self.profileGetDepositsId(self.extend(request, params))
        #
        #     {
        #         success: True,
        #         data: {
        #             id: '21974074',
        #             currency_id: '272',
        #             block_explorer_url: 'https://omniexplorer.info/search/',
        #             currency_code: 'USDT',
        #             deposit_fee_currency_id: '272',
        #             deposit_fee_currency_code: 'USDT',
        #             amount: '11.00000000',
        #             fee: '0.00000000',
        #             deposit_status_id: '3',
        #             status: 'FINISHED',
        #             status_color: '#00BE75',
        #             txid: '15b50da4600a5021dbddaed8f4a71de093bf206ea66eb4ab2f151e3e9e2fed71',
        #             protocol_id: '24',
        #             confirmations: '129 of 20',
        #             created_at: '2022-05-16 16:38:40',
        #             timestamp: '1652719120',
        #             protocol_specific_settings: [{
        #                 protocol_name: 'TRON',
        #                 protocol_id: '24',
        #                 block_explorer_url: 'https://tronscan.org/#/transaction/'
        #             }]
        #         },
        #         unified_message: {
        #             message_id: 'operation_successful',
        #             substitutions: []
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        return self.parse_transaction(data)

    def fetch_deposits(self, code=None, since=None, limit=None, params={}):
        """
        fetch all deposits made to an account
        :param str|None code: unified currency code
        :param int|None since: the earliest time in ms to fetch deposits for
        :param int|None limit: the maximum number of deposits structures to retrieve
        :param dict params: extra parameters specific to the stex api endpoint
        :returns [dict]: a list of `transaction structures <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        self.load_markets()
        currency = None
        request = {}
        if code is not None:
            currency = self.currency(code)
            request['currencyId'] = currency['id']
        if limit is not None:
            request['limit'] = limit
        if since is not None:
            request['timeStart'] = since
        response = self.profileGetDeposits(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": [
        #             {
        #                 "id": 123654789,
        #                 "currency_id": 1,
        #                 "currency_code": "BTC",
        #                 "deposit_fee_currency_id": 1,
        #                 "deposit_fee_currency_code": "BTC",
        #                 "amount": 0.25,
        #                 "fee": 0.00025,
        #                 "txid": "qwertyuhgfdsasdfgh",
        #                 "protocol_id": 0,
        #                 "deposit_status_id": 1,
        #                 "status": "PROCESSING",
        #                 "status_color": "#BC3D51",
        #                 "created_at": "2018-11-28 12:32:08",
        #                 "timestamp": "1543409389",
        #                 "confirmations": "1 of 2",
        #                 "protocol_specific_settings": {
        #                     "protocol_name": "Tether OMNI",
        #                     "protocol_id": 10,
        #                     "block_explorer_url": "https://omniexplorer.info/search/"
        #                 }
        #             }
        #         ]
        #     }
        #
        deposits = self.safe_value(response, 'data', [])
        return self.parse_transactions(deposits, currency, since, limit)

    def fetch_withdrawal(self, id, code=None, params={}):
        """
        fetch data on a currency withdrawal via the withdrawal id
        :param str id: withdrawal id
        :param str|None code: not used by stex.fetchWithdrawal
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: a `transaction structure <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        self.load_markets()
        request = {
            'id': id,
        }
        response = self.profileGetWithdrawalsId(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": {
        #             "id": 65899,
        #             "amount": "0.00600000",
        #             "currency_id": 1,
        #             "currency_code": "BTC",
        #             "fee": "0.00400000",
        #             "fee_currency_id": 1,
        #             "fee_currency_code": "BTC",
        #             "withdrawal_status_id": 1,
        #             "status": "Not Confirmed",
        #             "status_color": "#BC3D51",
        #             "created_at": "2019-01-21 09:36:05",
        #             "created_ts": "1548063365",
        #             "updated_at": "2019-01-21 09:36:05",
        #             "updated_ts": "1548063365",
        #             "reason": "string",
        #             "txid": null,
        #             "protocol_id": 0,
        #             "withdrawal_address": {
        #                 "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
        #                 "address_name": "Address",
        #                 "additional_address_parameter": "qwertyuiopasdfghjkl",
        #                 "additional_address_parameter_name": "Destination Tag",
        #                 "notification": "",
        #                 "protocol_id": 10,
        #                 "protocol_name": "Tether OMNI",
        #                 "supports_new_address_creation": False
        #             },
        #             "protocol_specific_settings": {
        #                 "protocol_name": "Tether OMNI",
        #                 "protocol_id": 10,
        #                 "block_explorer_url": "https://omniexplorer.info/search/"
        #             }
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        return self.parse_transaction(data)

    def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
        """
        fetch all withdrawals made from an account
        :param str|None code: unified currency code
        :param int|None since: the earliest time in ms to fetch withdrawals for
        :param int|None limit: the maximum number of withdrawals structures to retrieve
        :param dict params: extra parameters specific to the stex api endpoint
        :returns [dict]: a list of `transaction structures <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        self.load_markets()
        currency = None
        request = {}
        if code is not None:
            currency = self.currency(code)
            request['currencyId'] = currency['id']
        if limit is not None:
            request['limit'] = limit
        if since is not None:
            request['timeStart'] = since
        response = self.profileGetWithdrawals(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": [
        #             {
        #                 "id": 65899,
        #                 "amount": "0.00600000",
        #                 "currency_id": 1,
        #                 "currency_code": "BTC",
        #                 "fee": "0.00400000",
        #                 "fee_currency_id": 1,
        #                 "fee_currency_code": "BTC",
        #                 "withdrawal_status_id": 1,
        #                 "status": "Not Confirmed",
        #                 "status_color": "#BC3D51",
        #                 "created_at": "2019-01-21 09:36:05",
        #                 "created_ts": "1548063365",
        #                 "updated_at": "2019-01-21 09:36:05",
        #                 "updated_ts": "1548063365",
        #                 "txid": null,
        #                 "protocol_id": 0,
        #                 "withdrawal_address": {
        #                     "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
        #                     "address_name": "Address",
        #                     "additional_address_parameter": "qwertyuiopasdfghjkl",
        #                     "additional_address_parameter_name": "Destination Tag",
        #                     "notification": "",
        #                     "protocol_id": 10,
        #                     "protocol_name": "Tether OMNI",
        #                     "supports_new_address_creation": False
        #                 },
        #                 "protocol_specific_settings": {
        #                     "protocol_name": "Tether OMNI",
        #                     "protocol_id": 10,
        #                     "block_explorer_url": "https://omniexplorer.info/search/"
        #                 }
        #             }
        #         ]
        #     }
        #
        withdrawals = self.safe_value(response, 'data', [])
        return self.parse_transactions(withdrawals, currency, since, limit)

    def transfer(self, code, amount, fromAccount, toAccount, params={}):
        """
        transfer currency internally between wallets on the same account
        :param str code: unified currency code
        :param float amount: amount to transfer
        :param str fromAccount: account to transfer from
        :param str toAccount: account to transfer to
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: a `transfer structure <https://docs.ccxt.com/en/latest/manual.html#transfer-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        method = None
        request = {}
        if fromAccount == 'referal' and toAccount == 'spot':
            request['currencyId'] = currency['id']
            method = 'profilePostReferralBonusTransferCurrencyId'
        elif toAccount == 'hold':
            request['walletId'] = fromAccount
            amount = self.currency_to_precision(code, amount)
            amount = Precise.string_neg(amount)
            request['amount'] = amount
            method = 'profilePostWalletsWalletIdHoldAmount'
        elif fromAccount == 'hold':
            request['walletId'] = toAccount
            request['amount'] = amount
            method = 'profilePostWalletsWalletIdHoldAmount'
        else:
            raise ExchangeError(self.id + ' transfer() only allows transfers of referal to spot and between a walletId and funding')
        response = getattr(self, method)(self.extend(request, params))
        #
        #  profilePostReferralBonusTransferCurrencyId
        #     {
        #         "success": True,
        #         "data": ""
        #     }
        #
        #  profilePostWalletsWalletIdHoldAmount
        #     {
        #         success: True,
        #         data: {
        #             id: '4055802',
        #             currency_id: '272',
        #             currency_code: 'USDT',
        #             currency_name: 'TetherUSD',
        #             balance: '10.00000000',
        #             frozen_balance: '0.00000000',
        #             bonus_balance: '0.00000000',
        #             hold_balance: '1.00000000',
        #             total_balance: '11.00000000',
        #             disable_deposits: False,
        #             disable_withdrawals: False,
        #             withdrawal_limit: '0.00000000',
        #             delisted: False,
        #             disabled: False,
        #             deposit_address: null,
        #             multi_deposit_addresses: [{
        #                 address: 'TYzhabfHWMLgLnMW46ZyUHkUVJPXaDgdxK',
        #                 address_name: 'Deposit Address',
        #                 additional_address_parameter: null,
        #                 additional_address_parameter_name: null,
        #                 notification: '',
        #                 protocol_id: '24',
        #                 protocol_name: 'TRON',
        #                 supports_new_address_creation: False
        #             }],
        #             contract_or_asset_id: '31',
        #             contract_field_name: null,
        #             withdrawal_additional_field_name: null,
        #             depo_message: '',
        #             wd_message: '',
        #             currency_type_id: '23',
        #             protocol_specific_settings: [{
        #                 {
        #                     protocol_name: 'ERC20',
        #                     protocol_id: '5',
        #                     active: True,
        #                     disable_deposits: False,
        #                     disable_withdrawals: False,
        #                     withdrawal_limit: '0',
        #                     deposit_fee_currency_id: '272',
        #                     deposit_fee_currency_code: 'USDT',
        #                     deposit_fee_percent: '0',
        #                     deposit_fee_const: '0',
        #                     withdrawal_fee_currency_id: '272',
        #                     withdrawal_fee_currency_code: 'USDT',
        #                     withdrawal_fee_const: '10',
        #                     withdrawal_fee_percent: '0',
        #                     block_explorer_url: 'https://etherscan.io/tx/',
        #                     contract_or_asset_id: '0xdac17f958d2ee523a2206206994597c13d831ec7',
        #                     contract_field_name: '',
        #                     withdrawal_additional_field_name: '',
        #                     depo_message: '',
        #                     wd_message: ''
        #                 },
        #                 ...
        #             ],
        #             coin_info: {
        #                 twitter: 'https://twitter.com/Tether_to',
        #                 version: '',
        #                 facebook: 'https://www.facebook.com/tether.to',
        #                 telegram: '',
        #                 icon_large: 'https://app-coin-images.stex.com/large/usdt.png',
        #                 icon_small: 'https://app-coin-images.stex.com/small/usdt.png',
        #                 description: 'Tether(USDT) is a cryptocurrency with a value meant to mirror the value of the U.S. dollar. The idea was to create a stable cryptocurrency that can be used like digital dollars. Coins that serve self purpose of being a stable dollar substitute are called “stable coins.” Tether is the most popular stable coin and even acts as a dollar replacement on many popular exchanges! According to their site, Tether converts cash into digital currency, to anchor or “tether” the value of the coin to the price of national currencies like the US dollar, the Euro, and the Yen. Like other cryptos it uses blockchain. Unlike other cryptos, it is [according to the official Tether site] “100% backed by USD”(USD is held in reserve). The primary use of Tether is that it offers some stability to the otherwise volatile crypto space and offers liquidity to exchanges who can’t deal in dollars and with banks(for example to the sometimes controversial but leading exchange Bitfinex).The digital coins are issued by a company called Tether Limited that is governed by the laws of the British Virgin Islands, according to the legal part of its website. It is incorporated in Hong Kong. It has emerged that Jan Ludovicus van der Velde is the CEO of cryptocurrency exchange Bitfinex, which has been accused of being involved in the price manipulation of bitcoin, as well as tether. Many people trading on exchanges, including Bitfinex, will use tether to buy other cryptocurrencies like bitcoin. Tether Limited argues that using self method to buy virtual currencies allows users to move fiat in and out of an exchange more quickly and cheaply. Also, exchanges typically have rocky relationships with banks, and using Tether is a way to circumvent that.USDT is fairly simple to use. Once on exchanges like Poloniex or Bittrex, it can be used to purchase Bitcoin and other cryptocurrencies. It can be easily transferred from an exchange to any Omni Layer enabled wallet. Tether has no transaction fees, although external wallets and exchanges may charge one. In order to convert USDT to USD and vise versa through the Tether.to Platform, users must pay a small fee. Buying and selling Tether for Bitcoin can be done through a variety of exchanges like the ones mentioned previously or through the Tether.to platform, which also allows the conversion between USD to and from your bank account.',
        #                 official_site: 'https://tether.to/',
        #                 official_block_explorer: 'https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7'
        #             },
        #             rates: {
        #                 BTC: '0.00003372',
        #                 USD: '1'
        #             }
        #         },
        #         unified_message: {
        #             message_id: 'operation_successful',
        #             substitutions: []
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        transfer = self.parse_transfer(data, currency)
        transferOptions = self.safe_value(self.options, 'transfer', {})
        fillResponseFromRequest = self.safe_value(transferOptions, 'fillResponseFromRequest', True)
        if fillResponseFromRequest:
            transfer['fromAccount'] = fromAccount
            transfer['toAccount'] = toAccount
            if isinstance(amount, str) and Precise.string_lt(amount, '0'):
                amount = self.parse_number(Precise.string_neg(amount))
            transfer['amount'] = amount
            if transfer['currency'] is None:
                transfer['currency'] = code
        return transfer

    def parse_transfer(self, transfer, currency=None):
        #
        #     {
        #         "id": 45875,
        #         "currency_id": 1,
        #         "currency_code": "USDT",
        #         "currency_name": "TetherUSD",
        #         "balance": "0.198752",
        #         "frozen_balance": "1.5784",
        #         "bonus_balance": "0.000",
        #         "hold_balance": "0.000",
        #         "total_balance": "1.777152",
        #         "disable_deposits": False,
        #         "disable_withdrawals": False,
        #         "withdrawal_limit": "string",
        #         "delisted": False,
        #         "disabled": False,
        #         "deposit_address": {
        #             "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
        #             "address_name": "Address",
        #             "additional_address_parameter": "qwertyuiopasdfghjkl",
        #             "additional_address_parameter_name": "Destination Tag",
        #             "notification": "",
        #             "protocol_id": 10,
        #             "protocol_name": "Tether OMNI",
        #             "supports_new_address_creation": False
        #         },
        #         "multi_deposit_addresses": [{
        #             "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
        #             "address_name": "Address",
        #             "additional_address_parameter": "qwertyuiopasdfghjkl",
        #             "additional_address_parameter_name": "Destination Tag",
        #             "notification": "",
        #             "protocol_id": 10,
        #             "protocol_name": "Tether OMNI",
        #             "supports_new_address_creation": False
        #         }],
        #         "withdrawal_additional_field_name": "Payment ID(optional)",
        #         "currency_type_id": 23,
        #         "protocol_specific_settings": [{
        #             "protocol_name": "Tether OMNI",
        #             "protocol_id": 10,
        #             "active": True,
        #             "disable_deposits": False,
        #             "disable_withdrawals": False,
        #             "withdrawal_limit": 0,
        #             "deposit_fee_currency_id": 272,
        #             "deposit_fee_currency_code": "USDT",
        #             "deposit_fee_percent": 0,
        #             "deposit_fee_const": 0,
        #             "withdrawal_fee_currency_id": 1,
        #             "withdrawal_fee_currency_code": "USDT",
        #             "withdrawal_fee_const": 0.002,
        #             "withdrawal_fee_percent": 0,
        #             "block_explorer_url": "https://omniexplorer.info/search/",
        #             "withdrawal_additional_field_name": ""
        #         }],
        #         "coin_info": {
        #             "twitter": "https://twitter.com/btc",
        #             "version": "",
        #             "facebook": "https://www.facebook.com/bitcoins",
        #             "telegram": "",
        #             "icon_large": "https://app-coin-images.stex.com/large/btc.png",
        #             "icon_small": "https://app-coin-images.stex.com/small/btc.png",
        #             "description": "Bitcoin is the first successful internet money based on peer-to-peer technology;....",
        #             "official_site": "http://www.bitcoin.org",
        #             "official_block_explorer": "https://blockchair.com/bitcoin/"
        #         },
        #         "rates": {
        #             "BTC": 0.000001
        #         }
        #     }
        #
        currencyId = self.safe_string(transfer, 'currency_id')
        code = None
        if currencyId in self.currencies_by_id:
            currency = self.currencies_by_id[currencyId]
        else:
            code = self.common_currency_code(self.safe_string(transfer, 'currency_code'))
        if code is None:
            code = self.safe_value(currency, 'code')
        return {
            'info': transfer,
            'id': self.safe_string(transfer, 'id'),
            'timestamp': None,
            'datetime': None,
            'currency': code,
            'amount': None,
            'fromAccount': None,
            'toAccount': None,
            'status': None,
        }

    def withdraw(self, code, amount, address, tag=None, params={}):
        """
        make a withdrawal
        :param str code: unified currency code
        :param float amount: the amount to withdraw
        :param str address: the address to withdraw to
        :param str|None tag:
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: a `transaction structure <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        tag, params = self.handle_withdraw_tag_and_params(tag, params)
        self.check_address(address)
        self.load_markets()
        currency = self.currency(code)
        request = {
            'currency_id': currency['id'],
            'amount': float(self.currency_to_precision(code, amount)),
            'address': address,
            # 'protocol_id': 10,  # optional, to be used with multicurrency wallets like USDT
            # 'additional_address_parameter': tag,  # optional
        }
        if tag is not None:
            request['additional_address_parameter'] = tag
        networks = self.safe_value(self.options, 'networks', {})
        network = self.safe_string_upper(params, 'network')  # self line allows the user to specify either ERC20 or ETH
        network = self.safe_integer(networks, network, network)  # handle ERC20>ETH alias
        if network is not None:
            request['protocol_id'] = network
            params = self.omit(params, 'network')
        response = self.profilePostWithdraw(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "data": {
        #             "id": 65899,
        #             "amount": "0.00600000",
        #             "currency_id": 1,
        #             "currency_code": "BTC",
        #             "fee": "0.00400000",
        #             "fee_currency_id": 1,
        #             "fee_currency_code": "BTC",
        #             "withdrawal_status_id": 1,
        #             "status": "Not Confirmed",
        #             "status_color": "#BC3D51",
        #             "created_at": "2019-01-21 09:36:05",
        #             "created_ts": "1548063365",
        #             "updated_at": "2019-01-21 09:36:05",
        #             "updated_ts": "1548063365",
        #             "txid": null,
        #             "protocol_id": 0,
        #             "withdrawal_address": {
        #                 "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
        #                 "address_name": "Address",
        #                 "additional_address_parameter": "qwertyuiopasdfghjkl",
        #                 "additional_address_parameter_name": "Destination Tag",
        #                 "notification": "",
        #                 "protocol_id": 10,
        #                 "protocol_name": "Tether OMNI",
        #                 "supports_new_address_creation": False
        #             }
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        return self.parse_transaction(data, currency)

    def fetch_transaction_fees(self, codes=None, params={}):
        """
        *DEPRECATED* please use fetchDepositWithdrawFees instead
        see https://apidocs.stex.com/#tag/Public/paths/~1public~1currencies/get
        :param [str]|None codes: list of unified currency codes
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: a list of `fee structures <https://docs.ccxt.com/en/latest/manual.html#fee-structure>`
        """
        self.load_markets()
        #
        #     {
        #         "success": True,
        #         "data": [
        #             {
        #                 "id": 1,
        #                 "code": "BTC",
        #                 "name": "Bitcoin",
        #                 "active": True,
        #                 "delisted": False,
        #                 "precision": 8,
        #                 "minimum_tx_confirmations": 24,
        #                 "minimum_withdrawal_amount": "0.009",
        #                 "minimum_deposit_amount": "0.000003",
        #                 "deposit_fee_currency_id": 1,
        #                 "deposit_fee_currency_code": "ETH",
        #                 "deposit_fee_const": "0.00001",
        #                 "deposit_fee_percent": "0",
        #                 "withdrawal_fee_currency_id": 1,
        #                 "withdrawal_fee_currency_code": "ETH",
        #                 "withdrawal_fee_const": "0.0015",
        #                 "withdrawal_fee_percent": "0",
        #                 "withdrawal_limit": "string",
        #                 "block_explorer_url": "https://blockchain.info/tx/",
        #                 "protocol_specific_settings": [
        #                     {
        #                         "protocol_name": "Tether OMNI",
        #                         "protocol_id": 10,
        #                         "active": True,
        #                         "withdrawal_fee_currency_id": 1,
        #                         "withdrawal_fee_const": 0.002,
        #                         "withdrawal_fee_percent": 0,
        #                         "block_explorer_url": "https://omniexplorer.info/search/"
        #                     }
        #                 ]
        #             }
        #         ]
        #     }
        #
        currencyKeys = list(self.currencies.keys())
        result = {}
        for i in range(0, len(currencyKeys)):
            code = currencyKeys[i]
            currency = self.currencies[code]
            if codes is not None and not self.in_array(code, codes):
                continue
            info = self.safe_value(currency, 'info')
            result[code] = {
                'withdraw': self.safe_number(currency, 'fee'),
                'deposit': self.safe_number(info, 'deposit_fee_const'),
                'info': info,
            }
        return result

    def fetch_deposit_withdraw_fees(self, codes=None, params={}):
        """
        fetch deposit and withdraw fees
        see https://apidocs.stex.com/#tag/Public/paths/~1public~1currencies/get
        :param [str]|None codes: list of unified currency codes
        :param dict params: extra parameters specific to the stex api endpoint
        :returns dict: a list of `fee structures <https://docs.ccxt.com/en/latest/manual.html#fee-structure>`
        """
        self.load_markets()
        response = self.publicGetCurrencies(params)
        #
        #     {
        #         "success": True,
        #         "data": [
        #             {
        #                 "id": 1,
        #                 "code": "BTC",
        #                 "name": "Bitcoin",
        #                 "active": True,
        #                 "delisted": False,
        #                 "precision": 8,
        #                 "minimum_tx_confirmations": 24,
        #                 "minimum_withdrawal_amount": "0.009",
        #                 "minimum_deposit_amount": "0.000003",
        #                 "deposit_fee_currency_id": 1,
        #                 "deposit_fee_currency_code": "ETH",
        #                 "deposit_fee_const": "0.00001",
        #                 "deposit_fee_percent": "0",
        #                 "withdrawal_fee_currency_id": 1,
        #                 "withdrawal_fee_currency_code": "ETH",
        #                 "withdrawal_fee_const": "0.0015",
        #                 "withdrawal_fee_percent": "0",
        #                 "withdrawal_limit": "string",
        #                 "block_explorer_url": "https://blockchain.info/tx/",
        #                 "protocol_specific_settings": [
        #                     {
        #                         "protocol_name": "Tether OMNI",
        #                         "protocol_id": 10,
        #                         "active": True,
        #                         "withdrawal_fee_currency_id": 1,
        #                         "withdrawal_fee_const": 0.002,
        #                         "withdrawal_fee_percent": 0,
        #                         "block_explorer_url": "https://omniexplorer.info/search/"
        #                     }
        #                 ]
        #             }
        #             ...
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data')
        return self.parse_deposit_withdraw_fees(data, codes, 'code')

    def parse_deposit_withdraw_fee(self, fee, currency=None):
        #
        #    {
        #        "id": 1,
        #        "code": "BTC",
        #        "name": "Bitcoin",
        #        "active": True,
        #        "delisted": False,
        #        "precision": 8,
        #        "minimum_tx_confirmations": 24,
        #        "minimum_withdrawal_amount": "0.009",
        #        "minimum_deposit_amount": "0.000003",
        #        "deposit_fee_currency_id": 1,
        #        "deposit_fee_currency_code": "ETH",
        #        "deposit_fee_const": "0.00001",
        #        "deposit_fee_percent": "0",
        #        "withdrawal_fee_currency_id": 1,
        #        "withdrawal_fee_currency_code": "ETH",
        #        "withdrawal_fee_const": "0.0015",
        #        "withdrawal_fee_percent": "0",
        #        "withdrawal_limit": "string",
        #        "block_explorer_url": "https://blockchain.info/tx/",
        #        "protocol_specific_settings": [
        #            {
        #                "protocol_name": "Tether OMNI",
        #                "protocol_id": 10,
        #                "active": True,
        #                "withdrawal_fee_currency_id": 1,
        #                "withdrawal_fee_const": 0.002,
        #                "withdrawal_fee_percent": 0,
        #                "block_explorer_url": "https://omniexplorer.info/search/"
        #            }
        #        ]
        #    }
        #
        result = {
            'withdraw': {
                'fee': self.safe_number(fee, 'withdrawal_fee_const'),
                'percentage': False,
            },
            'deposit': {
                'fee': self.safe_number(fee, 'deposit_fee_const'),
                'percentage': False,
            },
            'networks': {},
        }
        networks = self.safe_value(fee, 'protocol_specific_settings', [])
        for i in range(0, len(networks)):
            network = networks[i]
            networkId = self.safe_string(network, 'protocol_name')
            networkCode = self.network_id_to_code(networkId)
            result['networks'][networkCode] = {
                'withdraw': {
                    'fee': self.safe_number(network, 'withdrawal_fee_const'),
                    'percentage': False,
                },
                'deposit': {
                    'fee': None,
                    'percentage': None,
                },
            }
        return result

    def handle_errors(self, httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody):
        if response is None:
            return  # fallback to default error handler
        #
        #     {"success":false,"message":"Wrong parameters","errors":{"candleType":["Invalid Candle Type!"]}}
        #     {"success":false,"message":"Wrong parameters","errors":{"time":["timeStart or timeEnd is less then 1"]}}
        #     {"success":false,"message":"Not enough  ETH"}
        #
        success = self.safe_value(response, 'success', False)
        if not success:
            message = self.safe_string(response, 'message')
            feedback = self.id + ' ' + body
            self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
            self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
            raise ExchangeError(feedback)  # unknown message
