<?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\async\abstract\onetrading as Exchange;
use ccxt\ExchangeError;
use ccxt\ArgumentsRequired;
use ccxt\BadRequest;
use ccxt\NotSupported;
use ccxt\Precise;
use \React\Async;
use \React\Promise\PromiseInterface;

class onetrading extends Exchange {

    public function describe(): mixed {
        return $this->deep_extend(parent::describe(), array(
            'id' => 'onetrading',
            'name' => 'One Trading',
            'countries' => array( 'AT' ), // Austria
            'rateLimit' => 300,
            'version' => 'v1',
            'pro' => true,
            // new metainfo interface
            'has' => array(
                'CORS' => null,
                'spot' => true,
                'margin' => false,
                'swap' => false,
                'future' => false,
                'option' => false,
                'addMargin' => false,
                'borrowCrossMargin' => false,
                'borrowIsolatedMargin' => false,
                'borrowMargin' => false,
                'cancelAllOrders' => true,
                'cancelOrder' => true,
                'cancelOrders' => true,
                'closeAllPositions' => false,
                'closePosition' => false,
                'createDepositAddress' => false,
                'createOrder' => true,
                'createReduceOnlyOrder' => false,
                'createStopLimitOrder' => true,
                'createStopMarketOrder' => false,
                'createStopOrder' => true,
                'fetchAccounts' => false,
                'fetchAllGreeks' => false,
                'fetchBalance' => true,
                'fetchBorrowInterest' => false,
                'fetchBorrowRate' => false,
                'fetchBorrowRateHistories' => false,
                'fetchBorrowRateHistory' => false,
                'fetchBorrowRates' => false,
                'fetchBorrowRatesPerSymbol' => false,
                'fetchClosedOrders' => true,
                'fetchCrossBorrowRate' => false,
                'fetchCrossBorrowRates' => false,
                'fetchCurrencies' => true,
                'fetchDeposit' => false,
                'fetchDepositAddress' => false,
                'fetchDepositAddresses' => false,
                'fetchDepositAddressesByNetwork' => false,
                'fetchDeposits' => false,
                'fetchDepositsWithdrawals' => false,
                'fetchFundingHistory' => false,
                'fetchFundingInterval' => false,
                'fetchFundingIntervals' => false,
                'fetchFundingRate' => false,
                'fetchFundingRateHistory' => false,
                'fetchFundingRates' => false,
                'fetchGreeks' => false,
                'fetchIndexOHLCV' => false,
                'fetchIsolatedBorrowRate' => false,
                'fetchIsolatedBorrowRates' => false,
                'fetchIsolatedPositions' => false,
                'fetchLedger' => false,
                'fetchLeverage' => false,
                'fetchLeverages' => false,
                'fetchLeverageTiers' => false,
                'fetchLiquidations' => false,
                'fetchLongShortRatio' => false,
                'fetchLongShortRatioHistory' => false,
                'fetchMarginAdjustmentHistory' => false,
                'fetchMarginMode' => false,
                'fetchMarginModes' => false,
                'fetchMarketLeverageTiers' => false,
                'fetchMarkets' => true,
                'fetchMarkOHLCV' => false,
                'fetchMarkPrice' => false,
                'fetchMarkPrices' => false,
                'fetchMyLiquidations' => false,
                'fetchMySettlementHistory' => false,
                'fetchMyTrades' => true,
                'fetchOHLCV' => true,
                'fetchOpenInterest' => false,
                'fetchOpenInterestHistory' => false,
                'fetchOpenInterests' => false,
                'fetchOpenOrders' => true,
                'fetchOption' => false,
                'fetchOptionChain' => false,
                'fetchOrder' => true,
                'fetchOrderBook' => true,
                'fetchOrders' => false,
                'fetchOrderTrades' => true,
                'fetchPosition' => false,
                'fetchPositionHistory' => false,
                'fetchPositionMode' => false,
                'fetchPositions' => false,
                'fetchPositionsForSymbol' => false,
                'fetchPositionsHistory' => false,
                'fetchPositionsRisk' => false,
                'fetchPremiumIndexOHLCV' => false,
                'fetchSettlementHistory' => false,
                'fetchTicker' => true,
                'fetchTickers' => true,
                'fetchTime' => true,
                'fetchTrades' => false,
                'fetchTradingFee' => false,
                'fetchTradingFees' => true,
                'fetchTransactionFee' => false,
                'fetchTransactionFees' => false,
                'fetchTransactions' => false,
                'fetchTransfer' => false,
                'fetchTransfers' => false,
                'fetchUnderlyingAssets' => false,
                'fetchVolatilityHistory' => false,
                'fetchWithdrawal' => false,
                'fetchWithdrawals' => false,
                'reduceMargin' => false,
                'repayCrossMargin' => false,
                'repayIsolatedMargin' => false,
                'setLeverage' => false,
                'setMargin' => false,
                'setMarginMode' => false,
                'setPositionMode' => false,
                'transfer' => false,
                'withdraw' => false,
            ),
            'timeframes' => array(
                '1m' => '1/MINUTES',
                '5m' => '5/MINUTES',
                '15m' => '15/MINUTES',
                '30m' => '30/MINUTES',
                '1h' => '1/HOURS',
                '4h' => '4/HOURS',
                '1d' => '1/DAYS',
                '1w' => '1/WEEKS',
                '1M' => '1/MONTHS',
            ),
            'urls' => array(
                'logo' => 'https://github.com/ccxt/ccxt/assets/43336371/bdbc26fd-02f2-4ca7-9f1e-17333690bb1c',
                'api' => array(
                    'public' => 'https://api.onetrading.com/fast',
                    'private' => 'https://api.onetrading.com/fast',
                ),
                'www' => 'https://onetrading.com/',
                'doc' => array(
                    'https://docs.onetrading.com',
                ),
                'fees' => 'https://onetrading.com/fees',
            ),
            'api' => array(
                'public' => array(
                    'get' => array(
                        'currencies',
                        'candlesticks/{instrument_code}',
                        'fees',
                        'instruments',
                        'order-book/{instrument_code}',
                        'market-ticker',
                        'market-ticker/{instrument_code}',
                        'time',
                    ),
                ),
                'private' => array(
                    'get' => array(
                        'account/balances',
                        'account/fees',
                        'account/orders',
                        'account/orders/{order_id}',
                        'account/orders/{order_id}/trades',
                        'account/trades',
                        'account/trades/{trade_id}',
                    ),
                    'post' => array(
                        'account/orders',
                    ),
                    'delete' => array(
                        'account/orders',
                        'account/orders/{order_id}',
                        'account/orders/client/{client_id}',
                    ),
                ),
            ),
            'fees' => array(
                'trading' => array(
                    'tierBased' => true,
                    'percentage' => true,
                    'taker' => $this->parse_number('0.0015'),
                    'maker' => $this->parse_number('0.001'),
                    'tiers' => array(
                        // volume in BTC
                        array(
                            'taker' => array(
                                array( $this->parse_number('0'), $this->parse_number('0.0015') ),
                                array( $this->parse_number('100'), $this->parse_number('0.0013') ),
                                array( $this->parse_number('250'), $this->parse_number('0.0013') ),
                                array( $this->parse_number('1000'), $this->parse_number('0.001') ),
                                array( $this->parse_number('5000'), $this->parse_number('0.0009') ),
                                array( $this->parse_number('10000'), $this->parse_number('0.00075') ),
                                array( $this->parse_number('20000'), $this->parse_number('0.00065') ),
                            ),
                            'maker' => array(
                                array( $this->parse_number('0'), $this->parse_number('0.001') ),
                                array( $this->parse_number('100'), $this->parse_number('0.001') ),
                                array( $this->parse_number('250'), $this->parse_number('0.0009') ),
                                array( $this->parse_number('1000'), $this->parse_number('0.00075') ),
                                array( $this->parse_number('5000'), $this->parse_number('0.0006') ),
                                array( $this->parse_number('10000'), $this->parse_number('0.0005') ),
                                array( $this->parse_number('20000'), $this->parse_number('0.0005') ),
                            ),
                        ),
                    ),
                ),
            ),
            'requiredCredentials' => array(
                'apiKey' => true,
                'secret' => false,
            ),
            'precisionMode' => TICK_SIZE,
            'exceptions' => array(
                'exact' => array(
                    'INVALID_CLIENT_UUID' => '\\ccxt\\InvalidOrder',
                    'ORDER_NOT_FOUND' => '\\ccxt\\OrderNotFound',
                    'ONLY_ONE_ERC20_ADDRESS_ALLOWED' => '\\ccxt\\InvalidAddress',
                    'DEPOSIT_ADDRESS_NOT_USED' => '\\ccxt\\InvalidAddress',
                    'INVALID_CREDENTIALS' => '\\ccxt\\AuthenticationError',
                    'MISSING_CREDENTIALS' => '\\ccxt\\AuthenticationError',
                    'INVALID_APIKEY' => '\\ccxt\\AuthenticationError',
                    'INVALID_SCOPES' => '\\ccxt\\AuthenticationError',
                    'INVALID_SUBJECT' => '\\ccxt\\AuthenticationError',
                    'INVALID_ISSUER' => '\\ccxt\\AuthenticationError',
                    'INVALID_AUDIENCE' => '\\ccxt\\AuthenticationError',
                    'INVALID_DEVICE_ID' => '\\ccxt\\AuthenticationError',
                    'INVALID_IP_RESTRICTION' => '\\ccxt\\AuthenticationError',
                    'APIKEY_REVOKED' => '\\ccxt\\AuthenticationError',
                    'APIKEY_EXPIRED' => '\\ccxt\\AuthenticationError',
                    'SYNCHRONIZER_TOKEN_MISMATCH' => '\\ccxt\\AuthenticationError',
                    'SESSION_EXPIRED' => '\\ccxt\\AuthenticationError',
                    'INTERNAL_ERROR' => '\\ccxt\\AuthenticationError',
                    'CLIENT_IP_BLOCKED' => '\\ccxt\\PermissionDenied',
                    'MISSING_PERMISSION' => '\\ccxt\\PermissionDenied',
                    'ILLEGAL_CHARS' => '\\ccxt\\BadRequest',
                    'UNSUPPORTED_MEDIA_TYPE' => '\\ccxt\\BadRequest',
                    'ACCOUNT_HISTORY_TIME_RANGE_TOO_BIG' => '\\ccxt\\BadRequest',
                    'CANDLESTICKS_TIME_RANGE_TOO_BIG' => '\\ccxt\\BadRequest',
                    'INVALID_INSTRUMENT_CODE' => '\\ccxt\\BadRequest',
                    'INVALID_ORDER_TYPE' => '\\ccxt\\BadRequest',
                    'INVALID_UNIT' => '\\ccxt\\BadRequest',
                    'INVALID_PERIOD' => '\\ccxt\\BadRequest',
                    'INVALID_TIME' => '\\ccxt\\BadRequest',
                    'INVALID_DATE' => '\\ccxt\\BadRequest',
                    'INVALID_CURRENCY' => '\\ccxt\\BadRequest',
                    'INVALID_AMOUNT' => '\\ccxt\\BadRequest',
                    'INVALID_PRICE' => '\\ccxt\\BadRequest',
                    'INVALID_LIMIT' => '\\ccxt\\BadRequest',
                    'INVALID_QUERY' => '\\ccxt\\BadRequest',
                    'INVALID_CURSOR' => '\\ccxt\\BadRequest',
                    'INVALID_ACCOUNT_ID' => '\\ccxt\\BadRequest',
                    'INVALID_SIDE' => '\\ccxt\\InvalidOrder',
                    'INVALID_ACCOUNT_HISTORY_FROM_TIME' => '\\ccxt\\BadRequest',
                    'INVALID_ACCOUNT_HISTORY_MAX_PAGE_SIZE' => '\\ccxt\\BadRequest',
                    'INVALID_ACCOUNT_HISTORY_TIME_PERIOD' => '\\ccxt\\BadRequest',
                    'INVALID_ACCOUNT_HISTORY_TO_TIME' => '\\ccxt\\BadRequest',
                    'INVALID_CANDLESTICKS_GRANULARITY' => '\\ccxt\\BadRequest',
                    'INVALID_CANDLESTICKS_UNIT' => '\\ccxt\\BadRequest',
                    'INVALID_ORDER_BOOK_DEPTH' => '\\ccxt\\BadRequest',
                    'INVALID_ORDER_BOOK_LEVEL' => '\\ccxt\\BadRequest',
                    'INVALID_PAGE_CURSOR' => '\\ccxt\\BadRequest',
                    'INVALID_TIME_RANGE' => '\\ccxt\\BadRequest',
                    'INVALID_TRADE_ID' => '\\ccxt\\BadRequest',
                    'INVALID_UI_ACCOUNT_SETTINGS' => '\\ccxt\\BadRequest',
                    'NEGATIVE_AMOUNT' => '\\ccxt\\InvalidOrder',
                    'NEGATIVE_PRICE' => '\\ccxt\\InvalidOrder',
                    'MIN_SIZE_NOT_SATISFIED' => '\\ccxt\\InvalidOrder',
                    'BAD_AMOUNT_PRECISION' => '\\ccxt\\InvalidOrder',
                    'BAD_PRICE_PRECISION' => '\\ccxt\\InvalidOrder',
                    'BAD_TRIGGER_PRICE_PRECISION' => '\\ccxt\\InvalidOrder',
                    'MAX_OPEN_ORDERS_EXCEEDED' => '\\ccxt\\BadRequest',
                    'MISSING_PRICE' => '\\ccxt\\InvalidOrder',
                    'MISSING_ORDER_TYPE' => '\\ccxt\\InvalidOrder',
                    'MISSING_SIDE' => '\\ccxt\\InvalidOrder',
                    'MISSING_CANDLESTICKS_PERIOD_PARAM' => '\\ccxt\\ArgumentsRequired',
                    'MISSING_CANDLESTICKS_UNIT_PARAM' => '\\ccxt\\ArgumentsRequired',
                    'MISSING_FROM_PARAM' => '\\ccxt\\ArgumentsRequired',
                    'MISSING_INSTRUMENT_CODE' => '\\ccxt\\ArgumentsRequired',
                    'MISSING_ORDER_ID' => '\\ccxt\\InvalidOrder',
                    'MISSING_TO_PARAM' => '\\ccxt\\ArgumentsRequired',
                    'MISSING_TRADE_ID' => '\\ccxt\\ArgumentsRequired',
                    'INVALID_ORDER_ID' => '\\ccxt\\OrderNotFound',
                    'NOT_FOUND' => '\\ccxt\\OrderNotFound',
                    'INSUFFICIENT_LIQUIDITY' => '\\ccxt\\InsufficientFunds',
                    'INSUFFICIENT_FUNDS' => '\\ccxt\\InsufficientFunds',
                    'NO_TRADING' => '\\ccxt\\ExchangeNotAvailable',
                    'SERVICE_UNAVAILABLE' => '\\ccxt\\ExchangeNotAvailable',
                    'GATEWAY_TIMEOUT' => '\\ccxt\\ExchangeNotAvailable',
                    'RATELIMIT' => '\\ccxt\\DDoSProtection',
                    'CF_RATELIMIT' => '\\ccxt\\DDoSProtection',
                    'INTERNAL_SERVER_ERROR' => '\\ccxt\\ExchangeError',
                ),
                'broad' => array(
                    'Order not found.' => '\\ccxt\\OrderNotFound',
                ),
            ),
            'commonCurrencies' => array(
                'MIOTA' => 'IOTA', // https://github.com/ccxt/ccxt/issues/7487
            ),
            // exchange-specific options
            'options' => array(
                'fetchTradingFees' => array(
                    'method' => 'fetchPrivateTradingFees', // or 'fetchPublicTradingFees'
                ),
                'fiat' => array( 'EUR', 'CHF' ),
            ),
            'features' => array(
                'spot' => array(
                    'sandbox' => false,
                    'createOrder' => array(
                        'marginMode' => false,
                        'triggerPrice' => false,
                        'triggerDirection' => false,
                        'triggerPriceType' => null,
                        'stopLossPrice' => false,
                        'takeProfitPrice' => false,
                        'attachedStopLossTakeProfit' => null,
                        'timeInForce' => array(
                            'IOC' => true,
                            'FOK' => true,
                            'PO' => true,
                            'GTD' => false,
                        ),
                        'hedged' => false,
                        'trailing' => false,
                        'leverage' => false,
                        'marketBuyByCost' => false,
                        'marketBuyRequiresPrice' => false,
                        'selfTradePrevention' => false,
                        'iceberg' => false,
                    ),
                    'createOrders' => null,
                    'fetchMyTrades' => array(
                        'marginMode' => false,
                        'limit' => 100,
                        'daysBack' => 100000, // todo
                        'untilDays' => 100000, // todo
                        'symbolRequired' => false,
                    ),
                    'fetchOrder' => array(
                        'marginMode' => false,
                        'trigger' => false,
                        'trailing' => false,
                        'symbolRequired' => false,
                    ),
                    'fetchOpenOrders' => array(
                        'marginMode' => false,
                        'limit' => 100,
                        'trigger' => false,
                        'trailing' => false,
                        'symbolRequired' => false,
                    ),
                    'fetchOrders' => null, // todo
                    'fetchClosedOrders' => array(
                        'marginMode' => false,
                        'limit' => 100,
                        'daysBack' => 100000, // todo
                        'daysBackCanceled' => 1 / 12, // todo
                        'untilDays' => 100000, // todo
                        'trigger' => false,
                        'trailing' => false,
                        'symbolRequired' => false,
                    ),
                    'fetchOHLCV' => array(
                        'limit' => 5000,
                    ),
                ),
                'swap' => array(
                    'linear' => null,
                    'inverse' => null,
                ),
                'future' => array(
                    'linear' => null,
                    'inverse' => null,
                ),
            ),
        ));
    }

