<?php

namespace ccxt\async;

// 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

use Exception; // a common import
use \ccxt\ExchangeError;
use \ccxt\ArgumentsRequired;
use \ccxt\OrderNotFound;

class stex extends Exchange {

    public function describe() {
        return $this->deep_extend(parent::describe (), array(
            'id' => 'stex',
            'name' => 'STEX', // formerly known as stocks.exchange
            'countries' => array( 'EE' ), // Estonia
            'rateLimit' => 500, // https://help.stex.com/en/articles/2815043-api-3-rate-limits
            'certified' => false,
            // new metainfo interface
            'has' => array(
                'cancelAllOrders' => true,
                'cancelOrder' => true,
                'CORS' => false,
                'createDepositAddress' => true,
                'createMarketOrder' => false, // limit orders only
                'createOrder' => true,
                'fetchBalance' => true,
                'fetchCurrencies' => true,
                'fetchDepositAddress' => true,
                'fetchDeposits' => true,
                'fetchFundingFees' => true,
                'fetchMarkets' => true,
                'fetchMyTrades' => true,
                'fetchOHLCV' => true,
                'fetchOpenOrders' => true,
                'fetchOrder' => true,
                'fetchOrderBook' => true,
                'fetchOrderTrades' => true,
                'fetchTicker' => true,
                'fetchTickers' => true,
                'fetchTime' => true,
                'fetchTrades' => true,
                'fetchWithdrawals' => true,
                'withdraw' => true,
            ),
            'version' => 'v3',
            'urls' => array(
                'logo' => 'https://user-images.githubusercontent.com/1294454/69680782-03fd0b80-10bd-11ea-909e-7f603500e9cc.jpg',
                'api' => 'https://api3.stex.com',
                'www' => 'https://www.stex.com',
                'doc' => array(
                    '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' => array(
                'apiKey' => false,
                'secret' => false,
                'token' => true,
            ),
            'timeframes' => array(
                '1m' => '1',
                '5m' => '5',
                '30m' => '30',
                '1h' => '60',
                '4h' => '240',
                '12h' => '720',
                '1d' => '1D', // default
            ),
            'api' => array(
                'public' => array(
                    'get' => array(
                        'currencies', // Available Currencies
                        'currencies/{currencyId}', // Get currency info
                        'markets', // Available markets
                        'pairs-groups', // Available currency pairs groups (as displayed at stex trading page)
                        'currency_pairs/list/{code}', // Available currency pairs
                        'currency_pairs/group/{currencyPairGroupId}', // Available currency pairs for a given group
                        'currency_pairs/{currencyPairId}', // Get currency pair information
                        'ticker', // Tickers list for all currency pairs
                        'ticker/{currencyPairId}', // Ticker for currency pair
                        'trades/{currencyPairId}', // Trades for given currency pair
                        'orderbook/{currencyPairId}', // Orderbook for given currency pair
                        'chart/{currencyPairId}/{candlesType}', // A list of candles for given currency pair
                        'deposit-statuses', // Available Deposit Statuses
                        'deposit-statuses/{statusId}', // Get deposit status info
                        'withdrawal-statuses', // Available Withdrawal Statuses
                        'withdrawal-statuses/{statusId}', // Get status info
                        'ping', // Test API is working and get server time
                        'mobile-versions', // Shows the official mobile applications data
                    ),
                ),
                'trading' => array(
                    'get' => array(
                        'fees/{currencyPairId}', // Returns the user's fees for a given currency pair
                        'orders', // List your currently open orders
                        'orders/{currencyPairId}', // List your currently open orders for given currency pair
                        'order/{orderId}', // Get a single order
                    ),
                    'post' => array(
                        'orders/{currencyPairId}', // Create new order and put it to the orders processing queue
                    ),
                    'delete' => array(
                        'orders', // Delete all active orders
                        'orders/{currencyPairId}', // Delete active orders for given currency pair
                        'order/{orderId}', // Cancel order
                    ),
                ),
                'reports' => array(
                    'get' => array(
                        'orders', // Get past orders
                        'orders/{orderId}', // Get specified order details
                        'trades/{currencyPairId}', // Get a list of user trades according to request parameters
                        'background/{listMode}', // Get reports list for category
                        'background/{id}', // Get some report info
                        'background/download/{id}', // Get file by id
                    ),
                    'post' => array(
                        'background/create', // Create new report
                    ),
                    'delete' => array(
                        'background/{id}', // Remove report by id
                    ),
                ),
                'profile' => array(
                    'get' => array(
                        'info', // Account information
                        'wallets', // Get a list of user wallets
                        'wallets/{walletId}', // Single wallet information
                        'wallets/address/{walletId}', // Get deposit address for given wallet
                        'deposits', // Get a list of deposits made by user
                        'deposits/{id}', // Get deposit by id
                        'withdrawals', // Get a list of withdrawals made by user
                        'withdrawals/{id}', // Get withdrawal by id
                        'notifications', // Get notifications
                        'favorite/currency_pairs', // Get favorite currency pairs
                        'token-scopes', // Get current token scopes
                    ),
                    'post' => array(
                        'wallets/burn/{walletId}', // Burns the given wallet
                        'wallets/{currencyId}', // Create a wallet for given currency
                        'wallets/address/{walletId}', // Create new deposit address
                        'withdraw', // Create withdrawal request
                        'referral/program', // Create referral program
                        'referral/insert/{code}', // Insert referral code
                        'referral/bonus_transfer/{currencyId}', // Transfer referral bonuses balance to main balance for given currency
                    ),
                    'put' => array(
                        'profile/favorite/currency_pairs/set', // Set favorite currency pairs
                    ),
                    'delete' => array(
                        'profile/withdraw/{withdrawalId}', // Cancel unconfirmed withdrawal
                    ),
                ),
                'verification' => array(
                    'get' => array(
                        'verification/countries', // Countries list, beta
                        'verification/stex', // Get information about your KYC, beta
                    ),
                    'post' => array(
                        'verification/stex', // Update information regarding of your KYC verification, beta
                    ),
                ),
                'settings' => array(
                    'get' => array(
                        'notifications/{event}', // User event notification settings
                        'notifications', // User events notification settings
                    ),
                    'put' => array(
                        'notifications', // Set notification settings
                        'notifications/set',
                    ),
                ),
            ),
            'fees' => array(
                'trading' => array(
                    'tierBased' => false,
                    'percentage' => true,
                    'taker' => 0.002,
                    'maker' => 0.002,
                ),
            ),
            'commonCurrencies' => array(
                'BC' => 'Bitcoin Confidential',
                'BITS' => 'Bitcoinus',
                'BITSW' => 'BITS',
                'BHD' => 'Bithold',
                'BTH' => 'Bithereum',
                'SBTC' => 'SBTCT', // SiamBitcoin
            ),
            'options' => array(
                'parseOrderToPrecision' => false,
            ),
            'exceptions' => array(
                'exact' => array(
                    // array("success":false,"message":"Wrong parameters","errors":array("candleType":["Invalid Candle Type!"]))
                    // array("success":false,"message":"Wrong parameters","errors":array("time":["timeStart or timeEnd is less then 1"]))
                    'Wrong parameters' => '\\ccxt\\BadRequest',
                    'Unauthenticated.' => '\\ccxt\\AuthenticationError', // array("message":"Unauthenticated.")
                    'Server Error' => '\\ccxt\\ExchangeError', // array( "message" => "Server Error" )
                    'This feature is only enabled for users verifies by Cryptonomica' => '\\ccxt\\PermissionDenied', // array("success":false,"message":"This feature is only enabled for users verifies by Cryptonomica")
                    'Too Many Attempts.' => '\\ccxt\\DDoSProtection', // array( "message" => "Too Many Attempts." )
                ),
                'broad' => array(
                    'Not enough' => '\\ccxt\\InsufficientFunds', // array("success":false,"message":"Not enough  ETH")
                ),
            ),
        ));
    }

    public function fetch_currencies($params = array ()) {
        $response = yield $this->publicGetCurrencies ($params);
        //
        //     {
        //         "success":true,
        //         "data":array(
        //             array(
        //                 "$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 = array();
        $currencies = $this->safe_value($response, 'data', array());
        for ($i = 0; $i < count($currencies); $i++) {
            $currency = $currencies[$i];
            $id = $this->safe_string($currency, 'id');
            $numericId = $this->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 = $this->safe_currency_code($this->safe_string($currency, 'code'));
            $precision = $this->safe_integer($currency, 'precision');
            $fee = $this->safe_float($currency, 'withdrawal_fee_const'); // todo => redesign
            $active = $this->safe_value($currency, 'active', true);
            $result[$code] = array(
                'id' => $id,
                'numericId' => $numericId,
                'code' => $code,
                'info' => $currency,
                'type' => null,
                'name' => $this->safe_string($currency, 'name'),
                'active' => $active,
                'fee' => $fee,
                'precision' => $precision,
                'limits' => array(
                    'amount' => array( 'min' => pow(10, -$precision), 'max' => null ),
                    'price' => array( 'min' => pow(10, -$precision), 'max' => null ),
                    'cost' => array( 'min' => null, 'max' => null ),
                    'deposit' => array(
                        'min' => $this->safe_float($currency, 'minimum_deposit_amount'),
                        'max' => null,
                    ),
                    'withdraw' => array(
                        'min' => $this->safe_float($currency, 'minimum_withdrawal_amount'),
                        'max' => null,
                    ),
                ),
            );
        }
        return $result;
    }

    public function fetch_markets($params = array ()) {
        $request = array(
            'code' => 'ALL',
        );
        $response = yield $this->publicGetCurrencyPairsListCode (array_merge($request, $params));
        //
        //     {
        //         "success":true,
        //         "data":array(
        //             {
        //                 "$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 = array();
        $markets = $this->safe_value($response, 'data', array());
        for ($i = 0; $i < count($markets); $i++) {
            $market = $markets[$i];
            $id = $this->safe_string($market, 'id');
            $numericId = $this->safe_integer($market, 'id');
            $baseId = $this->safe_string($market, 'currency_id');
            $quoteId = $this->safe_string($market, 'market_currency_id');
            $baseNumericId = $this->safe_integer($market, 'currency_id');
            $quoteNumericId = $this->safe_integer($market, 'market_currency_id');
            $base = $this->safe_currency_code($this->safe_string($market, 'currency_code'));
            $quote = $this->safe_currency_code($this->safe_string($market, 'market_code'));
            $symbol = $base . '/' . $quote;
            $precision = array(
                'amount' => $this->safe_integer($market, 'currency_precision'),
                'price' => $this->safe_integer($market, 'market_precision'),
            );
            $active = $this->safe_value($market, 'active');
            $minBuyPrice = $this->safe_float($market, 'min_buy_price');
            $minSellPrice = $this->safe_float($market, 'min_sell_price');
            $minPrice = max ($minBuyPrice, $minSellPrice);
            $buyFee = $this->safe_float($market, 'buy_fee_percent') / 100;
            $sellFee = $this->safe_float($market, 'sell_fee_percent') / 100;
            $fee = max ($buyFee, $sellFee);
            $result[] = array(
                'id' => $id,
                'numericId' => $numericId,
                'symbol' => $symbol,
                'base' => $base,
                'quote' => $quote,
                'baseId' => $baseId,
                'quoteId' => $quoteId,
                'baseNumericId' => $baseNumericId,
                'quoteNumericId' => $quoteNumericId,
                'info' => $market,
                'active' => $active,
                'maker' => $fee,
                'taker' => $fee,
                'precision' => $precision,
                'limits' => array(
                    'amount' => array(
                        'min' => $this->safe_float($market, 'min_order_amount'),
                        'max' => null,
                    ),
                    'price' => array( 'min' => $minPrice, 'max' => null ),
                    'cost' => array(
                        'min' => null,
                        'max' => null,
                    ),
                ),
            );
        }
        return $result;
    }

    public function fetch_ticker($symbol, $params = array ()) {
        yield $this->load_markets();
        $market = $this->market($symbol);
        $request = array(
            'currencyPairId' => $market['id'],
        );
        $response = yield $this->publicGetTickerCurrencyPairId (array_merge($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" => array(
        //                 "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 = $this->safe_value($response, 'data', array());
        return $this->parse_ticker($ticker, $market);
    }

    public function fetch_time($params = array ()) {
        $response = yield $this->publicGetPing ($params);
        //
        //     {
        //         "success" => true,
        //         "$data" => {
        //             "server_datetime" => array(
        //                 "date" => "2019-01-22 15:13:34.233796",
        //                 "timezone_type" => 3,
        //                 "timezone" => "UTC"
        //             ),
        //             "server_timestamp" => 1548170014
        //         }
        //     }
        //
        $data = $this->safe_value($response, 'data', array());
        $serverDatetime = $this->safe_value($data, 'server_datetime', array());
        return $this->parse8601($this->safe_string($serverDatetime, 'date'));
    }

    public function fetch_order_book($symbol, $limit = null, $params = array ()) {
        yield $this->load_markets();
        $market = $this->market($symbol);
        $request = array(
            'currencyPairId' => $market['id'],
        );
        if ($limit !== null) {
            $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 = yield $this->publicGetOrderbookCurrencyPairId (array_merge($request, $params));
        //
        //     {
        //         "success" => true,
        //         "data" => {
        //             "ask" => array(
        //                 array( "currency_pair_id" => 2, "amount" => "2.17865373", "price" => "0.02062917", "amount2" => "0.04494382", "count" => 1, "cumulative_amount" => 2.17865373 ),
        //                 array( "currency_pair_id" => 2, "amount" => "2.27521743", "price" => "0.02062918", "amount2" => "0.04693587", "count" => 1, "cumulative_amount" => 4.45387116 ),
        //                 array( "currency_pair_id" => 2, "amount" => "1.26980049", "price" => "0.02063170", "amount2" => "0.02619814", "count" => 1, "cumulative_amount" => 5.72367165 ),
        //             ),
        //             "bid" => array(
        //                 array( "currency_pair_id" => 2, "amount" => "0.00978005", "price" => "0.02057000", "amount2" => "0.00020118", "count" => 1, "cumulative_amount" => 0.00978005 ),
        //                 array( "currency_pair_id" => 2, "amount" => "0.00500000", "price" => "0.02056000", "amount2" => "0.00010280", "count" => 1, "cumulative_amount" => 0.01478005 ),
        //                 array( "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 = $this->safe_value($response, 'data', array());
        return $this->parse_order_book($orderbook, null, 'bid', 'ask', 'price', 'amount');
    }

    public function parse_ticker($ticker, $market = null) {
        //
        //     {
        //         "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" => array(
        //             "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 = $this->safe_integer($ticker, 'timestamp');
        $marketId = $this->safe_string_2($ticker, 'id', 'symbol');
        $symbol = $this->safe_symbol($marketId, $market, '_');
        $last = $this->safe_float($ticker, 'last');
        $open = $this->safe_float($ticker, 'open');
        $change = null;
        $percentage = null;
        if ($last !== null) {
            if (($open !== null) && ($open > 0)) {
                $change = $last - $open;
                $percentage = ((100 / $open) * $last) - 100;
            }
        }
        return array(
            'symbol' => $symbol,
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'high' => $this->safe_float($ticker, 'high'),
            'low' => $this->safe_float($ticker, 'low'),
            'bid' => $this->safe_float($ticker, 'bid'),
            'bidVolume' => null,
            'ask' => $this->safe_float($ticker, 'ask'),
            'askVolume' => null,
            'vwap' => null,
            'open' => $open,
            'close' => $last,
            'last' => $last,
            'previousClose' => null, // previous day close
            'change' => $change,
            'percentage' => $percentage,
            'average' => null,
            'baseVolume' => $this->safe_float($ticker, 'volumeQuote'),
            'quoteVolume' => $this->safe_float($ticker, 'volume'),
            'info' => $ticker,
        );
    }

    public function parse_tickers($tickers, $symbols = null) {
        $result = array();
        for ($i = 0; $i < count($tickers); $i++) {
            $result[] = $this->parse_ticker($tickers[$i]);
        }
        return $this->filter_by_array($result, 'symbol', $symbols);
    }

    public function fetch_tickers($symbols = null, $params = array ()) {
        yield $this->load_markets();
        $response = yield $this->publicGetTicker ($params);
        //
        //     {
        //         "success":true,
        //         "data":array(
        //             array(
        //                 "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":array(
        //                     "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 = $this->safe_value($response, 'data', array());
        return $this->parse_tickers($tickers, $symbols);
    }

    public function parse_ohlcv($ohlcv, $market = null) {
        //
        //     {
        //         "time" => 1566086400000,
        //         "close" => 0.01895,
        //         "open" => 0.01812427,
        //         "high" => 0.0191588,
        //         "low" => 0.01807001,
        //         "volume" => 2588.597813750006
        //     }
        //
        return array(
            $this->safe_integer($ohlcv, 'time'),
            $this->safe_float($ohlcv, 'open'),
            $this->safe_float($ohlcv, 'high'),
            $this->safe_float($ohlcv, 'low'),
            $this->safe_float($ohlcv, 'close'),
            $this->safe_float($ohlcv, 'volume'),
        );
    }

    public function fetch_ohlcv($symbol, $timeframe = '1d', $since = null, $limit = null, $params = array ()) {
        yield $this->load_markets();
        $market = $this->market($symbol);
        $request = array(
            'currencyPairId' => $market['id'],
            'candlesType' => $this->timeframes[$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 === null) {
            $limit = 100;
        } else {
            $request['limit'] = $limit;
        }
        $duration = $this->parse_timeframe($timeframe);
        $timerange = $limit * $duration;
        if ($since === null) {
            $request['timeEnd'] = $this->seconds();
            $request['timeStart'] = $request['timeEnd'] - $timerange;
        } else {
            $request['timeStart'] = intval($since / 1000);
            $request['timeEnd'] = $this->sum($request['timeStart'], $timerange);
        }
        $response = yield $this->publicGetChartCurrencyPairIdCandlesType (array_merge($request, $params));
        //
        //     {
        //         "success" => true,
        //         "$data" => array(
        //             array(
        //                 "time" => 1566086400000,
        //                 "close" => 0.01895,
        //                 "open" => 0.01812427,
        //                 "high" => 0.0191588,
        //                 "low" => 0.01807001,
        //                 "volume" => 2588.597813750006
        //             ),
        //         )
        //     }
        //
        $data = $this->safe_value($response, 'data', array());
        return $this->parse_ohlcvs($data, $market, $timeframe, $since, $limit);
    }

    public function parse_trade($trade, $market = null) {
        //
        // 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 = $this->safe_string($trade, 'id');
        $timestamp = $this->safe_timestamp($trade, 'timestamp');
        $price = $this->safe_float($trade, 'price');
        $amount = $this->safe_float($trade, 'amount');
        $cost = null;
        if (($price !== null) && ($amount !== null)) {
            $cost = $price * $amount;
        }
        $symbol = null;
        if (($symbol === null) && ($market !== null)) {
            $symbol = $market['symbol'];
        }
        $side = $this->safe_string_lower_2($trade, 'type', 'trade_type');
        return array(
            'info' => $trade,
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'symbol' => $symbol,
            'id' => $id,
            'order' => null,
            'type' => null,
            'takerOrMaker' => null,
            'side' => $side,
            'price' => $price,
            'amount' => $amount,
            'cost' => $cost,
            'fee' => null,
        );
    }

    public function fetch_trades($symbol, $since = null, $limit = null, $params = array ()) {
        yield $this->load_markets();
        $market = $this->market($symbol);
        $request = array(
            '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 !== null) {
            $request['limit'] = $limit; // currently limited to 100 or fewer
        }
        if ($since !== null) {
            $request['sort'] = 'ASC'; // needed to make the from param work
            $request['from'] = intval($since / 1000);
        }
        $response = yield $this->publicGetTradesCurrencyPairId (array_merge($request, $params));
        //
        //     {
        //         "success" => true,
        //         "data" => array(
        //             array(
        //                 "id" => 35989317,
        //                 "price" => "0.02033813",
        //                 "amount" => "3.60000000",
        //                 "type" => "BUY",
        //                 "timestamp" => "1574713503"
        //             ),
        //         )
        //     }
        //
        $trades = $this->safe_value($response, 'data', array());
        return $this->parse_trades($trades, $market, $since, $limit);
    }

    public function fetch_balance($params = array ()) {
        yield $this->load_markets();
        // yield $this->load_accounts();
        $response = yield $this->profileGetWallets ($params);
        //
        //     {
        //         "success" => true,
        //         "data" => array(
        //             array(
        //                 "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" => array( "BTC" => "0.00000000020", "USD" => "0.00000147" ),
        //             ),
        //             array(
        //                 "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" => array(
        //                     array( "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/" ),
        //                     array( "protocol_name" => "ERC20", "protocol_id" => 5, "active" => true, "withdrawal_fee_const" => 1.2, "withdrawal_fee_percent" => 0, "block_explorer_url" => "https://etherscan.io/tx/" ),
        //                     array( "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" => array( "BTC" => "0.00013893", "USD" => "1" ),
        //             ),
        //         )
        //     }
        //
        $result = array( 'info' => $response );
        $balances = $this->safe_value($response, 'data', array());
        for ($i = 0; $i < count($balances); $i++) {
            $balance = $balances[$i];
            $code = $this->safe_currency_code($this->safe_string($balance, 'currency_id'));
            $account = $this->account();
            $account['free'] = $this->safe_float($balance, 'balance');
            $account['used'] = $this->safe_float($balance, 'frozen_balance');
            $result[$code] = $account;
        }
        return $this->parse_balance($result);
    }

    public function parse_order_status($status) {
        $statuses = array(
            'PROCESSING' => 'open',
            'PENDING' => 'open',
            'PARTIAL' => 'open',
            'FINISHED' => 'closed',
            'CANCELLED' => 'canceled',
        );
        return $this->safe_string($statuses, $status, $status);
    }

    public function parse_order($order, $market = null) {
        //
        // 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" => array(
        //             {
        //                 "$id" => 658745,
        //                 "buy_order_id" => 658745,
        //                 "sell_order_id" => 828680665,
        //                 "$price" => 0.012285,
        //                 "$amount" => 6.35,
        //                 "trade_type" => "SELL",
        //                 "$timestamp" => "1538737692"
        //             }
        //         ),
        //         // fetchClosedOrder only
        //         "$fees" => array(
        //             {
        //                 "$id" => 1234567,
        //                 "currency_id" => 1,
        //                 "$amount" => 0.00025,
        //                 "$timestamp" => "1548149238"
        //             }
        //         )
        //     }
        //
        $id = $this->safe_string($order, 'id');
        $status = $this->parse_order_status($this->safe_string($order, 'status'));
        $marketId = $this->safe_string_2($order, 'currency_pair_id', 'currency_pair_name');
        $symbol = $this->safe_symbol($marketId, $market, '_');
        $timestamp = $this->safe_timestamp($order, 'timestamp');
        $price = $this->safe_float($order, 'price');
        $amount = $this->safe_float($order, 'initial_amount');
        $filled = $this->safe_float($order, 'processed_amount');
        $remaining = null;
        $cost = null;
        if ($filled !== null) {
            if ($amount !== null) {
                $remaining = $amount - $filled;
                if ($this->options['parseOrderToPrecision']) {
                    $remaining = floatval($this->amount_to_precision($symbol, $remaining));
                }
                $remaining = max ($remaining, 0.0);
            }
            if ($price !== null) {
                if ($cost === null) {
                    $cost = $price * $filled;
                }
            }
        }
        $type = $this->safe_string($order, 'original_type');
        if (($type === 'BUY') || ($type === 'SELL')) {
            $type = null;
        }
        $side = $this->safe_string_lower($order, 'type');
        $rawTrades = $this->safe_value($order, 'trades');
        $trades = null;
        if ($rawTrades !== null) {
            $trades = $this->parse_trades($rawTrades, $market, null, null, array(
                'symbol' => $symbol,
                'order' => $id,
            ));
        }
        $stopPrice = $this->safe_float($order, 'trigger_price');
        $result = array(
            'info' => $order,
            'id' => $id,
            'clientOrderId' => null,
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'lastTradeTimestamp' => null,
            'symbol' => $symbol,
            'type' => $type,
            'timeInForce' => null,
            'postOnly' => null,
            'side' => $side,
            'price' => $price,
            'stopPrice' => $stopPrice,
            'amount' => $amount,
            'cost' => $cost,
            'average' => null,
            'filled' => $filled,
            'remaining' => $remaining,
            'status' => $status,
            'trades' => $trades,
        );
        $fees = $this->safe_value($order, 'fees');
        if ($fees === null) {
            $result['fee'] = null;
        } else {
            $numFees = is_array($fees) ? count($fees) : 0;
            if ($numFees > 0) {
                $result['fees'] = array();
                for ($i = 0; $i < count($fees); $i++) {
                    $feeCost = $this->safe_float($fees[$i], 'amount');
                    if ($feeCost !== null) {
                        $feeCurrencyId = $this->safe_string($fees[$i], 'currency_id');
                        $feeCurrencyCode = $this->safe_currency_code($feeCurrencyId);
                        $result['fees'][] = array(
                            'cost' => $feeCost,
                            'currency' => $feeCurrencyCode,
                        );
                    }
                }
            } else {
                $result['fee'] = null;
            }
        }
        return $result;
    }

    public function create_order($symbol, $type, $side, $amount, $price = null, $params = array ()) {
        if ($type === 'market') {
            throw new ExchangeError($this->id . ' createOrder allows limit orders only');
        }
        yield $this->load_markets();
        $market = $this->market($symbol);
        if ($type === 'limit') {
            $type = $side;
        }
        $request = array(
            'currencyPairId' => $market['id'],
            'type' => strtoupper($type), // 'BUY', 'SELL', 'STOP_LIMIT_BUY', 'STOP_LIMIT_SELL'
            'amount' => floatval($this->amount_to_precision($symbol, $amount)), // required
            'price' => floatval($this->price_to_precision($symbol, $price)), // required
            // 'trigger_price' => 123.45 // required for STOP_LIMIT_BUY or STOP_LIMIT_SELL
        );
        $response = yield $this->tradingPostOrdersCurrencyPairId (array_merge($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 = $this->safe_value($response, 'data', array());
        return $this->parse_order($data, $market);
    }

    public function fetch_order($id, $symbol = null, $params = array ()) {
        yield $this->load_markets();
        $request = array(
            'orderId' => $id,
        );
        $response = yield $this->tradingGetOrderOrderId (array_merge($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 = $this->safe_value($response, 'data', array());
        $market = null;
        if ($symbol !== null) {
            $market = $this->market($symbol);
        }
        return $this->parse_order($data, $market);
    }

    public function fetch_closed_order($id, $symbol = null, $params = array ()) {
        yield $this->load_markets();
        $request = array(
            'orderId' => $id,
        );
        $response = yield $this->reportsGetOrdersOrderId (array_merge($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" => array(
        //                 {
        //                     "$id" => 658745,
        //                     "buy_order_id" => 6587453,
        //                     "sell_order_id" => 6587459,
        //                     "price" => 0.012285,
        //                     "amount" => 6.35,
        //                     "trade_type" => "SELL",
        //                     "timestamp" => "1538737692"
        //                 }
        //             ),
        //             "fees" => array(
        //                 {
        //                     "$id" => 1234567,
        //                     "currency_id" => 1,
        //                     "amount" => 0.00025,
        //                     "timestamp" => "1548149238"
        //                 }
        //             )
        //         }
        //     }
        //
        $data = $this->safe_value($response, 'data', array());
        $market = null;
        if ($symbol !== null) {
            $market = $this->market($symbol);
        }
        return $this->parse_order($data, $market);
    }

    public function fetch_order_trades($id, $symbol = null, $since = null, $limit = null, $params = array ()) {
        $order = yield $this->fetch_closed_order($id, $symbol, $params);
        return $order['trades'];
    }

    public function fetch_open_orders($symbol = null, $since = null, $limit = null, $params = array ()) {
        yield $this->load_markets();
        $market = null;
        $method = 'tradingGetOrders';
        $request = array(
            // 'limit' => 100, // default 100
            // 'offset' => 100,
        );
        if ($symbol !== null) {
            $method = 'tradingGetOrdersCurrencyPairId';
            $market = $this->market($symbol);
            $request['currencyPairId'] = $market['id'];
        }
        if ($limit !== null) {
            $request['limit'] = $limit;
        }
        $response = yield $this->$method (array_merge($request, $params));
        //
        //     {
        //         "success" => true,
        //         "$data" => array(
        //             {
        //                 "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 = $this->safe_value($response, 'data', array());
        return $this->parse_orders($data, $market, $since, $limit);
    }

    public function cancel_order($id, $symbol = null, $params = array ()) {
        yield $this->load_markets();
        $request = array(
            'orderId' => $id,
        );
        $response = yield $this->tradingDeleteOrderOrderId (array_merge($request, $params));
        //
        //     {
        //         "success" => true,
        //         "$data" => {
        //             "put_into_processing_queue" => array(
        //                 {
        //                     "$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" => array(
        //                 {
        //                     "$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 = $this->safe_value($response, 'data', array());
        $acceptedOrders = $this->safe_value($data, 'put_into_processing_queue', array());
        $rejectedOrders = $this->safe_value($data, 'not_put_into_processing_queue', array());
        $numAcceptedOrders = is_array($acceptedOrders) ? count($acceptedOrders) : 0;
        $numRejectedOrders = is_array($rejectedOrders) ? count($rejectedOrders) : 0;
        if ($numAcceptedOrders < 1) {
            if ($numRejectedOrders < 1) {
                throw new OrderNotFound($this->id . ' cancelOrder received an empty $response => ' . $this->json($response));
            } else {
                return $this->parse_order($rejectedOrders[0]);
            }
        } else {
            if ($numRejectedOrders < 1) {
                return $this->parse_order($acceptedOrders[0]);
            } else {
                throw new OrderNotFound($this->id . ' cancelOrder received an empty $response => ' . $this->json($response));
            }
        }
    }

    public function cancel_all_orders($symbol = null, $params = array ()) {
        yield $this->load_markets();
        $request = array();
        $method = 'tradingDeleteOrders';
        if ($symbol !== null) {
            $market = $this->market($symbol);
            $request['currencyPairId'] = $market['id'];
            $method = 'tradingDeleteOrdersCurrencyPairId';
        }
        $response = yield $this->$method (array_merge($request, $params));
        //
        //     {
        //         "success":true,
        //         "data":{
        //             "put_into_processing_queue":array(),
        //             "not_put_into_processing_queue":array(),
        //             "message":"Orders operations are handled in processing queue, therefore cancelling is not immediate."
        //         }
        //     }
        //
        return $response;
    }

    public function fetch_my_trades($symbol = null, $since = null, $limit = null, $params = array ()) {
        if ($symbol === null) {
            throw new ArgumentsRequired($this->id . ' fetchMyTrades() requires a $symbol argument');
        }
        yield $this->load_markets();
        $market = $this->market($symbol);
        $request = array(
            '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 !== null) {
            $request['timeStart'] = $this->iso8601($since);
        }
        if ($limit !== null) {
            $request['limit'] = $limit;
        }
        $response = yield $this->reportsGetTradesCurrencyPairId (array_merge($request, $params));
        //
        //     {
        //         "success" => true,
        //         "data" => array(
        //             {
        //                 "id" => 658745,
        //                 "buy_order_id" => 6587453,
        //                 "sell_order_id" => 6587459,
        //                 "price" => 0.012285,
        //                 "amount" => 6.35,
        //                 "trade_type" => "SELL",
        //                 "timestamp" => "1538737692"
        //             }
        //         )
        //     }
        //
        $trades = $this->safe_value($response, 'data', array());
        return $this->parse_trades($trades, $market, $since, $limit);
    }

    public function create_deposit_address($code, $params = array ()) {
        yield $this->load_markets();
        $currency = $this->currency($code);
        $request = array(
            '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 = yield $this->profilePostWalletsCurrencyId (array_merge($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" => array(
        //                 "$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" => array(
        //                 {
        //                     "$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" => array( "BTC" => 0.000001 ),
        //             "protocol_specific_settings" => array(
        //                 {
        //                     "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 = $this->safe_value($response, 'data', array());
        $depositAddress = $this->safe_value($data, 'deposit_address', array());
        $address = $this->safe_string($depositAddress, 'address');
        $tag = $this->safe_string($depositAddress, 'additional_address_parameter');
        $this->check_address($address);
        return array(
            'currency' => $code,
            'address' => $address,
            'tag' => $tag,
            'info' => $response,
        );
    }

    public function fetch_deposit_address($code, $params = array ()) {
        yield $this->load_markets();
        $balance = yield $this->fetch_balance();
        $wallets = $this->safe_value($balance['info'], 'data', array());
        $walletsByCurrencyId = $this->index_by($wallets, 'currency_id');
        $currency = $this->currency($code);
        $wallet = $this->safe_value($walletsByCurrencyId, $currency['id']);
        if ($wallet === null) {
            throw new ExchangeError($this->id . ' fetchDepositAddress() could not find the $wallet id for $currency $code ' . $code . ', try to call createDepositAddress() first');
        }
        $walletId = $this->safe_integer($wallet, 'id');
        if ($walletId === null) {
            throw new ExchangeError($this->id . ' fetchDepositAddress() could not find the $wallet id for $currency $code ' . $code . ', try to call createDepositAddress() first');
        }
        $request = array(
            'walletId' => $walletId,
        );
        $response = yield $this->profileGetWalletsWalletId (array_merge($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" => array(
        //                 "$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" => array(
        //                 {
        //                     "$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" => array( "BTC" => 0.000001 ),
        //             "protocol_specific_settings" => array(
        //                 {
        //                     "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 = $this->safe_value($response, 'data', array());
        $depositAddress = $this->safe_value($data, 'deposit_address', array());
        $address = $this->safe_string($depositAddress, 'address');
        $tag = $this->safe_string($depositAddress, 'additional_address_parameter');
        $this->check_address($address);
        return array(
            'currency' => $code,
            'address' => $address,
            'tag' => $tag,
            'info' => $response,
        );
    }

    public function sign($path, $api = 'public', $method = 'GET', $params = array (), $headers = null, $body = null) {
        $url = $this->urls['api'] . '/' . $api . '/' . $this->implode_params($path, $params);
        $query = $this->omit($params, $this->extract_params($path));
        if ($api === 'public') {
            if ($query) {
                $url .= '?' . $this->urlencode($query);
            }
        } else {
            $this->check_required_credentials();
            $headers = array(
                'Authorization' => 'Bearer ' . $this->token,
            );
            if ($method === 'GET' || $method === 'DELETE') {
                if ($query) {
                    $url .= '?' . $this->urlencode($query);
                }
            } else {
                $body = $this->json($query);
                if ($query) {
                    $headers['Content-Type'] = 'application/json';
                }
            }
        }
        return array( 'url' => $url, 'method' => $method, 'body' => $body, 'headers' => $headers );
    }

    public function parse_transaction_status($status) {
        $statuses = array(
            '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 $this->safe_string($statuses, $status, $status);
    }

    public function parse_transaction($transaction, $currency = null) {
        //
        // 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"
        //     }
        //
        // 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 = $this->safe_string($transaction, 'id');
        $withdrawalAddress = $this->safe_value($transaction, 'withdrawal_address', array());
        $address = $this->safe_string($withdrawalAddress, 'address');
        $tag = $this->safe_string($withdrawalAddress, 'additional_address_parameter');
        $currencyId = $this->safe_string($transaction, 'currency_id');
        $code = null;
        if (is_array($this->currencies_by_id) && array_key_exists($currencyId, $this->currencies_by_id)) {
            $currency = $this->currencies_by_id[$currencyId];
        } else {
            $code = $this->common_currency_code($this->safe_string($transaction, 'currency_code'));
        }
        if (($code === null) && ($currency !== null)) {
            $code = $currency['code'];
        }
        $type = (is_array($transaction) && array_key_exists('deposit_status_id', $transaction)) ? 'deposit' : 'withdrawal';
        $amount = $this->safe_float($transaction, 'amount');
        $status = $this->parse_transaction_status($this->safe_string_lower($transaction, 'status'));
        $timestamp = $this->safe_timestamp_2($transaction, 'timestamp', 'created_ts');
        $updated = $this->safe_timestamp($transaction, 'updated_ts');
        $txid = $this->safe_string($transaction, 'txid');
        $fee = null;
        $feeCost = $this->safe_float($transaction, 'fee');
        if ($feeCost !== null) {
            $feeCurrencyId = $this->safe_string($transaction, 'fee_currency_id', 'deposit_fee_currency_id');
            $feeCurrencyCode = $this->safe_currency_code($feeCurrencyId);
            $fee = array(
                'cost' => $feeCost,
                'currency' => $feeCurrencyCode,
            );
        }
        return array(
            'info' => $transaction,
            'id' => $id,
            'txid' => $txid,
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'addressFrom' => null,
            'address' => $address,
            'addressTo' => $address,
            'tagFrom' => null,
            'tag' => $tag,
            'tagTo' => $tag,
            'type' => $type,
            'amount' => $amount,
            'currency' => $code,
            'status' => $status,
            'updated' => $updated,
            'fee' => $fee,
        );
    }

    public function fetch_deposits($code = null, $since = null, $limit = null, $params = array ()) {
        yield $this->load_markets();
        $currency = null;
        $request = array();
        if ($code !== null) {
            $currency = $this->currency($code);
            $request['currencyId'] = $currency['id'];
        }
        if ($limit !== null) {
            $request['limit'] = $limit;
        }
        if ($since !== null) {
            $request['timeStart'] = $since;
        }
        $response = yield $this->profileGetDeposits (array_merge($request, $params));
        //
        //     {
        //         "success" => true,
        //         "data" => array(
        //             {
        //                 "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 = $this->safe_value($response, 'data', array());
        return $this->parse_transactions($deposits, $code, $since, $limit);
    }

    public function fetch_withdrawals($code = null, $since = null, $limit = null, $params = array ()) {
        yield $this->load_markets();
        $currency = null;
        $request = array();
        if ($code !== null) {
            $currency = $this->currency($code);
            $request['currencyId'] = $currency['id'];
        }
        if ($limit !== null) {
            $request['limit'] = $limit;
        }
        if ($since !== null) {
            $request['timeStart'] = $since;
        }
        $response = yield $this->profileGetWithdrawals (array_merge($request, $params));
        //
        //     {
        //         "success" => true,
        //         "data" => array(
        //             {
        //                 "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" => array(
        //                     "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 = $this->safe_value($response, 'data', array());
        return $this->parse_transactions($withdrawals, $code, $since, $limit);
    }

    public function withdraw($code, $amount, $address, $tag = null, $params = array ()) {
        $this->check_address($address);
        yield $this->load_markets();
        $currency = $this->currency($code);
        $request = array(
            'currency_id' => $currency['id'],
            'amount' => floatval($this->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 !== null) {
            $request['additional_address_parameter'] = $tag;
        }
        $response = yield $this->profilePostWithdraw (array_merge($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 = $this->safe_value($response, 'data', array());
        return $this->parse_transaction($data, $currency);
    }

    public function fetch_funding_fees($codes = null, $params = array ()) {
        $response = yield $this->publicGetCurrencies ($params);
        //
        //     {
        //         "success" => true,
        //         "$data" => array(
        //             {
        //                 "$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" => array(
        //                     {
        //                         "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 = $this->safe_value($response, 'data', array());
        $withdrawFees = array();
        $depositFees = array();
        for ($i = 0; $i < count($data); $i++) {
            $id = $this->safe_string($data[$i], 'id');
            $code = $this->safe_currency_code($id);
            $withdrawFees[$code] = $this->safe_float($data[$i], 'withdrawal_fee_const');
            $depositFees[$code] = $this->safe_float($data[$i], 'deposit_fee_const');
        }
        return array(
            'withdraw' => $withdrawFees,
            'deposit' => $depositFees,
            'info' => $response,
        );
    }

    public function handle_errors($httpCode, $reason, $url, $method, $headers, $body, $response, $requestHeaders, $requestBody) {
        if ($response === null) {
            return; // fallback to default error handler
        }
        //
        //     array("$success":false,"$message":"Wrong parameters","errors":array("candleType":["Invalid Candle Type!"]))
        //     array("$success":false,"$message":"Wrong parameters","errors":array("time":["timeStart or timeEnd is less then 1"]))
        //     array("$success":false,"$message":"Not enough  ETH")
        //
        $success = $this->safe_value($response, 'success', false);
        if (!$success) {
            $message = $this->safe_string($response, 'message');
            $feedback = $this->id . ' ' . $body;
            $this->throw_exactly_matched_exception($this->exceptions['exact'], $message, $feedback);
            $this->throw_broadly_matched_exception($this->exceptions['broad'], $message, $feedback);
            throw new ExchangeError($feedback); // unknown $message
        }
    }
}
