text: # -*- coding: utf-8 -*-
  
  # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
  
  from ccxt.base.exchange import Exchange
  import math
  import json
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import AuthenticationError
  from ccxt.base.errors import InsufficientFunds
  from ccxt.base.errors import InvalidOrder
  from ccxt.base.errors import OrderNotFound
  
  
  class okcoinusd (Exchange):
  
      def describe(self):
          return self.deep_extend(super(okcoinusd, self).describe(), {
              'id': 'okcoinusd',
              'name': 'OKCoin USD',
              'countries': ['CN', 'US'],
              'version': 'v1',
              'rateLimit': 1000,  # up to 3000 requests per 5 minutes ≈ 600 requests per minute ≈ 10 requests per second ≈ 100 ms
              'has': {
                  'CORS': False,
                  'fetchOHLCV': True,
                  'fetchOrder': True,
                  'fetchOrders': False,
                  'fetchOpenOrders': True,
                  'fetchClosedOrders': True,
                  'withdraw': True,
                  'futures': False,
              },
              'extension': '.do',  # appended to endpoint URL
              'timeframes': {
                  '1m': '1min',
                  '3m': '3min',
                  '5m': '5min',
                  '15m': '15min',
                  '30m': '30min',
                  '1h': '1hour',
                  '2h': '2hour',
                  '4h': '4hour',
                  '6h': '6hour',
                  '12h': '12hour',
                  '1d': '1day',
                  '3d': '3day',
                  '1w': '1week',
              },
              'api': {
                  'web': {
                      'get': [
                          'spot/markets/currencies',
                          'spot/markets/products',
                      ],
                  },
                  'public': {
                      'get': [
                          'depth',
                          'exchange_rate',
                          'future_depth',
                          'future_estimated_price',
                          'future_hold_amount',
                          'future_index',
                          'future_kline',
                          'future_price_limit',
                          'future_ticker',
                          'future_trades',
                          'kline',
                          'otcs',
                          'ticker',
                          'tickers',
                          'trades',
                      ],
                  },
                  'private': {
                      'post': [
                          'account_records',
                          'batch_trade',
                          'borrow_money',
                          'borrow_order_info',
                          'borrows_info',
                          'cancel_borrow',
                          'cancel_order',
                          'cancel_otc_order',
                          'cancel_withdraw',
                          'future_batch_trade',
                          'future_cancel',
                          'future_devolve',
                          'future_explosive',
                          'future_order_info',
                          'future_orders_info',
                          'future_position',
                          'future_position_4fix',
                          'future_trade',
                          'future_trades_history',
                          'future_userinfo',
                          'future_userinfo_4fix',
                          'lend_depth',
                          'order_fee',
                          'order_history',
                          'order_info',
                          'orders_info',
                          'otc_order_history',
                          'otc_order_info',
                          'repayment',
                          'submit_otc_order',
                          'trade',
                          'trade_history',
                          'trade_otc_order',
                          'withdraw',
                          'withdraw_info',
                          'unrepayments_info',
                          'userinfo',
                      ],
                  },
              },
              'urls': {
                  'logo': 'https://user-images.githubusercontent.com/1294454/27766791-89ffb502-5ee5-11e7-8a5b-c5950b68ac65.jpg',
                  'api': {
                      'web': 'https://www.okcoin.com/v2',
                      'public': 'https://www.okcoin.com/api',
                      'private': 'https://www.okcoin.com/api',
                  },
                  'www': 'https://www.okcoin.com',
                  'doc': [
                      'https://www.okcoin.com/rest_getStarted.html',
                      'https://www.npmjs.com/package/okcoin.com',
                  ],
              },
              'fees': {
                  'trading': {
                      'taker': 0.002,
                      'maker': 0.002,
                  },
              },
              'exceptions': {
                  '1009': OrderNotFound,  # for spot markets, cancelling closed order
                  '1051': OrderNotFound,  # for spot markets, cancelling "just closed" order
                  '1019': OrderNotFound,  # order closed?
                  '20015': OrderNotFound,  # for future markets
                  '1013': InvalidOrder,  # no contract type(PR-1101)
                  '1027': InvalidOrder,  # createLimitBuyOrder(symbol, 0, 0): Incorrect parameter may exceeded limits
                  '1002': InsufficientFunds,  # "The transaction amount exceed the balance"
                  '1050': InvalidOrder,  # returned when trying to cancel an order that was filled or canceled previously
                  '10000': ExchangeError,  # createLimitBuyOrder(symbol, None, None)
                  '10005': AuthenticationError,  # bad apiKey
                  '10008': ExchangeError,  # Illegal URL parameter
              },
              'options': {
                  'warnOnFetchOHLCVLimitArgument': True,
              },
          })
  
      def fetch_markets(self):
          response = self.webGetSpotMarketsProducts()
          markets = response['data']
          result = []
          futureMarkets = {
              'BCH/USD': True,
              'BTC/USD': True,
              'ETC/USD': True,
              'ETH/USD': True,
              'LTC/USD': True,
              'XRP/USD': True,
              'EOS/USD': True,
              'BTG/USD': True,
          }
          for i in range(0, len(markets)):
              id = markets[i]['symbol']
              baseId, quoteId = id.split('_')
              baseIdUppercase = baseId.upper()
              quoteIdUppercase = quoteId.upper()
              base = self.common_currency_code(baseIdUppercase)
              quote = self.common_currency_code(quoteIdUppercase)
              symbol = base + '/' + quote
              precision = {
                  'amount': markets[i]['maxSizeDigit'],
                  'price': markets[i]['maxPriceDigit'],
              }
              lot = math.pow(10, -precision['amount'])
              minAmount = markets[i]['minTradeSize']
              minPrice = math.pow(10, -precision['price'])
              active = (markets[i]['online'] != 0)
              baseNumericId = markets[i]['baseCurrency']
              quoteNumericId = markets[i]['quoteCurrency']
              market = self.extend(self.fees['trading'], {
                  'id': id,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'baseNumericId': baseNumericId,
                  'quoteNumericId': quoteNumericId,
                  'info': markets[i],
                  'type': 'spot',
                  'spot': True,
                  'future': False,
                  'lot': lot,
                  'active': active,
                  'precision': precision,
                  'limits': {
                      'amount': {
                          'min': minAmount,
                          'max': None,
                      },
                      'price': {
                          'min': minPrice,
                          'max': None,
                      },
                      'cost': {
                          'min': minAmount * minPrice,
                          'max': None,
                      },
                  },
              })
              result.append(market)
              futureQuote = 'USD' if (market['quote'] == 'USDT') else market['quote']
              futureSymbol = market['base'] + '/' + futureQuote
              if (self.has['futures']) and(futureSymbol in list(futureMarkets.keys())):
                  result.append(self.extend(market, {
                      'quote': 'USD',
                      'symbol': market['base'] + '/USD',
                      'id': market['id'].replace('usdt', 'usd'),
                      'quoteId': market['quoteId'].replace('usdt', 'usd'),
                      'type': 'future',
                      'spot': False,
                      'future': True,
                  }))
          return result
  
      def fetch_order_book(self, symbol, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          method = 'publicGet'
          request = {
              'symbol': market['id'],
          }
          if limit is not None:
              request['size'] = limit
          if market['future']:
              method += 'Future'
              request['contract_type'] = 'this_week'  # next_week, quarter
          method += 'Depth'
          orderbook = getattr(self, method)(self.extend(request, params))
          return self.parse_order_book(orderbook)
  
      def parse_ticker(self, ticker, market=None):
          timestamp = ticker['timestamp']
          symbol = None
          if not market:
              if 'symbol' in ticker:
                  marketId = ticker['symbol']
                  if marketId in self.markets_by_id:
                      market = self.markets_by_id[marketId]
          if market:
              symbol = market['symbol']
          last = self.safe_float(ticker, 'last')
          return {
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': self.safe_float(ticker, 'high'),
              'low': self.safe_float(ticker, 'low'),
              'bid': self.safe_float(ticker, 'buy'),
              'bidVolume': None,
              'ask': self.safe_float(ticker, 'sell'),
              'askVolume': None,
              'vwap': None,
              'open': None,
              'close': last,
              'last': last,
              'previousClose': None,
              'change': None,
              'percentage': None,
              'average': None,
              'baseVolume': self.safe_float(ticker, 'vol'),
              'quoteVolume': None,
              'info': ticker,
          }
  
      def fetch_ticker(self, symbol, params={}):
          '''
          :param symbol: spot example: EOS/USDT, future example:EOS/USD
          :param params:
          :return:
          '''
          self.load_markets()
          market = self.market(symbol)
          method = 'publicGet'
          request = {
              'symbol': market['id'],
          }
          if market['future']:
              method += 'Future'
              request['contract_type'] = 'this_week'  # next_week, quarter
          method += 'Ticker'
          response = getattr(self, method)(self.extend(request, params))
          ticker = self.safe_value(response, 'ticker')
          if ticker is None:
              raise ExchangeError(self.id + ' fetchTicker returned an empty response: ' + self.json(response))
          timestamp = self.safe_integer(response, 'date')
          if timestamp is not None:
              timestamp *= 1000
              ticker = self.extend(ticker, {'timestamp': timestamp})
          return self.parse_ticker(ticker, market)
  
      def parse_trade(self, trade, market=None):
          symbol = None
          if market:
              symbol = market['symbol']
          return {
              'info': trade,
              'timestamp': trade['date_ms'],
              'datetime': self.iso8601(trade['date_ms']),
              'symbol': symbol,
              'id': str(trade['tid']),
              'order': None,
              'type': None,
              'side': trade['type'],
              'price': self.safe_float(trade, 'price'),
              'amount': self.safe_float(trade, 'amount'),
          }
  
      def fetch_trades(self, symbol, since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          method = 'publicGet'
          request = {
              'symbol': market['id'],
          }
          if market['future']:
              method += 'Future'
              request['contract_type'] = 'this_week'  # next_week, quarter
          method += 'Trades'
          response = getattr(self, method)(self.extend(request, params))
          return self.parse_trades(response, market, since, limit)
  
      def parse_ohlcv(self, ohlcv, market=None, timeframe='1m', since=None, limit=None):
          numElements = len(ohlcv)
          volumeIndex = 6 if (numElements > 6) else 5
          return [
              ohlcv[0],  # timestamp
              ohlcv[1],  # Open
              ohlcv[2],  # High
              ohlcv[3],  # Low
              ohlcv[4],  # Close
              # ohlcv[5],  # quote volume
              # ohlcv[6],  # base volume
              ohlcv[volumeIndex],  # okex will return base volume in the 7th element for future markets
          ]
  
      def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          method = 'publicGet'
          request = {
              'symbol': market['id'],
              'type': self.timeframes[timeframe],
          }
          if market['future']:
              method += 'Future'
              request['contract_type'] = 'this_week'  # next_week, quarter
          method += 'Kline'
          if limit is not None:
              if self.options['warnOnFetchOHLCVLimitArgument']:
                  raise ExchangeError(self.id + ' fetchOHLCV counts "limit" candles from current time backwards, therefore the "limit" argument for ' + self.id + ' is disabled. Set ' + self.id + '.options["warnOnFetchOHLCVLimitArgument"] = False to suppress self warning message.')
              request['size'] = int(limit)  # max is 1440 candles
          if since is not None:
              request['since'] = since
          else:
              request['since'] = self.milliseconds() - 86400000  # last 24 hours
          response = getattr(self, method)(self.extend(request, params))
          return self.parse_ohlcvs(response, market, timeframe, since, limit)
  
      def fetch_balance(self, params={}):
          self.load_markets()
          response = self.privatePostUserinfo()
          balances = response['info']['funds']
          result = {'info': response}
          ids = list(self.currencies_by_id.keys())
          for i in range(0, len(ids)):
              id = ids[i]
              code = self.currencies_by_id[id]['code']
              account = self.account()
              account['free'] = self.safe_float(balances['free'], id, 0.0)
              account['used'] = self.safe_float(balances['freezed'], id, 0.0)
              account['total'] = self.sum(account['free'], account['used'])
              result[code] = account
          return self.parse_balance(result)
  
      def fetch_future_balance(self, params={}):
          '''
          :param params:
          :return: example retern val:
          {'bch': {'account_rights': 0,
            'keep_deposit': 0,
            'profit_real': 0,
            'profit_unreal': 0,
            'risk_rate': 10000},
           'btc': {'account_rights': 0,
            'keep_deposit': 0,
            'profit_real': 0,
            'profit_unreal': 0,
            'risk_rate': 10000},
            ...
           }
          '''
          self.load_markets()
          response = self.privatePostFutureUserinfo()
          return response['info']
  
      def fetch_future_position(self, symbol, contract_type=None):
          '''
          :param symbol:  EOS/USD or eos_usd
          :param contract_type: this_week, next_week, quarter. If None, return all.
          :return: example return val:
          {'force_liqu_price': '0.000',
           'holding': [{'buy_amount': 0,
                        'buy_available': 0,
                        'buy_price_avg': 0,
                        'buy_price_cost': 0,
                        'buy_profit_real': 0,
                        'contract_id': 201805110200054,
                        'contract_type': 'this_week',
                        'create_date': 1525392600000,
                        'lever_rate': 10,
                        'sell_amount': 4000,
                        'sell_available': 4000,
                        'sell_price_avg': 18.0483803,
                        'sell_price_cost': 17.90034047,
                        'sell_profit_real': -0.41249864,
                        'symbol': 'eos_usd'}],
           'result': True}
          '''
          self.load_markets()
          # for uniformality, allow EOS/USD
          if '/' in symbol:
              symbol = '_'.join([x.lower() for x in symbol.split('/')])
          params = {'symbol':symbol}
          if contract_type != None:
              params['contract_type'] = contract_type
          response = self.privatePostFuturePosition(params=params)
          return response
  
      def create_order(self, symbol, type, side, amount, price=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          method = 'privatePost'
          order = {
              'symbol': market['id'],
              'type': side,
          }
          if market['future']:
              method += 'Future'
              order = self.extend(order, {
                  'contract_type': 'this_week',  # next_week, quarter
                  'match_price': 0,  # match best counter party price? 0 or 1, ignores price if 1
                  'lever_rate': 10,  # leverage rate value: 10 or 20(10 by default)
                  'price': price,
                  'amount': amount,
              })
          else:
              if type == 'limit':
                  order['price'] = price
                  order['amount'] = amount
              else:
                  order['type'] += '_market'
                  if side == 'buy':
                      order['price'] = self.safe_float(params, 'cost')
                      if not order['price']:
                          raise ExchangeError(self.id + ' market buy orders require an additional cost parameter, cost = price * amount')
                  else:
                      order['amount'] = amount
          params = self.omit(params, 'cost')
          method += 'Trade'
          response = getattr(self, method)(self.extend(order, params))
          timestamp = self.milliseconds()
          return {
              'info': response,
              'id': str(response['order_id']),
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': None,
              'status': None,
              'symbol': symbol,
              'type': type,
              'side': side,
              'price': price,
              'amount': amount,
              'filled': None,
              'remaining': None,
              'cost': None,
              'trades': None,
              'fee': None,
          }
  
      def cancel_order(self, id, symbol=None, params={}):
          if not symbol:
              raise ExchangeError(self.id + ' cancelOrder() requires a symbol argument')
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
              'order_id': id,
          }
          method = 'privatePost'
          if market['future']:
              method += 'FutureCancel'
              request['contract_type'] = 'this_week'  # next_week, quarter
          else:
              method += 'CancelOrder'
          response = getattr(self, method)(self.extend(request, params))
          return response
  
      def parse_order_status(self, status):
          if status == -1:
              return 'canceled'
          if status == 0:
              return 'open'
          if status == 1:
              return 'open'
          if status == 2:
              return 'closed'
          if status == 3:
              return 'open'
          if status == 4:
              return 'canceled'
          return status
  
      def parse_order_side(self, side):
          if side == 1:
              return 'buy'  # open long position
          if side == 2:
              return 'sell'  # open short position
          if side == 3:
              return 'sell'  # liquidate long position
          if side == 4:
              return 'buy'  # liquidate short position
          return side
  
      def parse_order(self, order, market=None):
          side = None
          type = None
          if 'type' in order:
              if (order['type'] == 'buy') or (order['type'] == 'sell'):
                  side = order['type']
                  type = 'limit'
              elif order['type'] == 'buy_market':
                  side = 'buy'
                  type = 'market'
              elif order['type'] == 'sell_market':
                  side = 'sell'
                  type = 'market'
              else:
                  side = self.parse_order_side(order['type'])
                  if ('contract_name' in list(order.keys())) or ('lever_rate' in list(order.keys())):
                      type = 'margin'
          status = self.parse_order_status(order['status'])
          symbol = None
          if not market:
              if 'symbol' in order:
                  if order['symbol'] in self.markets_by_id:
                      market = self.markets_by_id[order['symbol']]
          if market:
              symbol = market['symbol']
          timestamp = None
          createDateField = self.get_create_date_field()
          if createDateField in order:
              timestamp = order[createDateField]
          amount = self.safe_float(order, 'amount')
          filled = self.safe_float(order, 'deal_amount')
          remaining = amount - filled
          if type == 'market':
              remaining = 0
          average = self.safe_float(order, 'avg_price')
          # https://github.com/ccxt/ccxt/issues/2452
          average = self.safe_float(order, 'price_avg', average)
          cost = average * filled
          result = {
              'info': order,
              'id': str(order['order_id']),
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': None,
              'symbol': symbol,
              'type': type,
              'side': side,
              'price': order['price'],
              'average': average,
              'cost': cost,
              'amount': amount,
              'filled': filled,
              'remaining': remaining,
              'status': status,
              'fee': None,
          }
          return result
  
      def get_create_date_field(self):
          # needed for derived exchanges
          # allcoin typo create_data instead of create_date
          return 'create_date'
  
      def get_orders_field(self):
          # needed for derived exchanges
          # allcoin typo order instead of orders(expected based on their API docs)
          return 'orders'
  
      def fetch_order(self, id, symbol=None, params={}):
          if not symbol:
              raise ExchangeError(self.id + ' fetchOrder requires a symbol parameter')
          self.load_markets()
          market = self.market(symbol)
          method = 'privatePost'
          request = {
              'order_id': id,
              'symbol': market['id'],
              # 'status': 0,  # 0 for unfilled orders, 1 for filled orders
              # 'current_page': 1,  # current page number
              # 'page_length': 200,  # number of orders returned per page, maximum 200
          }
          if market['future']:
              method += 'Future'
              request['contract_type'] = 'this_week'  # next_week, quarter
          method += 'OrderInfo'
          response = getattr(self, method)(self.extend(request, params))
          ordersField = self.get_orders_field()
          numOrders = len(response[ordersField])
          if numOrders > 0:
              return self.parse_order(response[ordersField][0])
          raise OrderNotFound(self.id + ' order ' + id + ' not found')
  
      def fetch_orders(self, symbol=None, since=None, limit=None, params={}):
          if not symbol:
              raise ExchangeError(self.id + ' fetchOrders requires a symbol parameter')
          self.load_markets()
          market = self.market(symbol)
          method = 'privatePost'
          request = {
              'symbol': market['id'],
          }
          order_id_in_params = ('order_id' in list(params.keys()))
          if market['future']:
              method += 'FutureOrdersInfo'
              request['contract_type'] = 'this_week'  # next_week, quarter
              if not order_id_in_params:
                  raise ExchangeError(self.id + ' fetchOrders() requires order_id param for futures market ' + symbol + '(a string of one or more order ids, comma-separated)')
          else:
              status = None
              if 'type' in params:
                  status = params['type']
              elif 'status' in params:
                  status = params['status']
              else:
                  name = 'type' if order_id_in_params else 'status'
                  raise ExchangeError(self.id + ' fetchOrders() requires ' + name + ' param for spot market ' + symbol + '(0 - for unfilled orders, 1 - for filled/canceled orders)')
              if order_id_in_params:
                  method += 'OrdersInfo'
                  request = self.extend(request, {
                      'type': status,
                      'order_id': params['order_id'],
                  })
              else:
                  method += 'OrderHistory'
                  request = self.extend(request, {
                      'status': status,
                      'current_page': 1,  # current page number
                      'page_length': 200,  # number of orders returned per page, maximum 200
                  })
              params = self.omit(params, ['type', 'status'])
          response = getattr(self, method)(self.extend(request, params))
          ordersField = self.get_orders_field()
          return self.parse_orders(response[ordersField], market, since, limit)
  
      def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
          open = 0  # 0 for unfilled orders, 1 for filled orders
          return self.fetch_orders(symbol, since, limit, self.extend({
              'status': open,
          }, params))
  
      def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}):
          closed = 1  # 0 for unfilled orders, 1 for filled orders
          orders = self.fetch_orders(symbol, since, limit, self.extend({
              'status': closed,
          }, params))
          return orders
  
      def withdraw(self, code, amount, address, tag=None, params={}):
          self.check_address(address)
          self.load_markets()
          currency = self.currency(code)
          # if amount < 0.01:
          #     raise ExchangeError(self.id + ' withdraw() requires amount > 0.01')
          # for some reason they require to supply a pair of currencies for withdrawing one currency
          currencyId = currency['id'] + '_usd'
          request = {
              'symbol': currencyId,
              'withdraw_address': address,
              'withdraw_amount': amount,
              'target': 'address',  # or 'okcn', 'okcom', 'okex'
          }
          query = params
          if 'chargefee' in query:
              request['chargefee'] = query['chargefee']
              query = self.omit(query, 'chargefee')
          else:
              raise ExchangeError(self.id + ' withdraw() requires a `chargefee` parameter')
          if self.password:
              request['trade_pwd'] = self.password
          elif 'password' in query:
              request['trade_pwd'] = query['password']
              query = self.omit(query, 'password')
          elif 'trade_pwd' in query:
              request['trade_pwd'] = query['trade_pwd']
              query = self.omit(query, 'trade_pwd')
          passwordInRequest = ('trade_pwd' in list(request.keys()))
          if not passwordInRequest:
              raise ExchangeError(self.id + ' withdraw() requires self.password set on the exchange instance or a password / trade_pwd parameter')
          response = self.privatePostWithdraw(self.extend(request, query))
          return {
              'info': response,
              'id': self.safe_string(response, 'withdraw_id'),
          }
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          url = '/'
          if api != 'web':
              url += self.version + '/'
          url += path
          if api != 'web':
              url += self.extension
          if api == 'private':
              self.check_required_credentials()
              query = self.keysort(self.extend({
                  'api_key': self.apiKey,
              }, params))
              # secret key must be at the end of query
              queryString = self.rawencode(query) + '&secret_key=' + self.secret
              query['sign'] = self.hash(self.encode(queryString)).upper()
              body = self.urlencode(query)
              headers = {'Content-Type': 'application/x-www-form-urlencoded'}
          else:
              if params:
                  url += '?' + self.urlencode(params)
          url = self.urls['api'][api] + url
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  
      def handle_errors(self, code, reason, url, method, headers, body):
          if len(body) < 2:
              return  # fallback to default error handler
          if body[0] == '{':
              response = json.loads(body)
              if 'error_code' in response:
                  error = self.safe_string(response, 'error_code')
                  message = self.id + ' ' + self.json(response)
                  if error in self.exceptions:
                      ExceptionClass = self.exceptions[error]
                      raise ExceptionClass(message)
                  else:
                      raise ExchangeError(message)
              if 'result' in response:
                  if not response['result']:
                      raise ExchangeError(self.id + ' ' + self.json(response))
  