    public function fetch_time($params = array ()): PromiseInterface {
        return Async\async(function () use ($params) {
            /**
             * fetches the current integer timestamp in milliseconds from the exchange server
             *
             * @see https://docs.onetrading.com/#time
             *
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @return {int} the current integer timestamp in milliseconds from the exchange server
             */
            $response = Async\await($this->publicGetTime ($params));
            //
            //     {
            //         "iso" => "2020-07-10T05:17:26.716Z",
            //         "epoch_millis" => 1594358246716,
            //     }
            //
            return $this->safe_integer($response, 'epoch_millis');
        }) ();
    }

    public function fetch_currencies($params = array ()): PromiseInterface {
        return Async\async(function () use ($params) {
            /**
             * fetches all available currencies on an exchange
             *
             * @see https://docs.onetrading.com/#currencies
             *
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @return {array} an associative dictionary of currencies
             */
            $response = Async\await($this->publicGetCurrencies ($params));
            //
            //     array(
            //         array(
            //             "code" => "USDT",
            //             "precision" => 6,
            //             "unified_cryptoasset_id" => 825,
            //             "name" => "Tether USDt",
            //             "collateral_percentage" => 0
            //         ),
            //     )
            //
            $result = array();
            for ($i = 0; $i < count($response); $i++) {
                $currency = $response[$i];
                $id = $this->safe_string($currency, 'code');
                $code = $this->safe_currency_code($id);
                $result[$code] = $this->safe_currency_structure(array(
                    'id' => $id,
                    'code' => $code,
                    'name' => $this->safe_string($currency, 'name'),
                    'info' => $currency,
                    'active' => null,
                    'fee' => null,
                    'precision' => $this->parse_number($this->parse_precision($this->safe_string($currency, 'precision'))),
                    'withdraw' => null,
                    'deposit' => null,
                    'limits' => array(
                        'amount' => array( 'min' => null, 'max' => null ),
                        'withdraw' => array( 'min' => null, 'max' => null ),
                    ),
                    'networks' => array(),
                ));
            }
            return $result;
        }) ();
    }

