<?php

namespace ccxt;

// 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\abstract\btcalpha as Exchange;

class btcalpha extends Exchange {

    public function describe(): mixed {
        return $this->deep_extend(parent::describe(), array(
            'id' => 'btcalpha',
            'name' => 'BTC-Alpha',
            'countries' => array( 'US' ),
            'version' => 'v1',
            'has' => array(
                'CORS' => null,
                'spot' => true,
                'margin' => false,
                'swap' => false,
                'future' => false,
                'option' => false,
                'addMargin' => false,
                'borrowCrossMargin' => false,
                'borrowIsolatedMargin' => false,
                'borrowMargin' => false,
                'cancelOrder' => true,
                'closeAllPositions' => false,
                'closePosition' => false,
                'createDepositAddress' => false,
                'createOrder' => true,
                'createOrderWithTakeProfitAndStopLoss' => false,
                'createOrderWithTakeProfitAndStopLossWs' => false,
                'createPostOnlyOrder' => false,
                'createReduceOnlyOrder' => false,
                'createStopLimitOrder' => false,
                'createStopMarketOrder' => false,
                'createStopOrder' => false,
                'fetchBalance' => true,
                'fetchBorrowInterest' => false,
                'fetchBorrowRate' => false,
                'fetchBorrowRateHistories' => false,
                'fetchBorrowRateHistory' => false,
                'fetchBorrowRates' => false,
                'fetchBorrowRatesPerSymbol' => false,
                'fetchClosedOrders' => true,
                'fetchCrossBorrowRate' => false,
                'fetchCrossBorrowRates' => false,
                'fetchCurrencies' => false,
                'fetchDeposit' => false,
                'fetchDepositAddress' => false,
                'fetchDepositAddresses' => false,
                'fetchDepositAddressesByNetwork' => false,
                'fetchDeposits' => true,
                'fetchFundingHistory' => false,
                'fetchFundingInterval' => false,
                'fetchFundingIntervals' => false,
                'fetchFundingRate' => false,
                'fetchFundingRateHistory' => false,
                'fetchFundingRates' => false,
                'fetchGreeks' => false,
                'fetchIndexOHLCV' => false,
                'fetchIsolatedBorrowRate' => false,
                'fetchIsolatedBorrowRates' => false,
                'fetchIsolatedPositions' => false,
                'fetchL2OrderBook' => true,
                'fetchLeverage' => false,
                'fetchLeverages' => false,
                'fetchLeverageTiers' => false,
                'fetchLiquidations' => false,
                'fetchLongShortRatio' => false,
                'fetchLongShortRatioHistory' => false,
                'fetchMarginAdjustmentHistory' => false,
                'fetchMarginMode' => false,
                'fetchMarginModes' => false,
                'fetchMarketLeverageTiers' => false,
                'fetchMarkets' => true,
                'fetchMarkOHLCV' => 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' => true,
                'fetchPosition' => false,
                'fetchPositionHistory' => false,
                'fetchPositionMode' => false,
                'fetchPositions' => false,
                'fetchPositionsForSymbol' => false,
                'fetchPositionsHistory' => false,
                'fetchPositionsRisk' => false,
                'fetchPremiumIndexOHLCV' => false,
                'fetchSettlementHistory' => false,
                'fetchTicker' => true,
                'fetchTickers' => true,
                'fetchTrades' => true,
                'fetchTradingFee' => false,
                'fetchTradingFees' => false,
                'fetchTransfer' => false,
                'fetchTransfers' => false,
                'fetchVolatilityHistory' => false,
                'fetchWithdrawal' => false,
                'fetchWithdrawals' => true,
                'reduceMargin' => false,
                'repayCrossMargin' => false,
                'repayIsolatedMargin' => false,
                'repayMargin' => false,
                'setLeverage' => false,
                'setMargin' => false,
                'setMarginMode' => false,
                'setPositionMode' => false,
                'transfer' => false,
                'withdraw' => false,
            ),
            'timeframes' => array(
                '5m' => '5',
                '15m' => '15',
                '30m' => '30',
                '1h' => '60',
                '4h' => '240',
                '1d' => 'D',
            ),
            'urls' => array(
                'logo' => 'https://github.com/user-attachments/assets/dce49f3a-61e5-4ba0-a2fe-41d192fd0e5d',
                'api' => array(
                    'rest' => 'https://btc-alpha.com/api',
                ),
                'www' => 'https://btc-alpha.com',
                'doc' => 'https://btc-alpha.github.io/api-docs',
                'fees' => 'https://btc-alpha.com/fees/',
                'referral' => 'https://btc-alpha.com/?r=123788',
            ),
            'api' => array(
                'public' => array(
                    'get' => array(
                        'currencies/',
                        'pairs/',
                        'orderbook/{pair_name}',
                        'exchanges/',
                        'charts/{pair}/{type}/chart/',
                        'ticker/',
                    ),
                ),
                'private' => array(
                    'get' => array(
                        'wallets/',
                        'orders/own/',
                        'order/{id}/',
                        'exchanges/own/',
                        'deposits/',
                        'withdraws/',
                    ),
                    'post' => array(
                        'order/',
                        'order-cancel/',
                    ),
                ),
            ),
            'fees' => array(
                'trading' => array(
                    'maker' => $this->parse_number('0.002'),
                    'taker' => $this->parse_number('0.002'),
                ),
                'funding' => array(
                    'withdraw' => array(),
                ),
            ),
            'commonCurrencies' => array(
                'CBC' => 'Cashbery',
            ),
            'features' => array(
                'spot' => array(
                    'sandbox' => false,
                    'createOrder' => array(
                        'marginMode' => false,
                        'triggerPrice' => false,
                        'triggerPriceType' => null,
                        'triggerDirection' => false,
                        'stopLossPrice' => false,
                        'takeProfitPrice' => false,
                        'attachedStopLossTakeProfit' => null,
                        'timeInForce' => array(
                            'IOC' => false,
                            'FOK' => false,
                            'PO' => false,
                            'GTD' => false,
                        ),
                        'hedged' => false,
                        'leverage' => false,
                        'marketBuyRequiresPrice' => false,
                        'marketBuyByCost' => false,
                        'selfTradePrevention' => false,
                        'trailing' => false,
                        'iceberg' => false,
                    ),
                    'createOrders' => null,
                    'fetchMyTrades' => array(
                        'marginMode' => false,
                        'limit' => 100,
                        'daysBack' => null,
                        'untilDays' => null,
                        'symbolRequired' => false,
                    ),
                    'fetchOrder' => array(
                        'marginMode' => false,
                        'trigger' => false,
                        'trailing' => false,
                        'symbolRequired' => false,
                    ),
                    'fetchOpenOrders' => array(
                        'marginMode' => false,
                        'limit' => 2000,
                        'trigger' => false,
                        'trailing' => false,
                        'symbolRequired' => false,
                    ),
                    'fetchOrders' => array(
                        'marginMode' => false,
                        'limit' => 2000,
                        'daysBack' => null,
                        'untilDays' => null,
                        'trigger' => false,
                        'trailing' => false,
                        'symbolRequired' => false,
                    ),
                    'fetchClosedOrders' => array(
                        'marginMode' => false,
                        'limit' => 2000,
                        'daysBack' => null,
                        'daysBackCanceled' => null,
                        'untilDays' => null,
                        'trigger' => false,
                        'trailing' => false,
                        'symbolRequired' => false,
                    ),
                    'fetchOHLCV' => array(
                        'limit' => 720,
                    ),
                ),
                'swap' => array(
                    'linear' => null,
                    'inverse' => null,
                ),
                'future' => array(
                    'linear' => null,
                    'inverse' => null,
                ),
            ),
            'precisionMode' => TICK_SIZE,
            'exceptions' => array(
                'exact' => array(),
                'broad' => array(
                    'Out of balance' => '\\ccxt\\InsufficientFunds', // array("date":1570599531.4814300537,"error":"Out of balance -9.99243661 BTC")
                ),
            ),
        ));
    }