    public function fetch_markets($params = array ()): PromiseInterface {
        return Async\async(function () use ($params) {
            /**
             * retrieves data on all markets for onetrading
             *
             * @see https://docs.onetrading.com/#instruments
             *
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @return {array[]} an array of objects representing market data
             */
            $response = Async\await($this->publicGetInstruments ($params));
            //
            //     array(
            //         {
            //             "state" => "ACTIVE",
            //             "base" => array( code => "ETH", precision => 8 ),
            //             "quote" => array( code => "CHF", precision => 2 ),
            //             "amount_precision" => 4,
            //             "market_precision" => 2,
            //             "min_size" => "10.0"
            //         }
            //     )
            //
            return $this->parse_markets($response);
        }) ();
    }

    public function parse_market(array $market): array {
        //
        //   {
        //      "base":array(
        //         "code":"BTC",
        //         "precision":"5"
        //      ),
        //      "quote":array(
        //         "code":"USDC",
        //         "precision":"2"
        //      ),
        //      "amount_precision":"5",
        //      "market_precision":"2",
        //      "min_size":"10.0",
        //      "min_price":"1000",
        //      "max_price":"10000000",
        //      "id":"BTC_USDC",
        //      "type":"SPOT",
        //      "state":"ACTIVE"
        //   }
        //
        //
        //  {
        //      "base" => array(
        //          "code" => "BTC",
        //          "precision" => 5
        //      ),
        //      "quote" => array(
        //          "code" => "EUR",
        //          "precision" => 2
        //      ),
        //      "amount_precision" => 5,
        //      "market_precision" => 2,
        //      "min_size" => "10.0",
        //      "min_price" => "1000",
        //      "max_price" => "10000000",
        //      "id" => "BTC_EUR_P",
        //      "type" => "PERP",
        //      "state" => "ACTIVE"
        //  }
        //
        $baseAsset = $this->safe_dict($market, 'base', array());
        $quoteAsset = $this->safe_dict($market, 'quote', array());
        $baseId = $this->safe_string($baseAsset, 'code');
        $quoteId = $this->safe_string($quoteAsset, 'code');
        $id = $this->safe_string($market, 'id');
        $base = $this->safe_currency_code($baseId);
        $quote = $this->safe_currency_code($quoteId);
        $state = $this->safe_string($market, 'state');
        $type = $this->safe_string($market, 'type');
        $isPerp = $type === 'PERP';
        $symbol = $base . '/' . $quote;
        if ($isPerp) {
            $symbol = $symbol . ':' . $quote;
        }
        return array(
            'id' => $id,
            'symbol' => $symbol,
            'base' => $base,
            'quote' => $quote,
            'settle' => $isPerp ? $quote : null,
            'baseId' => $baseId,
            'quoteId' => $quoteId,
            'settleId' => $isPerp ? $quoteId : null,
            'type' => $isPerp ? 'swap' : 'spot',
            'spot' => !$isPerp,
            'margin' => false,
            'swap' => $isPerp,
            'future' => false,
            'option' => false,
            'active' => ($state === 'ACTIVE'),
            'contract' => $isPerp,
            'linear' => $isPerp ? true : null,
            'inverse' => $isPerp ? false : null,
            'contractSize' => $isPerp ? $this->parse_number('1') : null,
            'expiry' => null,
            'expiryDatetime' => null,
            'strike' => null,
            'optionType' => null,
            'precision' => array(
                'amount' => $this->parse_number($this->parse_precision($this->safe_string($market, 'amount_precision'))),
                'price' => $this->parse_number($this->parse_precision($this->safe_string($market, 'market_precision'))),
            ),
            'limits' => array(
                'leverage' => array(
                    'min' => null,
                    'max' => null,
                ),
                'amount' => array(
                    'min' => null,
                    'max' => null,
                ),
                'price' => array(
                    'min' => null,
                    'max' => null,
                ),
                'cost' => array(
                    'min' => $this->safe_number($market, 'min_size'),
                    'max' => null,
                ),
            ),
            'created' => null,
            'info' => $market,
        );
    }

    public function fetch_trading_fees($params = array ()): PromiseInterface {
        return Async\async(function () use ($params) {
            /**
             * fetch the trading fees for multiple markets
             *
             * @see https://docs.onetrading.com/#fee-groups
             * @see https://docs.onetrading.com/#fees
             *
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @param {string} [$params->method] fetchPrivateTradingFees or fetchPublicTradingFees
             * @return {array} a dictionary of ~@link https://docs.ccxt.com/#/?id=fee-structure fee structures~ indexed by market symbols
             */
            $method = $this->safe_string($params, 'method');
            $params = $this->omit($params, 'method');
            if ($method === null) {
                $options = $this->safe_value($this->options, 'fetchTradingFees', array());
                $method = $this->safe_string($options, 'method', 'fetchPrivateTradingFees');
            }
            if ($method === 'fetchPrivateTradingFees') {
                return Async\await($this->fetch_private_trading_fees($params));
            } elseif ($method === 'fetchPublicTradingFees') {
                return Async\await($this->fetch_public_trading_fees($params));
            } else {
                throw new NotSupported($this->id . ' fetchTradingFees() does not support ' . $method . ', fetchPrivateTradingFees and fetchPublicTradingFees are supported');
            }
        }) ();
    }

    public function fetch_public_trading_fees($params = array ()) {
        return Async\async(function () use ($params) {
            Async\await($this->load_markets());
            $response = Async\await($this->publicGetFees ($params));
            //
            // array(
            //     array(
            //         'fee_group_id' => 'SPOT',
            //         'display_text' => 'The fee plan for spot trading.',
            //         'volume_currency' => 'EUR',
            //         'fee_tiers' => array(
            //             array(
            //                 'volume' => '0',
            //                 'fee_group_id' => 'SPOT',
            //                 'maker_fee' => '0.1000',
            //                 'taker_fee' => '0.2000',
            //             ),
            //             array(
            //                 'volume' => '10000',
            //                 'fee_group_id' => 'SPOT',
            //                 'maker_fee' => '0.0400',
            //                 'taker_fee' => '0.0800',
            //             ),
            //         ),
            //     ),
            //     array(
            //         'fee_group_id' => 'FUTURES',
            //         'display_text' => 'The fee plan for futures trading.',
            //         'volume_currency' => 'EUR',
            //         'fee_tiers' => array(
            //             array(
            //                 'volume' => '0',
            //                 'fee_group_id' => 'FUTURES',
            //                 'maker_fee' => '0.1000',
            //                 'taker_fee' => '0.2000',
            //             ),
            //             array(
            //                 'volume' => '10000',
            //                 'fee_group_id' => 'FUTURES',
            //                 'maker_fee' => '0.0400',
            //                 'taker_fee' => '0.0800',
            //             ),
            //         ),
            //     ),
            // );
            //
            $spotFees = $this->safe_dict($response, 0, array());
            $futuresFees = $this->safe_dict($response, 1, array());
            $spotFeeTiers = $this->safe_list($spotFees, 'fee_tiers', array());
            $futuresFeeTiers = $this->safe_list($futuresFees, 'fee_tiers', array());
            $spotTiers = $this->parse_fee_tiers($spotFeeTiers);
            $futuresTiers = $this->parse_fee_tiers($futuresFeeTiers);
            $firstSpotTier = $this->safe_dict($spotTiers, 0, array());
            $firstFuturesTier = $this->safe_dict($futuresTiers, 0, array());
            $result = array();
            for ($i = 0; $i < count($this->symbols); $i++) {
                $symbol = $this->symbols[$i];
                $market = $this->market($symbol);
                $tierObject = ($market['spot']) ? $firstSpotTier : $firstFuturesTier;
                $result[$symbol] = array(
                    'info' => $spotFees,
                    'symbol' => $symbol,
                    'maker' => $this->safe_number($tierObject, 'maker_fee'),
                    'taker' => $this->safe_number($tierObject, 'taker_fee'),
                    'percentage' => true,
                    'tierBased' => true,
                    'tiers' => $spotTiers,
                );
            }
            return $result;
        }) ();
    }

    public function fetch_private_trading_fees($params = array ()) {
        return Async\async(function () use ($params) {
            Async\await($this->load_markets());
            $response = Async\await($this->privateGetAccountFees ($params));
            //
            // {
            //    "account_id":"b7f4e27e-b34a-493a-b0d4-4bd341a3f2e0",
            //    "running_volumes":array(
            //       array(
            //          "fee_group_id":"SPOT",
            //          "volume":"0",
            //          "currency":"EUR"
            //       ),
            //       {
            //          "fee_group_id":"FUTURES",
            //          "volume":"0",
            //          "currency":"EUR"
            //       }
            //    ),
            //    "active_fee_tiers":array(
            //       array(
            //          "fee_group_id":"SPOT",
            //          "volume":"0",
            //          "maker_fee":"0.1000",
            //          "taker_fee":"0.2000"
            //       ),
            //       {
            //          "fee_group_id":"FUTURES",
            //          "volume":"0",
            //          "maker_fee":"0.1000",
            //          "taker_fee":"0.2000"
            //       }
            //    )
            // }
            //
            $activeFeeTier = $this->safe_list($response, 'active_fee_tiers');
            $spotFees = $this->safe_dict($activeFeeTier, 0, array());
            $futuresFees = $this->safe_dict($activeFeeTier, 1, array());
            $spotMakerFee = $this->safe_string($spotFees, 'maker_fee');
            $spotTakerFee = $this->safe_string($spotFees, 'taker_fee');
            $spotMakerFee = Precise::string_div($spotMakerFee, '100');
            $spotTakerFee = Precise::string_div($spotTakerFee, '100');
            // $feeTiers = $this->safe_value($response, 'fee_tiers');
            $futuresMakerFee = $this->safe_string($futuresFees, 'maker_fee');
            $futuresTakerFee = $this->safe_string($futuresFees, 'taker_fee');
            $futuresMakerFee = Precise::string_div($futuresMakerFee, '100');
            $futuresTakerFee = Precise::string_div($futuresTakerFee, '100');
            $result = array();
            // $tiers = $this->parse_fee_tiers($feeTiers);
            for ($i = 0; $i < count($this->symbols); $i++) {
                $symbol = $this->symbols[$i];
                $market = $this->market($symbol);
                $makerFee = ($market['spot']) ? $spotMakerFee : $futuresMakerFee;
                $takerFee = ($market['spot']) ? $spotTakerFee : $futuresTakerFee;
                $result[$symbol] = array(
                    'info' => $response,
                    'symbol' => $symbol,
                    'maker' => $this->parse_number($makerFee),
                    'taker' => $this->parse_number($takerFee),
                    'percentage' => true,
                    'tierBased' => true,
                    'tiers' => null,
                );
            }
            return $result;
        }) ();
    }

    public function parse_fee_tiers($feeTiers, ?array $market = null) {
        $takerFees = array();
        $makerFees = array();
        for ($i = 0; $i < count($feeTiers); $i++) {
            $tier = $feeTiers[$i];
            $volume = $this->safe_number($tier, 'volume');
            $taker = $this->safe_string($tier, 'taker_fee');
            $maker = $this->safe_string($tier, 'maker_fee');
            $maker = Precise::string_div($maker, '100');
            $taker = Precise::string_div($taker, '100');
            $makerFees[] = array( $volume, $this->parse_number($maker) );
            $takerFees[] = array( $volume, $this->parse_number($taker) );
        }
        return array(
            'maker' => $makerFees,
            'taker' => $takerFees,
        );
    }

    public function parse_ticker(array $ticker, ?array $market = null): array {
        //
        // fetchTicker, fetchTickers
        //
        //     {
        //         "instrument_code":"BTC_EUR",
        //         "sequence":602562,
        //         "time":"2020-07-10T06:27:34.951Z",
        //         "state":"ACTIVE",
        //         "is_frozen":0,
        //         "quote_volume":"1695555.1783768",
        //         "base_volume":"205.67436",
        //         "last_price":"8143.91",
        //         "best_bid":"8143.71",
        //         "best_ask":"8156.9",
        //         "price_change":"-147.47",
        //         "price_change_percentage":"-1.78",
        //         "high":"8337.45",
        //         "low":"8110.0"
        //     }
        //
        $timestamp = $this->parse8601($this->safe_string($ticker, 'time'));
        $marketId = $this->safe_string($ticker, 'instrument_code');
        $symbol = $this->safe_symbol($marketId, $market, '_');
        $last = $this->safe_string($ticker, 'last_price');
        $percentage = $this->safe_string($ticker, 'price_change_percentage');
        $change = $this->safe_string($ticker, 'price_change');
        $baseVolume = $this->safe_string($ticker, 'base_volume');
        $quoteVolume = $this->safe_string($ticker, 'quote_volume');
        return $this->safe_ticker(array(
            'symbol' => $symbol,
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'high' => $this->safe_string($ticker, 'high'),
            'low' => $this->safe_string($ticker, 'low'),
            'bid' => $this->safe_string($ticker, 'best_bid'),
            'bidVolume' => null,
            'ask' => $this->safe_string($ticker, 'best_ask'),
            'askVolume' => null,
            'vwap' => null,
            'open' => null,
            'close' => $last,
            'last' => $last,
            'previousClose' => null,
            'change' => $change,
            'percentage' => $percentage,
            'average' => null,
            'baseVolume' => $baseVolume,
            'quoteVolume' => $quoteVolume,
            'info' => $ticker,
        ), $market);
    }

    public function fetch_ticker(string $symbol, $params = array ()): PromiseInterface {
        return Async\async(function () use ($symbol, $params) {
            /**
             * fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific $market
             *
             * @see https://docs.onetrading.com/#$market-ticker-for-instrument
             *
             * @param {string} $symbol unified $symbol of the $market to fetch the ticker for
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @return {array} a ~@link https://docs.ccxt.com/#/?id=ticker-structure ticker structure~
             */
            Async\await($this->load_markets());
            $market = $this->market($symbol);
            $request = array(
                'instrument_code' => $market['id'],
            );
            $response = Async\await($this->publicGetMarketTickerInstrumentCode ($this->extend($request, $params)));
            //
            //     {
            //         "instrument_code":"BTC_EUR",
            //         "sequence":602562,
            //         "time":"2020-07-10T06:27:34.951Z",
            //         "state":"ACTIVE",
            //         "is_frozen":0,
            //         "quote_volume":"1695555.1783768",
            //         "base_volume":"205.67436",
            //         "last_price":"8143.91",
            //         "best_bid":"8143.71",
            //         "best_ask":"8156.9",
            //         "price_change":"-147.47",
            //         "price_change_percentage":"-1.78",
            //         "high":"8337.45",
            //         "low":"8110.0"
            //     }
            //
            return $this->parse_ticker($response, $market);
        }) ();
    }

    public function fetch_tickers(?array $symbols = null, $params = array ()): PromiseInterface {
        return Async\async(function () use ($symbols, $params) {
            /**
             * fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
             *
             * @see https://docs.onetrading.com/#market-$ticker
             *
             * @param {string[]} [$symbols] unified $symbols of the markets to fetch the $ticker for, all market tickers are returned if not assigned
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @return {array} a dictionary of ~@link https://docs.ccxt.com/#/?id=$ticker-structure $ticker structures~
             */
            Async\await($this->load_markets());
            $symbols = $this->market_symbols($symbols);
            $response = Async\await($this->publicGetMarketTicker ($params));
            //
            //     array(
            //         {
            //             "instrument_code":"BTC_EUR",
            //             "sequence":602562,
            //             "time":"2020-07-10T06:27:34.951Z",
            //             "state":"ACTIVE",
            //             "is_frozen":0,
            //             "quote_volume":"1695555.1783768",
            //             "base_volume":"205.67436",
            //             "last_price":"8143.91",
            //             "best_bid":"8143.71",
            //             "best_ask":"8156.9",
            //             "price_change":"-147.47",
            //             "price_change_percentage":"-1.78",
            //             "high":"8337.45",
            //             "low":"8110.0"
            //         }
            //     )
            //
            $result = array();
            for ($i = 0; $i < count($response); $i++) {
                $ticker = $this->parse_ticker($response[$i]);
                $symbol = $ticker['symbol'];
                $result[$symbol] = $ticker;
            }
            return $this->filter_by_array_tickers($result, 'symbol', $symbols);
        }) ();
    }

    public function fetch_order_book(string $symbol, ?int $limit = null, $params = array ()): PromiseInterface {
        return Async\async(function () use ($symbol, $limit, $params) {
            /**
             * fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
             *
             * @see https://docs.onetrading.com/#order-book
             *
             * @param {string} $symbol unified $symbol of the $market to fetch the order book for
             * @param {int} [$limit] the maximum amount of order book entries to return
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @return {array} A dictionary of ~@link https://docs.ccxt.com/#/?id=order-book-structure order book structures~ indexed by $market symbols
             */
            Async\await($this->load_markets());
            $market = $this->market($symbol);
            $request = array(
                'instrument_code' => $market['id'],
                // level 1 means only the best bid and ask
                // level 2 is a compiled order book up to $market precision
                // level 3 is a full orderbook
                // if you wish to get regular updates about orderbooks please use the Websocket channel
                // heavy usage of this endpoint may result in limited access according to rate limits rules
                // 'level' => 3, // default
            );
            if ($limit !== null) {
                $request['depth'] = $limit;
            }
            $response = Async\await($this->publicGetOrderBookInstrumentCode ($this->extend($request, $params)));
            //
            // level 1
            //
            //     {
            //         "instrument_code":"BTC_EUR",
            //         "time":"2020-07-10T07:39:06.343Z",
            //         "asks":{
            //             "value":array(
            //                 "price":"8145.29",
            //                 "amount":"0.96538",
            //                 "number_of_orders":1
            //             }
            //         ),
            //         "bids":{
            //             "value":{
            //                 "price":"8134.0",
            //                 "amount":"1.5978",
            //                 "number_of_orders":5
            //             }
            //         }
            //     }
            //
            // level 2
            //
            //     {
            //         "instrument_code":"BTC_EUR","time":"2020-07-10T07:36:43.538Z",
            //         "asks":array(
            //             array("price":"8146.59","amount":"0.89691","number_of_orders":1),
            //             array("price":"8146.89","amount":"1.92062","number_of_orders":1),
            //             array("price":"8169.5","amount":"0.0663","number_of_orders":1),
            //         ),
            //         "bids":array(
            //             array("price":"8143.49","amount":"0.01329","number_of_orders":1),
            //             array("price":"8137.01","amount":"5.34748","number_of_orders":1),
            //             array("price":"8137.0","amount":"2.0","number_of_orders":1),
            //         )
            //     }
            //
            // level 3
            //
            //     {
            //         "instrument_code":"BTC_EUR",
            //         "time":"2020-07-10T07:32:31.525Z",
            //         "bids":array(
            //             array("price":"8146.79","amount":"0.01537","order_id":"5d717da1-a8f4-422d-afcc-03cb6ab66825"),
            //             array("price":"8139.32","amount":"3.66009","order_id":"d0715c68-f28d-4cf1-a450-d56cf650e11c"),
            //             array("price":"8137.51","amount":"2.61049","order_id":"085fd6f4-e835-4ca5-9449-a8f165772e60"),
            //         ),
            //         "asks":array(
            //             array("price":"8153.49","amount":"0.93384","order_id":"755d3aa3-42b5-46fa-903d-98f42e9ae6c4"),
            //             array("price":"8153.79","amount":"1.80456","order_id":"62034cf3-b70d-45ff-b285-ba6307941e7c"),
            //             array("price":"8167.9","amount":"0.0018","order_id":"036354e0-71cd-492f-94f2-01f7d4b66422"),
            //         )
            //     }
            //
            $timestamp = $this->parse8601($this->safe_string($response, 'time'));
            return $this->parse_order_book($response, $market['symbol'], $timestamp, 'bids', 'asks', 'price', 'amount');
        }) ();
    }