    public function fetch_markets($params = array ()): array {
        /**
         * retrieves data on all markets for btcalpha
         *
         * @see https://btc-alpha.github.io/api-docs/#list-all-currencies
         *
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array[]} an array of objects representing market data
         */
        $response = $this->publicGetPairs ($params);
        //
        //    array(
        //        array(
        //            "name" => "1INCH_USDT",
        //            "currency1" => "1INCH",
        //            "currency2" => "USDT",
        //            "price_precision" => 4,
        //            "amount_precision" => 2,
        //            "minimum_order_size" => "0.01000000",
        //            "maximum_order_size" => "900000.00000000",
        //            "minimum_order_value" => "10.00000000",
        //            "liquidity_type" => 10
        //        ),
        //    )
        //
        return $this->parse_markets($response);
    }

    public function parse_market(array $market): array {
        $id = $this->safe_string($market, 'name');
        $baseId = $this->safe_string($market, 'currency1');
        $quoteId = $this->safe_string($market, 'currency2');
        $base = $this->safe_currency_code($baseId);
        $quote = $this->safe_currency_code($quoteId);
        $pricePrecision = $this->safe_string($market, 'price_precision');
        $priceLimit = $this->parse_precision($pricePrecision);
        $amountLimit = $this->safe_string($market, 'minimum_order_size');
        return array(
            'id' => $id,
            'symbol' => $base . '/' . $quote,
            'base' => $base,
            'quote' => $quote,
            'settle' => null,
            'baseId' => $baseId,
            'quoteId' => $quoteId,
            'settleId' => null,
            'type' => 'spot',
            'spot' => true,
            'margin' => false,
            'swap' => false,
            'future' => false,
            'option' => false,
            'active' => true,
            'contract' => false,
            'linear' => null,
            'inverse' => null,
            'contractSize' => 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(($pricePrecision))),
            ),
            'limits' => array(
                'leverage' => array(
                    'min' => null,
                    'max' => null,
                ),
                'amount' => array(
                    'min' => $this->parse_number($amountLimit),
                    'max' => $this->safe_number($market, 'maximum_order_size'),
                ),
                'price' => array(
                    'min' => $this->parse_number($priceLimit),
                    'max' => null,
                ),
                'cost' => array(
                    'min' => $this->parse_number(Precise::string_mul($priceLimit, $amountLimit)),
                    'max' => null,
                ),
            ),
            'created' => null,
            'info' => $market,
        );
    }

    public function fetch_tickers(?array $symbols = null, $params = array ()): array {
        /**
         *
         * @see https://btc-alpha.github.io/api-docs/#tickers
         *
         * fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
         * @param {string[]|null} $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~
         */
        $this->load_markets();
        $response = $this->publicGetTicker ($params);
        //
        //    array(
        //        array(
        //            "timestamp" => "1674658.445272",
        //            "pair" => "BTC_USDT",
        //            "last" => "22476.85",
        //            "diff" => "458.96",
        //            "vol" => "6660.847784",
        //            "high" => "23106.08",
        //            "low" => "22348.29",
        //            "buy" => "22508.46",
        //            "sell" => "22521.11"
        //        ),
        //        ...
        //    )
        //
        return $this->parse_tickers($response, $symbols);
    }

    public function fetch_ticker(string $symbol, $params = array ()): array {
        /**
         *
         * @see https://btc-alpha.github.io/api-docs/#tickers
         *
         * fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific $market
         * @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~
         */
        $this->load_markets();
        $market = $this->market($symbol);
        $request = array(
            'pair' => $market['id'],
        );
        $response = $this->publicGetTicker ($this->extend($request, $params));
        //
        //    {
        //        "timestamp" => "1674658.445272",
        //        "pair" => "BTC_USDT",
        //        "last" => "22476.85",
        //        "diff" => "458.96",
        //        "vol" => "6660.847784",
        //        "high" => "23106.08",
        //        "low" => "22348.29",
        //        "buy" => "22508.46",
        //        "sell" => "22521.11"
        //    }
        //
        return $this->parse_ticker($response, $market);
    }

    public function parse_ticker(array $ticker, ?array $market = null): array {
        //
        //    {
        //        "timestamp" => "1674658.445272",
        //        "pair" => "BTC_USDT",
        //        "last" => "22476.85",
        //        "diff" => "458.96",
        //        "vol" => "6660.847784",
        //        "high" => "23106.08",
        //        "low" => "22348.29",
        //        "buy" => "22508.46",
        //        "sell" => "22521.11"
        //    }
        //
        $timestampStr = $this->safe_string($ticker, 'timestamp');
        $timestamp = intval(Precise::string_mul($timestampStr, '1000000'));
        $marketId = $this->safe_string($ticker, 'pair');
        $market = $this->safe_market($marketId, $market, '_');
        $last = $this->safe_string($ticker, 'last');
        return $this->safe_ticker(array(
            'info' => $ticker,
            'symbol' => $market['symbol'],
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'high' => $this->safe_string($ticker, 'high'),
            'low' => $this->safe_string($ticker, 'low'),
            'bid' => $this->safe_string($ticker, 'buy'),
            'bidVolume' => null,
            'ask' => $this->safe_string($ticker, 'sell'),
            'askVolume' => null,
            'vwap' => null,
            'open' => null,
            'close' => $last,
            'last' => $last,
            'previousClose' => null,
            'change' => $this->safe_string($ticker, 'diff'),
            'percentage' => null,
            'average' => null,
            'baseVolume' => null,
            'quoteVolume' => $this->safe_string($ticker, 'vol'),
        ), $market);
    }

    public function fetch_order_book(string $symbol, ?int $limit = null, $params = array ()): array {
        /**
         *
         * @see https://btc-alpha.github.io/api-docs/#get-orderbook
         *
         * fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
         * @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
         */
        $this->load_markets();
        $market = $this->market($symbol);
        $request = array(
            'pair_name' => $market['id'],
        );
        if ($limit) {
            $request['limit_sell'] = $limit;
            $request['limit_buy'] = $limit;
        }
        $response = $this->publicGetOrderbookPairName ($this->extend($request, $params));
        return $this->parse_order_book($response, $market['symbol'], null, 'buy', 'sell', 'price', 'amount');
    }

    public function parse_bids_asks($bidasks, int|string $priceKey = 0, int|string $amountKey = 1, int|string $countOrIdKey = 2) {
        $result = array();
        for ($i = 0; $i < count($bidasks); $i++) {
            $bidask = $bidasks[$i];
            if ($bidask) {
                $result[] = $this->parse_bid_ask($bidask, $priceKey, $amountKey);
            }
        }
        return $result;
    }

    public function parse_trade(array $trade, ?array $market = null): array {
        //
        // fetchTrades (public)
        //
        //      {
        //          "id" => "202203440",
        //          "timestamp" => "1637856276.264215",
        //          "pair" => "AAVE_USDT",
        //          "price" => "320.79900000",
        //          "amount" => "0.05000000",
        //          "type" => "buy"
        //      }
        //
        // fetchMyTrades (private)
        //
        //      {
        //          "id" => "202203440",
        //          "timestamp" => "1637856276.264215",
        //          "pair" => "AAVE_USDT",
        //          "price" => "320.79900000",
        //          "amount" => "0.05000000",
        //          "type" => "buy",
        //          "my_side" => "buy"
        //      }
        //
        $marketId = $this->safe_string($trade, 'pair');
        $market = $this->safe_market($marketId, $market, '_');
        $timestampRaw = $this->safe_string($trade, 'timestamp');
        $timestamp = $this->parse_to_int(Precise::string_mul($timestampRaw, '1000000'));
        $priceString = $this->safe_string($trade, 'price');
        $amountString = $this->safe_string($trade, 'amount');
        $id = $this->safe_string($trade, 'id');
        $side = $this->safe_string_2($trade, 'my_side', 'type');
        return $this->safe_trade(array(
            'id' => $id,
            'info' => $trade,
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'symbol' => $market['symbol'],
            'order' => $id,
            'type' => 'limit',
            'side' => $side,
            'takerOrMaker' => null,
            'price' => $priceString,
            'amount' => $amountString,
            'cost' => null,
            'fee' => null,
        ), $market);
    }

    public function fetch_trades(string $symbol, ?int $since = null, ?int $limit = null, $params = array ()): array {
        /**
         * get the list of most recent $trades for a particular $symbol
         *
         * @see https://btc-alpha.github.io/api-docs/#list-all-exchanges
         *
         * @param {string} $symbol unified $symbol of the $market to fetch $trades for
         * @param {int} [$since] timestamp in ms of the earliest trade to fetch
         * @param {int} [$limit] the maximum amount of $trades to fetch
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {Trade[]} a list of ~@link https://docs.ccxt.com/#/?id=public-$trades trade structures~
         */
        $this->load_markets();
        $market = null;
        $request = array();
        if ($symbol !== null) {
            $market = $this->market($symbol);
            $request['pair'] = $market['id'];
        }
        if ($limit !== null) {
            $request['limit'] = $limit;
        }
        $trades = $this->publicGetExchanges ($this->extend($request, $params));
        return $this->parse_trades($trades, $market, $since, $limit);
    }

    public function fetch_deposits(?string $code = null, ?int $since = null, ?int $limit = null, $params = array ()): array {
        /**
         * fetch all deposits made to an account
         *
         * @see https://btc-alpha.github.io/api-docs/#list-own-deposits
         *
         * @param {string} $code unified $currency $code
         * @param {int} [$since] the earliest time in ms to fetch deposits for
         * @param {int} [$limit] the maximum number of deposits structures to retrieve
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?id=transaction-structure transaction structures~
         */
        $this->load_markets();
        $currency = null;
        if ($code !== null) {
            $currency = $this->currency($code);
        }
        $response = $this->privateGetDeposits ($params);
        //
        //     array(
        //         {
        //             "timestamp" => 1485363039.18359,
        //             "id" => 317,
        //             "currency" => "BTC",
        //             "amount" => 530.00000000
        //         }
        //     )
        //
        return $this->parse_transactions($response, $currency, $since, $limit, array( 'type' => 'deposit' ));
    }

    public function fetch_withdrawals(?string $code = null, ?int $since = null, ?int $limit = null, $params = array ()): array {
        /**
         * fetch all withdrawals made from an account
         *
         * @see https://btc-alpha.github.io/api-docs/#list-own-made-withdraws
         *
         * @param {string} $code unified $currency $code
         * @param {int} [$since] the earliest time in ms to fetch withdrawals for
         * @param {int} [$limit] the maximum number of withdrawals structures to retrieve
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?id=transaction-structure transaction structures~
         */
        $this->load_markets();
        $currency = null;
        $request = array();
        if ($code !== null) {
            $currency = $this->currency($code);
            $request['currency_id'] = $currency['id'];
        }
        $response = $this->privateGetWithdraws ($this->extend($request, $params));
        //
        //     array(
        //         {
        //             "id" => 403,
        //             "timestamp" => 1485363466.868539,
        //             "currency" => "BTC",
        //             "amount" => 0.53000000,
        //             "status" => 20
        //         }
        //     )
        //
        return $this->parse_transactions($response, $currency, $since, $limit, array( 'type' => 'withdrawal' ));
    }

    public function parse_transaction(array $transaction, ?array $currency = null): array {
        //
        //  deposit
        //      {
        //          "timestamp" => 1485363039.18359,
        //          "id" => 317,
        //          "currency" => "BTC",
        //          "amount" => 530.00000000
        //      }
        //
        //  withdrawal
        //      {
        //          "id" => 403,
        //          "timestamp" => 1485363466.868539,
        //          "currency" => "BTC",
        //          "amount" => 0.53000000,
        //          "status" => 20
        //      }
        //
        $timestamp = $this->safe_timestamp($transaction, 'timestamp');
        $currencyId = $this->safe_string($transaction, 'currency');
        $statusId = $this->safe_string($transaction, 'status');
        return array(
            'id' => $this->safe_string($transaction, 'id'),
            'info' => $transaction,
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'network' => null,
            'address' => null,
            'addressTo' => null,
            'addressFrom' => null,
            'tag' => null,
            'tagTo' => null,
            'tagFrom' => null,
            'currency' => $this->safe_currency_code($currencyId, $currency),
            'amount' => $this->safe_number($transaction, 'amount'),
            'txid' => null,
            'type' => null,
            'status' => $this->parse_transaction_status($statusId),
            'comment' => null,
            'internal' => null,
            'fee' => null,
            'updated' => null,
        );
    }

    public function parse_transaction_status(?string $status) {
        $statuses = array(
            '10' => 'pending',  // New
            '20' => 'pending',  // Verified, waiting for approving
            '30' => 'ok',       // Approved by moderator
            '40' => 'failed',   // Refused by moderator. See your email for more details
            '50' => 'canceled', // Cancelled by user
        );
        return $this->safe_string($statuses, $status, $status);
    }

    public function parse_ohlcv($ohlcv, ?array $market = null): array {
        //
        //     {
        //         "time":1591296000,
        //         "open":0.024746,
        //         "close":0.024728,
        //         "low":0.024728,
        //         "high":0.024753,
        //         "volume":16.624
        //     }
        //
        return array(
            $this->safe_timestamp($ohlcv, 'time'),
            $this->safe_number($ohlcv, 'open'),
            $this->safe_number($ohlcv, 'high'),
            $this->safe_number($ohlcv, 'low'),
            $this->safe_number($ohlcv, 'close'),
            $this->safe_number($ohlcv, 'volume'),
        );
    }

    public function fetch_ohlcv(string $symbol, $timeframe = '5m', ?int $since = null, ?int $limit = null, $params = array ()): array {
        /**
         * fetches historical candlestick data containing the open, high, low, and close price, and the volume of a $market
         *
         * @see https://btc-alpha.github.io/api-docs/#charts
         *
         * @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
         */
        $this->load_markets();
        $market = $this->market($symbol);
        $request = array(
            'pair' => $market['id'],
            'type' => $this->safe_string($this->timeframes, $timeframe, $timeframe),
        );
        if ($limit !== null) {
            $request['limit'] = $limit;
        }
        if ($since !== null) {
            $request['since'] = $this->parse_to_int($since / 1000);
        }
        $response = $this->publicGetChartsPairTypeChart ($this->extend($request, $params));
        //
        //     array(
        //         array("time":1591296000,"open":0.024746,"close":0.024728,"low":0.024728,"high":0.024753,"volume":16.624),
        //         array("time":1591295700,"open":0.024718,"close":0.02475,"low":0.024711,"high":0.02475,"volume":31.645),
        //         array("time":1591295400,"open":0.024721,"close":0.024717,"low":0.024711,"high":0.02473,"volume":65.071)
        //     )
        //
        return $this->parse_ohlcvs($response, $market, $timeframe, $since, $limit);
    }

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

    public function fetch_balance($params = array ()): array {
        /**
         * query for balance and get the amount of funds available for trading or funds locked in orders
         *
         * @see https://btc-alpha.github.io/api-docs/#list-own-wallets
         *
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a ~@link https://docs.ccxt.com/#/?id=balance-structure balance structure~
         */
        $this->load_markets();
        $response = $this->privateGetWallets ($params);
        return $this->parse_balance($response);
    }

    public function parse_order_status(?string $status) {
        $statuses = array(
            '1' => 'open',
            '2' => 'canceled',
            '3' => 'closed',
        );
        return $this->safe_string($statuses, $status, $status);
    }

    public function parse_order(array $order, ?array $market = null): array {
        //
        // fetchClosedOrders / fetchOrder
        //     {
        //       "id" => "923763073",
        //       "date" => "1635451090368",
        //       "type" => "sell",
        //       "pair" => "XRP_USDT",
        //       "price" => "1.00000000",
        //       "amount" => "0.00000000",
        //       "status" => "3",
        //       "amount_filled" => "10.00000000",
        //       "amount_original" => "10.0"
        //       "trades" => array(),
        //     }
        //
        // createOrder
        //     {
        //       "success" => true,
        //       "date" => "1635451754.497541",
        //       "type" => "sell",
        //       "oid" => "923776755",
        //       "price" => "1.0",
        //       "amount" => "10.0",
        //       "amount_filled" => "0.0",
        //       "amount_original" => "10.0",
        //       "trades" => array()
        //     }
        //
        $marketId = $this->safe_string($order, 'pair');
        $market = $this->safe_market($marketId, $market, '_');
        $symbol = $market['symbol'];
        $success = $this->safe_bool($order, 'success', false);
        $timestamp = null;
        if ($success) {
            $timestamp = $this->safe_timestamp($order, 'date');
        } else {
            $timestamp = $this->safe_integer($order, 'date');
        }
        $price = $this->safe_string($order, 'price');
        $remaining = $this->safe_string($order, 'amount');
        $filled = $this->safe_string($order, 'amount_filled');
        $amount = $this->safe_string($order, 'amount_original');
        $status = $this->parse_order_status($this->safe_string($order, 'status'));
        $id = $this->safe_string_n($order, array( 'oid', 'id', 'order' ));
        $trades = $this->safe_value($order, 'trades');
        $side = $this->safe_string_2($order, 'my_side', 'type');
        return $this->safe_order(array(
            'id' => $id,
            'clientOrderId' => null,
            'datetime' => $this->iso8601($timestamp),
            'timestamp' => $timestamp,
            'status' => $status,
            'symbol' => $symbol,
            'type' => 'limit',
            'timeInForce' => null,
            'postOnly' => null,
            'side' => $side,
            'price' => $price,
            'triggerPrice' => null,
            'cost' => null,
            'amount' => $amount,
            'filled' => $filled,
            'remaining' => $remaining,
            'trades' => $trades,
            'fee' => null,
            'info' => $order,
            'lastTradeTimestamp' => null,
            'average' => null,
        ), $market);
    }

    public function create_order(string $symbol, string $type, string $side, float $amount, ?float $price = null, $params = array ()) {
        /**
         *
         * @see https://btc-alpha.github.io/api-docs/#create-$order
         *
         * create a trade $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
         * @return {array} an ~@link https://docs.ccxt.com/#/?id=$order-structure $order structure~
         */
        if ($type === 'market') {
            throw new InvalidOrder($this->id . ' only limits orders are supported');
        }
        $this->load_markets();
        $market = $this->market($symbol);
        $request = array(
            'pair' => $market['id'],
            'type' => $side,
            'amount' => $amount,
            'price' => $this->price_to_precision($symbol, $price),
        );
        $response = $this->privatePostOrder ($this->extend($request, $params));
        if (!$response['success']) {
            throw new InvalidOrder($this->id . ' ' . $this->json($response));
        }
        $order = $this->parse_order($response, $market);
        $orderAmount = (string) $order['amount'];
        $amount = Precise::string_gt($orderAmount, '0') ? $order['amount'] : $amount;
        $order['amount'] = $this->parse_number($amount);
        return $order;
    }

    public function cancel_order(string $id, ?string $symbol = null, $params = array ()) {
        /**
         *
         * @see https://btc-alpha.github.io/api-docs/#cancel-order
         *
         * cancels an open order
         * @param {string} $id order $id
         * @param {string} $symbol unified $symbol of the market the order was made in
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} An ~@link https://docs.ccxt.com/#/?$id=order-structure order structure~
         */
        $request = array(
            'order' => $id,
        );
        $response = $this->privatePostOrderCancel ($this->extend($request, $params));
        //
        //    {
        //        "order" => 63568
        //    }
        //
        return $this->parse_order($response);
    }

    public function fetch_order(string $id, ?string $symbol = null, $params = array ()) {
        /**
         *
         * @see https://btc-alpha.github.io/api-docs/#retrieve-single-$order
         *
         * fetches information on an $order made by the user
         * @param {string} $id the $order $id
         * @param {string} $symbol not used by btcalpha 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~
         */
        $this->load_markets();
        $request = array(
            'id' => $id,
        );
        $order = $this->privateGetOrderId ($this->extend($request, $params));
        return $this->parse_order($order);
    }

    public function fetch_orders(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()): array {
        /**
         *
         * @see https://btc-alpha.github.io/api-docs/#list-own-$orders
         *
         * fetches information on multiple $orders made by the user
         * @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~
         */
        $this->load_markets();
        $request = array();
        $market = null;
        if ($symbol !== null) {
            $market = $this->market($symbol);
            $request['pair'] = $market['id'];
        }
        if ($limit !== null) {
            $request['limit'] = $limit;
        }
        $orders = $this->privateGetOrdersOwn ($this->extend($request, $params));
        return $this->parse_orders($orders, $market, $since, $limit);
    }

    public function fetch_open_orders(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()): array {
        /**
         * fetch all unfilled currently open orders
         *
         * @see https://btc-alpha.github.io/api-docs/#list-own-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~
         */
        $request = array(
            'status' => '1',
        );
        return $this->fetch_orders($symbol, $since, $limit, $this->extend($request, $params));
    }

    public function fetch_closed_orders(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()): array {
        /**
         * fetches information on multiple closed orders made by the user
         *
         * @see https://btc-alpha.github.io/api-docs/#list-own-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(
            'status' => '3',
        );
        return $this->fetch_orders($symbol, $since, $limit, $this->extend($request, $params));
    }

    public function fetch_my_trades(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()) {
        /**
         * fetch all $trades made by the user
         *
         * @see https://btc-alpha.github.io/api-docs/#list-own-exchanges
         *
         * @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~
         */
        $this->load_markets();
        $request = array();
        if ($symbol !== null) {
            $market = $this->market($symbol);
            $request['pair'] = $market['id'];
        }
        if ($limit !== null) {
            $request['limit'] = $limit;
        }
        $trades = $this->privateGetExchangesOwn ($this->extend($request, $params));
        return $this->parse_trades($trades, null, $since, $limit);
    }

    public function nonce() {
        return $this->milliseconds();
    }

    public function sign($path, $api = 'public', $method = 'GET', $params = array (), $headers = null, $body = null) {
        $query = $this->urlencode($this->keysort($this->omit($params, $this->extract_params($path))));
        $url = $this->urls['api']['rest'] . '/';
        if ($path !== 'charts/{pair}/{type}/chart/') {
            $url .= 'v1/';
        }
        $url .= $this->implode_params($path, $params);
        $headers = array( 'Accept' => 'application/json' );
        if ($api === 'public') {
            if (strlen($query)) {
                $url .= '?' . $query;
            }
        } else {
            $this->check_required_credentials();
            $payload = $this->apiKey;
            if ($method === 'POST') {
                $headers['Content-Type'] = 'application/x-www-form-urlencoded';
                $body = $query;
                $payload .= $body;
            } elseif (strlen($query)) {
                $url .= '?' . $query;
            }
            $headers['X-KEY'] = $this->apiKey;
            $headers['X-SIGN'] = $this->hmac($this->encode($payload), $this->encode($this->secret), 'sha256');
            $headers['X-NONCE'] = (string) $this->nonce();
        }
        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; // fallback to default $error handler
        }
        //
        //     array("date":1570599531.4814300537,"error":"Out of balance -9.99243661 BTC")
        //
        $error = $this->safe_string($response, 'error');
        if ($error !== null) {
            $feedback = $this->id . ' ' . $body;
            $this->throw_exactly_matched_exception($this->exceptions['exact'], $error, $feedback);
            $this->throw_broadly_matched_exception($this->exceptions['broad'], $error, $feedback);
            throw new ExchangeError($feedback); // unknown $error
        }
        return null;
    }
}