    public function parse_ohlcv($ohlcv, ?array $market = null): array {
        //
        //     {
        //         "instrument_code":"BTC_EUR",
        //         "granularity":array("unit":"HOURS","period":1),
        //         "high":"9252.65",
        //         "low":"9115.27",
        //         "open":"9250.0",
        //         "close":"9132.35",
        //         "total_amount":"33.85924",
        //         "volume":"311958.9635744",
        //         "time":"2020-05-08T22:59:59.999Z",
        //         "last_sequence":461123
        //     }
        //
        $granularity = $this->safe_value($ohlcv, 'granularity');
        $unit = $this->safe_string($granularity, 'unit');
        $period = $this->safe_string($granularity, 'period');
        $units = array(
            'MINUTES' => 'm',
            'HOURS' => 'h',
            'DAYS' => 'd',
            'WEEKS' => 'w',
            'MONTHS' => 'M',
        );
        $lowercaseUnit = $this->safe_string($units, $unit);
        $timeframe = $period . $lowercaseUnit;
        $durationInSeconds = $this->parse_timeframe($timeframe);
        $duration = $durationInSeconds * 1000;
        $timestamp = $this->parse8601($this->safe_string($ohlcv, 'time'));
        $alignedTimestamp = $duration * $this->parse_to_int($timestamp / $duration);
        $options = $this->safe_value($this->options, 'fetchOHLCV', array());
        $volumeField = $this->safe_string($options, 'volume', 'total_amount');
        return array(
            $alignedTimestamp,
            $this->safe_number($ohlcv, 'open'),
            $this->safe_number($ohlcv, 'high'),
            $this->safe_number($ohlcv, 'low'),
            $this->safe_number($ohlcv, 'close'),
            $this->safe_number($ohlcv, $volumeField),
        );
    }

    public function fetch_ohlcv(string $symbol, $timeframe = '1m', ?int $since = null, ?int $limit = null, $params = array ()): PromiseInterface {
        return Async\async(function () use ($symbol, $timeframe, $since, $limit, $params) {
            /**
             * fetches historical candlestick data containing the open, high, low, and close price, and the volume of a $market
             *
             * @see https://docs.onetrading.com/#candlesticks
             *
             * @param {string} $symbol unified $symbol of the $market to fetch OHLCV data for
             * @param {string} $timeframe the length of time each candle represents
             * @param {int} [$since] timestamp in ms of the earliest candle to fetch
             * @param {int} [$limit] the maximum amount of candles to fetch
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @return {int[][]} A list of candles ordered, open, high, low, close, volume
             */
            Async\await($this->load_markets());
            $market = $this->market($symbol);
            $periodUnit = $this->safe_string($this->timeframes, $timeframe);
            list($period, $unit) = explode('/', $periodUnit);
            $durationInSeconds = $this->parse_timeframe($timeframe);
            $duration = $durationInSeconds * 1000;
            if ($limit === null) {
                $limit = 1500;
            }
            $request = array(
                'instrument_code' => $market['id'],
                // 'from' => $this->iso8601($since),
                // 'to' => $this->iso8601($this->milliseconds()),
                'period' => $period,
                'unit' => $unit,
            );
            if ($since === null) {
                $now = $this->milliseconds();
                $request['to'] = $this->iso8601($now);
                $request['from'] = $this->iso8601($now - $limit * $duration);
            } else {
                $request['from'] = $this->iso8601($since);
                $request['to'] = $this->iso8601($this->sum($since, $limit * $duration));
            }
            $response = Async\await($this->publicGetCandlesticksInstrumentCode ($this->extend($request, $params)));
            //
            //     array(
            //         array("instrument_code":"BTC_EUR","granularity":array("unit":"HOURS","period":1),"high":"9252.65","low":"9115.27","open":"9250.0","close":"9132.35","total_amount":"33.85924","volume":"311958.9635744","time":"2020-05-08T22:59:59.999Z","last_sequence":461123),
            //         array("instrument_code":"BTC_EUR","granularity":array("unit":"HOURS","period":1),"high":"9162.49","low":"9040.0","open":"9132.53","close":"9083.69","total_amount":"26.19685","volume":"238553.7812365","time":"2020-05-08T23:59:59.999Z","last_sequence":461376),
            //         array("instrument_code":"BTC_EUR","granularity":array("unit":"HOURS","period":1),"high":"9135.7","low":"9002.59","open":"9055.45","close":"9133.98","total_amount":"26.21919","volume":"238278.8724959","time":"2020-05-09T00:59:59.999Z","last_sequence":461521),
            //     )
            //
            $ohlcv = $this->safe_list($response, 'candlesticks');
            return $this->parse_ohlcvs($ohlcv, $market, $timeframe, $since, $limit);
        }) ();
    }

    public function parse_trade(array $trade, ?array $market = null): array {
        //
        // fetchTrades (public)
        //
        //     {
        //         "instrument_code":"BTC_EUR",
        //         "price":"8137.28",
        //         "amount":"0.22269",
        //         "taker_side":"BUY",
        //         "volume":"1812.0908832",
        //         "time":"2020-07-10T14:44:32.299Z",
        //         "trade_timestamp":1594392272299,
        //         "sequence":603047
        //     }
        //
        // fetchMyTrades, fetchOrder, fetchOpenOrders, fetchClosedOrders trades (private)
        //
        //     {
        //         "fee" => array(
        //             "fee_amount" => "0.0014",
        //             "fee_currency" => "BTC",
        //             "fee_percentage" => "0.1",
        //             "fee_group_id" => "default",
        //             "fee_type" => "TAKER",
        //             "running_trading_volume" => "0.0"
        //         ),
        //         "trade" => {
        //             "trade_id" => "fdff2bcc-37d6-4a2d-92a5-46e09c868664",
        //             "order_id" => "36bb2437-7402-4794-bf26-4bdf03526439",
        //             "account_id" => "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
        //             "amount" => "1.4",
        //             "side" => "BUY",
        //             "instrument_code" => "BTC_EUR",
        //             "price" => "7341.4",
        //             "time" => "2019-09-27T15:05:32.564Z",
        //             "sequence" => 48670
        //         }
        //     }
        //
        $feeInfo = $this->safe_value($trade, 'fee', array());
        $trade = $this->safe_value($trade, 'trade', $trade);
        $timestamp = $this->safe_integer($trade, 'trade_timestamp');
        if ($timestamp === null) {
            $timestamp = $this->parse8601($this->safe_string($trade, 'time'));
        }
        $side = $this->safe_string_lower_2($trade, 'side', 'taker_side');
        $priceString = $this->safe_string($trade, 'price');
        $amountString = $this->safe_string($trade, 'amount');
        $costString = $this->safe_string($trade, 'volume');
        $marketId = $this->safe_string($trade, 'instrument_code');
        $symbol = $this->safe_symbol($marketId, $market, '_');
        $feeCostString = $this->safe_string($feeInfo, 'fee_amount');
        $takerOrMaker = null;
        $fee = null;
        if ($feeCostString !== null) {
            $feeCurrencyId = $this->safe_string($feeInfo, 'fee_currency');
            $feeCurrencyCode = $this->safe_currency_code($feeCurrencyId);
            $feeRateString = $this->safe_string($feeInfo, 'fee_percentage');
            $fee = array(
                'cost' => $feeCostString,
                'currency' => $feeCurrencyCode,
                'rate' => $feeRateString,
            );
            $takerOrMaker = $this->safe_string_lower($feeInfo, 'fee_type');
        }
        return $this->safe_trade(array(
            'id' => $this->safe_string_2($trade, 'trade_id', 'sequence'),
            'order' => $this->safe_string($trade, 'order_id'),
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'symbol' => $symbol,
            'type' => null,
            'side' => $side,
            'price' => $priceString,
            'amount' => $amountString,
            'cost' => $costString,
            'takerOrMaker' => $takerOrMaker,
            'fee' => $fee,
            'info' => $trade,
        ), $market);
    }

    public function parse_balance($response): array {
        $balances = $this->safe_value($response, 'balances', array());
        $result = array( 'info' => $response );
        for ($i = 0; $i < count($balances); $i++) {
            $balance = $balances[$i];
            $currencyId = $this->safe_string($balance, 'currency_code');
            $code = $this->safe_currency_code($currencyId);
            $account = $this->account();
            $account['free'] = $this->safe_string($balance, 'available');
            $account['used'] = $this->safe_string($balance, 'locked');
            $result[$code] = $account;
        }
        return $this->safe_balance($result);
    }

    public function fetch_balance($params = array ()): PromiseInterface {
        return Async\async(function () use ($params) {
            /**
             * query for balance and get the amount of funds available for trading or funds locked in orders
             *
             * @see https://docs.onetrading.com/#balances
             *
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @return {array} a ~@link https://docs.ccxt.com/#/?id=balance-structure balance structure~
             */
            Async\await($this->load_markets());
            $response = Async\await($this->privateGetAccountBalances ($params));
            //
            //     {
            //         "account_id":"4b95934f-55f1-460c-a525-bd5afc0cf071",
            //         "balances":array(
            //             {
            //                 "account_id":"4b95934f-55f1-460c-a525-bd5afc0cf071",
            //                 "currency_code":"BTC",
            //                 "change":"10.0",
            //                 "available":"10.0",
            //                 "locked":"0.0",
            //                 "sequence":142135994,
            //                 "time":"2020-07-01T10:57:32.959Z"
            //             }
            //         )
            //     }
            //
            return $this->parse_balance($response);
        }) ();
    }

    public function parse_order_status(?string $status) {
        $statuses = array(
            'FILLED' => 'open',
            'FILLED_FULLY' => 'closed',
            'FILLED_CLOSED' => 'canceled',
            'FILLED_REJECTED' => 'rejected',
            'OPEN' => 'open',
            'REJECTED' => 'rejected',
            'CLOSED' => 'canceled',
            'FAILED' => 'failed',
            'STOP_TRIGGERED' => 'triggered',
            'DONE' => 'closed',
        );
        return $this->safe_string($statuses, $status, $status);
    }

    public function parse_order(array $order, ?array $market = null): array {
        //
        // createOrder
        //
        //     {
        //         "order_id" => "d5492c24-2995-4c18-993a-5b8bf8fffc0d",
        //         "client_id" => "d75fb03b-b599-49e9-b926-3f0b6d103206",
        //         "account_id" => "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
        //         "instrument_code" => "BTC_EUR",
        //         "time" => "2019-08-01T08:00:44.026Z",
        //         "side" => "BUY",
        //         "price" => "5000",
        //         "amount" => "1",
        //         "filled_amount" => "0.5",
        //         "type" => "LIMIT",
        //         "time_in_force" => "GOOD_TILL_CANCELLED"
        //     }
        //
        // fetchOrder, fetchOpenOrders, fetchClosedOrders
        //
        //     {
        //         "order" => array(
        //             "order_id" => "66756a10-3e86-48f4-9678-b634c4b135b2",
        //             "account_id" => "1eb2ad5d-55f1-40b5-bc92-7dc05869e905",
        //             "instrument_code" => "BTC_EUR",
        //             "amount" => "1234.5678",
        //             "filled_amount" => "1234.5678",
        //             "side" => "BUY",
        //             "type" => "LIMIT",
        //             "status" => "OPEN",
        //             "sequence" => 123456789,
        //             "price" => "1234.5678",
        //             "average_price" => "1234.5678",
        //             "reason" => "INSUFFICIENT_FUNDS",
        //             "time" => "2019-08-24T14:15:22Z",
        //             "time_in_force" => "GOOD_TILL_CANCELLED",
        //             "time_last_updated" => "2019-08-24T14:15:22Z",
        //             "expire_after" => "2019-08-24T14:15:22Z",
        //             "is_post_only" => false,
        //             "time_triggered" => "2019-08-24T14:15:22Z",
        //             "trigger_price" => "1234.5678"
        //         ),
        //         "trades" => array(
        //             {
        //                 "fee" => array(
        //                     "fee_amount" => "0.0014",
        //                     "fee_currency" => "BTC",
        //                     "fee_percentage" => "0.1",
        //                     "fee_group_id" => "default",
        //                     "fee_type" => "TAKER",
        //                     "running_trading_volume" => "0.0"
        //                 ),
        //                 "trade" => {
        //                     "trade_id" => "fdff2bcc-37d6-4a2d-92a5-46e09c868664",
        //                     "order_id" => "36bb2437-7402-4794-bf26-4bdf03526439",
        //                     "account_id" => "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
        //                     "amount" => "1.4",
        //                     "side" => "BUY",
        //                     "instrument_code" => "BTC_EUR",
        //                     "price" => "7341.4",
        //                     "time" => "2019-09-27T15:05:32.564Z",
        //                     "sequence" => 48670
        //                 }
        //             }
        //         )
        //     }
        //
        $rawOrder = $this->safe_value($order, 'order', $order);
        $id = $this->safe_string($rawOrder, 'order_id');
        $clientOrderId = $this->safe_string($rawOrder, 'client_id');
        $timestamp = $this->parse8601($this->safe_string($rawOrder, 'time'));
        $rawStatus = $this->parse_order_status($this->safe_string($rawOrder, 'status'));
        $status = $this->parse_order_status($rawStatus);
        $marketId = $this->safe_string($rawOrder, 'instrument_code');
        $symbol = $this->safe_symbol($marketId, $market, '_');
        $price = $this->safe_string($rawOrder, 'price');
        $amount = $this->safe_string($rawOrder, 'amount');
        $filled = $this->safe_string($rawOrder, 'filled_amount');
        $side = $this->safe_string_lower($rawOrder, 'side');
        $type = $this->safe_string_lower($rawOrder, 'type');
        $timeInForce = $this->parse_time_in_force($this->safe_string($rawOrder, 'time_in_force'));
        $postOnly = $this->safe_value($rawOrder, 'is_post_only');
        $rawTrades = $this->safe_value($order, 'trades', array());
        return $this->safe_order(array(
            'id' => $id,
            'clientOrderId' => $clientOrderId,
            'info' => $order,
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'lastTradeTimestamp' => null,
            'symbol' => $symbol,
            'type' => $this->parse_order_type($type),
            'timeInForce' => $timeInForce,
            'postOnly' => $postOnly,
            'side' => $side,
            'price' => $price,
            'triggerPrice' => $this->safe_number($rawOrder, 'trigger_price'),
            'amount' => $amount,
            'cost' => null,
            'average' => null,
            'filled' => $filled,
            'remaining' => null,
            'status' => $status,
            // 'fee' => null,
            'trades' => $rawTrades,
        ), $market);
    }

    public function parse_order_type(?string $type) {
        $types = array(
            'booked' => 'limit',
        );
        return $this->safe_string($types, $type, $type);
    }

    public function parse_time_in_force(?string $timeInForce) {
        $timeInForces = array(
            'GOOD_TILL_CANCELLED' => 'GTC',
            'GOOD_TILL_TIME' => 'GTT',
            'IMMEDIATE_OR_CANCELLED' => 'IOC',
            'FILL_OR_KILL' => 'FOK',
        );
        return $this->safe_string($timeInForces, $timeInForce, $timeInForce);
    }

    public function create_order(string $symbol, string $type, string $side, float $amount, ?float $price = null, $params = array ()) {
        return Async\async(function () use ($symbol, $type, $side, $amount, $price, $params) {
            /**
             * create a trade order
             *
             * @see https://docs.onetrading.com/#create-order
             *
             * @param {string} $symbol unified $symbol of the $market to create an order in
             * @param {string} $type 'limit'
             * @param {string} $side 'buy' or 'sell'
             * @param {float} $amount how much of currency you want to trade in units of base currency
             * @param {float} [$price] the $price at which the order is to be fulfilled, in units of the quote currency, ignored in $market orders
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @param {float} [$params->triggerPrice] onetrading only does stop limit orders and does not do stop $market
             * @return {array} an ~@link https://docs.ccxt.com/#/?id=order-structure order structure~
             */
            Async\await($this->load_markets());
            $market = $this->market($symbol);
            $uppercaseType = strtoupper($type);
            $request = array(
                'instrument_code' => $market['id'],
                'type' => $uppercaseType, // LIMIT, MARKET, STOP
                'side' => strtoupper($side), // or SELL
                'amount' => $this->amount_to_precision($symbol, $amount),
                // "price" => "1234.5678", // required for LIMIT and STOP orders
                // "client_id" => "d75fb03b-b599-49e9-b926-3f0b6d103206", // optional
                // "time_in_force" => "GOOD_TILL_CANCELLED", // limit orders only, GOOD_TILL_CANCELLED, GOOD_TILL_TIME, IMMEDIATE_OR_CANCELLED and FILL_OR_KILL
                // "expire_after" => "2020-07-02T19:40:13Z", // required for GOOD_TILL_TIME
                // "is_post_only" => false, // limit orders only, optional
                // "trigger_price" => "1234.5678" // required for stop orders
            );
            $priceIsRequired = false;
            if ($uppercaseType === 'LIMIT' || $uppercaseType === 'STOP') {
                $priceIsRequired = true;
            }
            $triggerPrice = $this->safe_number_n($params, array( 'triggerPrice', 'trigger_price', 'stopPrice' ));
            if ($triggerPrice !== null) {
                if ($uppercaseType === 'MARKET') {
                    throw new BadRequest($this->id . ' createOrder() cannot place stop $market orders, only stop limit');
                }
                $request['trigger_price'] = $this->price_to_precision($symbol, $triggerPrice);
                $request['type'] = 'STOP';
                $params = $this->omit($params, array( 'triggerPrice', 'trigger_price', 'stopPrice' ));
            } elseif ($uppercaseType === 'STOP') {
                throw new ArgumentsRequired($this->id . ' createOrder() requires a $triggerPrice param for ' . $type . ' orders');
            }
            if ($priceIsRequired) {
                $request['price'] = $this->price_to_precision($symbol, $price);
            }
            $clientOrderId = $this->safe_string_2($params, 'clientOrderId', 'client_id');
            if ($clientOrderId !== null) {
                $request['client_id'] = $clientOrderId;
                $params = $this->omit($params, array( 'clientOrderId', 'client_id' ));
            }
            $timeInForce = $this->safe_string_2($params, 'timeInForce', 'time_in_force', 'GOOD_TILL_CANCELLED');
            $params = $this->omit($params, 'timeInForce');
            $request['time_in_force'] = $timeInForce;
            $response = Async\await($this->privatePostAccountOrders ($this->extend($request, $params)));
            //
            //     {
            //         "order_id" => "d5492c24-2995-4c18-993a-5b8bf8fffc0d",
            //         "client_id" => "d75fb03b-b599-49e9-b926-3f0b6d103206",
            //         "account_id" => "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
            //         "instrument_code" => "BTC_EUR",
            //         "time" => "2019-08-01T08:00:44.026Z",
            //         "side" => "BUY",
            //         "price" => "5000",
            //         "amount" => "1",
            //         "filled_amount" => "0.5",
            //         "type" => "LIMIT",
            //         "time_in_force" => "GOOD_TILL_CANCELLED"
            //     }
            //
            return $this->parse_order($response, $market);
        }) ();
    }

    public function cancel_order(string $id, ?string $symbol = null, $params = array ()) {
        return Async\async(function () use ($id, $symbol, $params) {
            /**
             * cancels an open order
             *
             * @see https://docs.onetrading.com/#close-order-by-order-$id
             *
             * @param {string} $id order $id
             * @param {string} $symbol not used by bitmex cancelOrder ()
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @return {array} An ~@link https://docs.ccxt.com/#/?$id=order-structure order structure~
             */
            Async\await($this->load_markets());
            $clientOrderId = $this->safe_string_2($params, 'clientOrderId', 'client_id');
            $params = $this->omit($params, array( 'clientOrderId', 'client_id' ));
            $method = 'privateDeleteAccountOrdersOrderId';
            $request = array();
            if ($clientOrderId !== null) {
                $method = 'privateDeleteAccountOrdersClientClientId';
                $request['client_id'] = $clientOrderId;
            } else {
                $request['order_id'] = $id;
            }
            $response = null;
            if ($method === 'privateDeleteAccountOrdersOrderId') {
                $response = Async\await($this->privateDeleteAccountOrdersOrderId ($this->extend($request, $params)));
            } else {
                $response = Async\await($this->privateDeleteAccountOrdersClientClientId ($this->extend($request, $params)));
            }
            //
            // responds with an empty body
            //
            return $this->parse_order($response);
        }) ();
    }

    public function cancel_all_orders(?string $symbol = null, $params = array ()) {
        return Async\async(function () use ($symbol, $params) {
            /**
             * cancel all open orders
             *
             * @see https://docs.onetrading.com/#close-all-orders
             *
             * @param {string} $symbol unified $market $symbol, only orders in the $market of this $symbol are cancelled when $symbol is not null
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?id=order-structure order structures~
             */
            Async\await($this->load_markets());
            $request = array();
            if ($symbol !== null) {
                $market = $this->market($symbol);
                $request['instrument_code'] = $market['id'];
            }
            $response = Async\await($this->privateDeleteAccountOrders ($this->extend($request, $params)));
            //
            //     array(
            //         "a10e9bd1-8f72-4cfe-9f1b-7f1c8a9bd8ee"
            //     )
            //
            return array( $this->safe_order(array( 'info' => $response )) );
        }) ();
    }

    public function cancel_orders($ids, ?string $symbol = null, $params = array ()) {
        return Async\async(function () use ($ids, $symbol, $params) {
            /**
             * cancel multiple orders
             *
             * @see https://docs.onetrading.com/#close-all-orders
             *
             * @param {string[]} $ids order $ids
             * @param {string} $symbol unified market $symbol, default is null
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @return {array} an list of ~@link https://docs.ccxt.com/#/?id=order-structure order structures~
             */
            Async\await($this->load_markets());
            $request = array(
                'ids' => implode(',', $ids),
            );
            $response = Async\await($this->privateDeleteAccountOrders ($this->extend($request, $params)));
            //
            //     array(
            //         "a10e9bd1-8f72-4cfe-9f1b-7f1c8a9bd8ee"
            //     )
            //
            return $response;
        }) ();
    }

    public function fetch_order(string $id, ?string $symbol = null, $params = array ()) {
        return Async\async(function () use ($id, $symbol, $params) {
            /**
             * fetches information on an order made by the user
             *
             * @see https://docs.onetrading.com/#get-order
             *
             * @param {string} $id the order $id
             * @param {string} $symbol not used by onetrading fetchOrder
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @return {array} An ~@link https://docs.ccxt.com/#/?$id=order-structure order structure~
             */
            Async\await($this->load_markets());
            $request = array(
                'order_id' => $id,
            );
            $response = Async\await($this->privateGetAccountOrdersOrderId ($this->extend($request, $params)));
            //
            //     {
            //         "order" => array(
            //             "order_id" => "36bb2437-7402-4794-bf26-4bdf03526439",
            //             "account_id" => "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
            //             "time_last_updated" => "2019-09-27T15:05:35.096Z",
            //             "sequence" => 48782,
            //             "price" => "7349.2",
            //             "filled_amount" => "100.0",
            //             "status" => "FILLED_FULLY",
            //             "amount" => "100.0",
            //             "instrument_code" => "BTC_EUR",
            //             "side" => "BUY",
            //             "time" => "2019-09-27T15:05:32.063Z",
            //             "type" => "MARKET"
            //         ),
            //         "trades" => array(
            //             {
            //                 "fee" => array(
            //                     "fee_amount" => "0.0014",
            //                     "fee_currency" => "BTC",
            //                     "fee_percentage" => "0.1",
            //                     "fee_group_id" => "default",
            //                     "fee_type" => "TAKER",
            //                     "running_trading_volume" => "0.0"
            //                 ),
            //                 "trade" => {
            //                     "trade_id" => "fdff2bcc-37d6-4a2d-92a5-46e09c868664",
            //                     "order_id" => "36bb2437-7402-4794-bf26-4bdf03526439",
            //                     "account_id" => "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
            //                     "amount" => "1.4",
            //                     "side" => "BUY",
            //                     "instrument_code" => "BTC_EUR",
            //                     "price" => "7341.4",
            //                     "time" => "2019-09-27T15:05:32.564Z",
            //                     "sequence" => 48670
            //                 }
            //             }
            //         )
            //     }
            //
            return $this->parse_order($response);
        }) ();
    }

    public function fetch_open_orders(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()): PromiseInterface {
        return Async\async(function () use ($symbol, $since, $limit, $params) {
            /**
             * fetch all unfilled currently open orders
             *
             * @see https://docs.onetrading.com/#get-orders
             *
             * @param {string} $symbol unified $market $symbol
             * @param {int} [$since] the earliest time in ms $to fetch open orders for
             * @param {int} [$limit] the maximum number of  open orders structures $to retrieve
             * @param {array} [$params] extra parameters specific $to the exchange API endpoint
             * @return {Order[]} a list of ~@link https://docs.ccxt.com/#/?id=order-structure order structures~
             */
            Async\await($this->load_markets());
            $request = array(
                // 'from' => $this->iso8601($since),
                // 'to' => $this->iso8601($this->milliseconds()), // max range is 100 days
                // 'instrument_code' => $market['id'],
                // 'with_cancelled_and_rejected' => false, // default is false, orders which have been cancelled by the user before being filled or rejected by the system, additionally, all inactive filled orders which would return with "with_just_filled_inactive"
                // 'with_just_filled_inactive' => false, // orders which have been filled and are no longer open, use of "with_cancelled_and_rejected" extends "with_just_filled_inactive" and in case both are specified the latter is ignored
                // 'with_just_orders' => false, // do not return any trades corresponsing $to the orders, it may be significanly faster and should be used if user is not interesting in trade information
                // 'max_page_size' => 100,
                // 'cursor' => 'string', // pointer specifying the position from which the next pages should be returned
            );
            $market = null;
            if ($symbol !== null) {
                $market = $this->market($symbol);
                $request['instrument_code'] = $market['id'];
            }
            if ($since !== null) {
                $to = $this->safe_string($params, 'to');
                if ($to === null) {
                    throw new ArgumentsRequired($this->id . ' fetchOpenOrders() requires a "to" iso8601 string param with the $since argument is specified, max range is 100 days');
                }
                $request['from'] = $this->iso8601($since);
            }
            if ($limit !== null) {
                $request['max_page_size'] = $limit;
            }
            $response = Async\await($this->privateGetAccountOrders ($this->extend($request, $params)));
            //
            //     {
            //         "order_history" => array(
            //             {
            //                 "order" => array(
            //                     "trigger_price" => "12089.88",
            //                     "order_id" => "d453ca12-c650-46dd-9dee-66910d96bfc0",
            //                     "account_id" => "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
            //                     "instrument_code" => "BTC_USDT",
            //                     "time" => "2019-08-23T10:02:31.663Z",
            //                     "side" => "SELL",
            //                     "price" => "10159.76",
            //                     "average_price" => "10159.76",
            //                     "amount" => "0.2",
            //                     "filled_amount" => "0.2",
            //                     "type" => "STOP",
            //                     "sequence" => 8,
            //                     "status" => "FILLED_FULLY"
            //                 ),
            //                 "trades" => array(
            //                     {
            //                         "fee" => array(
            //                             "fee_amount" => "0.4188869",
            //                             "fee_currency" => "USDT",
            //                             "fee_percentage" => "0.1",
            //                             "fee_group_id" => "default",
            //                             "fee_type" => "TAKER",
            //                             "running_trading_volume" => "0.0"
            //                         ),
            //                         "trade" => array(
            //                             "trade_id" => "ec82896f-fd1b-4cbb-89df-a9da85ccbb4b",
            //                             "order_id" => "d453ca12-c650-46dd-9dee-66910d96bfc0",
            //                             "account_id" => "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
            //                             "amount" => "0.2",
            //                             "side" => "SELL",
            //                             "instrument_code" => "BTC_USDT",
            //                             "price" => "10159.76",
            //                             "time" => "2019-08-23T10:02:32.663Z",
            //                             "sequence" => 9
            //                         }
            //                     }
            //                 )
            //             ),
            //             array(
            //                 "order" => array(
            //                     "order_id" => "5151a99e-f414-418f-8cf1-2568d0a63ea5",
            //                     "account_id" => "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
            //                     "instrument_code" => "BTC_USDT",
            //                     "time" => "2019-08-23T10:01:36.773Z",
            //                     "side" => "SELL",
            //                     "price" => "12289.88",
            //                     "amount" => "0.5",
            //                     "filled_amount" => "0.0",
            //                     "type" => "LIMIT",
            //                     "sequence" => 7,
            //                     "status" => "OPEN"
            //                 ),
            //                 "trades" => array()
            //             ),
            //             {
            //                 "order" => array(
            //                     "order_id" => "ac80d857-75e1-4733-9070-fd4288395fdc",
            //                     "account_id" => "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
            //                     "instrument_code" => "BTC_USDT",
            //                     "time" => "2019-08-23T10:01:25.031Z",
            //                     "side" => "SELL",
            //                     "price" => "11089.88",
            //                     "amount" => "0.1",
            //                     "filled_amount" => "0.0",
            //                     "type" => "LIMIT",
            //                     "sequence" => 6,
            //                     "status" => "OPEN"
            //                 ),
            //                 "trades" => array()
            //             }
            //         ),
            //         "max_page_size" => 100
            //     }
            //
            $orderHistory = $this->safe_list($response, 'order_history', array());
            return $this->parse_orders($orderHistory, $market, $since, $limit);
        }) ();
    }

    public function fetch_closed_orders(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()): PromiseInterface {
        return Async\async(function () use ($symbol, $since, $limit, $params) {
            /**
             * fetches information on multiple closed orders made by the user
             *
             * @see https://docs.onetrading.com/#get-orders
             *
             * @param {string} $symbol unified market $symbol of the market orders were made in
             * @param {int} [$since] the earliest time in ms to fetch orders for
             * @param {int} [$limit] the maximum number of order structures to retrieve
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @return {Order[]} a list of ~@link https://docs.ccxt.com/#/?id=order-structure order structures~
             */
            $request = array(
                'with_cancelled_and_rejected' => true, // default is false, orders which have been cancelled by the user before being filled or rejected by the system, additionally, all inactive filled orders which would return with "with_just_filled_inactive"
            );
            return Async\await($this->fetch_open_orders($symbol, $since, $limit, $this->extend($request, $params)));
        }) ();
    }

    public function fetch_order_trades(string $id, ?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()) {
        return Async\async(function () use ($id, $symbol, $since, $limit, $params) {
            /**
             * fetch all the trades made from a single order
             *
             * @see https://docs.onetrading.com/#trades-for-order
             *
             * @param {string} $id order $id
             * @param {string} $symbol unified $market $symbol
             * @param {int} [$since] the earliest time in ms to fetch trades for
             * @param {int} [$limit] the maximum number of trades to retrieve
             * @param {array} [$params] extra parameters specific to the exchange API endpoint
             * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?$id=trade-structure trade structures~
             */
            Async\await($this->load_markets());
            $request = array(
                'order_id' => $id,
                // 'max_page_size' => 100,
                // 'cursor' => 'string', // pointer specifying the position from which the next pages should be returned
            );
            if ($limit !== null) {
                $request['max_page_size'] = $limit;
            }
            $response = Async\await($this->privateGetAccountOrdersOrderIdTrades ($this->extend($request, $params)));
            //
            //     {
            //         "trade_history" => array(
            //             {
            //                 "trade" => array(
            //                     "trade_id" => "2b42efcd-d5b7-4a56-8e12-b69ffd68c5ef",
            //                     "order_id" => "66756a10-3e86-48f4-9678-b634c4b135b2",
            //                     "account_id" => "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
            //                     "amount" => "1234.5678",
            //                     "side" => "BUY",
            //                     "instrument_code" => "BTC_EUR",
            //                     "price" => "1234.5678",
            //                     "time" => "2019-08-24T14:15:22Z",
            //                     "price_tick_sequence" => 0,
            //                     "sequence" => 123456789
            //                 ),
            //                 "fee" => {
            //                     "fee_amount" => "1234.5678",
            //                     "fee_percentage" => "1234.5678",
            //                     "fee_group_id" => "default",
            //                     "running_trading_volume" => "1234.5678",
            //                     "fee_currency" => "BTC",
            //                     "fee_type" => "TAKER"
            //                 }
            //             }
            //         ),
            //         "max_page_size" => 0,
            //         "cursor" => "string"
            //     }
            //
            $tradeHistory = $this->safe_value($response, 'trade_history', array());
            $market = null;
            if ($symbol !== null) {
                $market = $this->market($symbol);
            }
            return $this->parse_trades($tradeHistory, $market, $since, $limit);
        }) ();
    }

    public function fetch_my_trades(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()) {
        return Async\async(function () use ($symbol, $since, $limit, $params) {
            /**
             * fetch all trades made by the user
             *
             * @see https://docs.onetrading.com/#all-trades
             *
             * @param {string} $symbol unified $market $symbol
             * @param {int} [$since] the earliest time in ms $to fetch trades for
             * @param {int} [$limit] the maximum number of trades structures $to retrieve
             * @param {array} [$params] extra parameters specific $to the exchange API endpoint
             * @return {Trade[]} a list of ~@link https://docs.ccxt.com/#/?id=trade-structure trade structures~
             */
            Async\await($this->load_markets());
            $request = array(
                // 'from' => $this->iso8601($since),
                // 'to' => $this->iso8601($this->milliseconds()), // max range is 100 days
                // 'instrument_code' => $market['id'],
                // 'max_page_size' => 100,
                // 'cursor' => 'string', // pointer specifying the position from which the next pages should be returned
            );
            $market = null;
            if ($symbol !== null) {
                $market = $this->market($symbol);
                $request['instrument_code'] = $market['id'];
            }
            if ($since !== null) {
                $to = $this->safe_string($params, 'to');
                if ($to === null) {
                    throw new ArgumentsRequired($this->id . ' fetchMyTrades() requires a "to" iso8601 string param with the $since argument is specified, max range is 100 days');
                }
                $request['from'] = $this->iso8601($since);
            }
            if ($limit !== null) {
                $request['max_page_size'] = $limit;
            }
            $response = Async\await($this->privateGetAccountTrades ($this->extend($request, $params)));
            //
            //     {
            //         "trade_history" => array(
            //             {
            //                 "trade" => array(
            //                     "trade_id" => "2b42efcd-d5b7-4a56-8e12-b69ffd68c5ef",
            //                     "order_id" => "66756a10-3e86-48f4-9678-b634c4b135b2",
            //                     "account_id" => "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
            //                     "amount" => "1234.5678",
            //                     "side" => "BUY",
            //                     "instrument_code" => "BTC_EUR",
            //                     "price" => "1234.5678",
            //                     "time" => "2019-08-24T14:15:22Z",
            //                     "price_tick_sequence" => 0,
            //                     "sequence" => 123456789
            //                 ),
            //                 "fee" => {
            //                     "fee_amount" => "1234.5678",
            //                     "fee_percentage" => "1234.5678",
            //                     "fee_group_id" => "default",
            //                     "running_trading_volume" => "1234.5678",
            //                     "fee_currency" => "BTC",
            //                     "fee_type" => "TAKER"
            //                 }
            //             }
            //         ),
            //         "max_page_size" => 0,
            //         "cursor" => "string"
            //     }
            //
            $tradeHistory = $this->safe_list($response, 'trade_history', array());
            return $this->parse_trades($tradeHistory, $market, $since, $limit);
        }) ();
    }

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

    public function handle_errors(int $code, string $reason, string $url, string $method, array $headers, string $body, $response, $requestHeaders, $requestBody) {
        if ($response === null) {
            return null;
        }
        //
        //     array("error":"MISSING_FROM_PARAM")
        //     array("error":"MISSING_TO_PARAM")
        //     array("error":"CANDLESTICKS_TIME_RANGE_TOO_BIG")
        //
        $message = $this->safe_string($response, 'error');
        if ($message !== null) {
            $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
        }
        return null;
    }
}
