UNPKG

ccxt

Version:

A cryptocurrency trading API with more than 100 exchanges in JavaScript / TypeScript / Python / C# / PHP / Go

1,055 lines (1,053 loc) 99.5 kB
// ---------------------------------------------------------------------------- // 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 // EDIT THE CORRESPONDENT .ts FILE INSTEAD // --------------------------------------------------------------------------- import { sha256 } from '@noble/hashes/sha2.js'; import Exchange from './abstract/bittrade.js'; import { AuthenticationError, ExchangeError, PermissionDenied, ExchangeNotAvailable, OnMaintenance, InvalidOrder, OrderNotFound, InsufficientFunds, BadSymbol, BadRequest, RequestTimeout, NetworkError, ArgumentsRequired, NotSupported } from './base/errors.js'; import { Precise } from './base/Precise.js'; import { TRUNCATE, TICK_SIZE } from './base/functions/number.js'; // --------------------------------------------------------------------------- /** * @class bittrade * @augments Exchange */ export default class bittrade extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'bittrade', 'name': 'BitTrade', 'countries': ['JP'], 'rateLimit': 100, 'userAgent': this.userAgents['chrome39'], 'certified': false, 'version': 'v1', 'hostname': 'api-cloud.bittrade.co.jp', 'pro': true, 'has': { 'CORS': undefined, 'spot': true, 'margin': undefined, 'swap': false, 'future': false, 'option': false, 'cancelAllOrders': true, 'cancelOrder': true, 'cancelOrders': true, 'createMarketBuyOrderWithCost': true, 'createMarketOrderWithCost': false, 'createMarketSellOrderWithCost': false, 'createOrder': true, 'createStopLimitOrder': false, 'createStopMarketOrder': false, 'createStopOrder': false, 'fetchAccounts': true, 'fetchBalance': true, 'fetchClosedOrders': true, 'fetchCurrencies': true, 'fetchDepositAddress': false, 'fetchDepositAddressesByNetwork': false, 'fetchDeposits': true, 'fetchFundingHistory': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': false, 'fetchFundingRates': false, 'fetchIndexOHLCV': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchOrderTrades': true, 'fetchPremiumIndexOHLCV': false, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingLimits': true, 'fetchWithdrawals': true, 'withdraw': true, }, 'timeframes': { '1m': '1min', '5m': '5min', '15m': '15min', '30m': '30min', '1h': '60min', '4h': '4hour', '1d': '1day', '1w': '1week', '1M': '1mon', '1y': '1year', }, 'urls': { 'logo': 'https://github.com/user-attachments/assets/c5996ed2-0d56-42d8-ac40-7eaf8116dbae', 'api': { 'market': 'https://{hostname}', 'public': 'https://{hostname}', 'private': 'https://{hostname}', 'v2Public': 'https://{hostname}', 'v2Private': 'https://{hostname}', }, 'www': 'https://www.bittrade.co.jp', 'referral': 'https://www.bittrade.co.jp/register/?invite_code=znnq3', 'doc': 'https://api-doc.bittrade.co.jp', 'fees': 'https://www.bittrade.co.jp/ja-jp/support/fee', }, 'api': { 'v2Public': { 'get': { 'reference/currencies': 1, // 币链参考信息 'market-status': 1, // 获取当前市场状态 }, }, 'v2Private': { 'get': { 'account/ledger': 1, 'account/withdraw/quota': 1, 'account/withdraw/address': 1, // 提币地址查询(限母用户可用) 'account/deposit/address': 1, 'account/repayment': 5, // 还币交易记录查询 'reference/transact-fee-rate': 1, 'account/asset-valuation': 0.2, // 获取账户资产估值 'point/account': 5, // 点卡余额查询 'sub-user/user-list': 1, // 获取子用户列表 'sub-user/user-state': 1, // 获取特定子用户的用户状态 'sub-user/account-list': 1, // 获取特定子用户的账户列表 'sub-user/deposit-address': 1, // 子用户充币地址查询 'sub-user/query-deposit': 1, // 子用户充币记录查询 'user/api-key': 1, // 母子用户API key信息查询 'user/uid': 1, // 母子用户获取用户UID 'algo-orders/opening': 1, // 查询未触发OPEN策略委托 'algo-orders/history': 1, // 查询策略委托历史 'algo-orders/specific': 1, // 查询特定策略委托 'c2c/offers': 1, // 查询借入借出订单 'c2c/offer': 1, // 查询特定借入借出订单及其交易记录 'c2c/transactions': 1, // 查询借入借出交易记录 'c2c/repayment': 1, // 查询还币交易记录 'c2c/account': 1, // 查询账户余额 'etp/reference': 1, // 基础参考信息 'etp/transactions': 5, // 获取杠杆ETP申赎记录 'etp/transaction': 5, // 获取特定杠杆ETP申赎记录 'etp/rebalance': 1, // 获取杠杆ETP调仓记录 'etp/limit': 1, // 获取ETP持仓限额 }, 'post': { 'account/transfer': 1, 'account/repayment': 5, // 归还借币(全仓逐仓通用) 'point/transfer': 5, // 点卡划转 'sub-user/management': 1, // 冻结/解冻子用户 'sub-user/creation': 1, // 子用户创建 'sub-user/tradable-market': 1, // 设置子用户交易权限 'sub-user/transferability': 1, // 设置子用户资产转出权限 'sub-user/api-key-generation': 1, // 子用户API key创建 'sub-user/api-key-modification': 1, // 修改子用户API key 'sub-user/api-key-deletion': 1, // 删除子用户API key 'sub-user/deduct-mode': 1, // 设置子用户手续费抵扣模式 'algo-orders': 1, // 策略委托下单 'algo-orders/cancel-all-after': 1, // 自动撤销订单 'algo-orders/cancellation': 1, // 策略委托(触发前)撤单 'c2c/offer': 1, // 借入借出下单 'c2c/cancellation': 1, // 借入借出撤单 'c2c/cancel-all': 1, // 撤销所有借入借出订单 'c2c/repayment': 1, // 还币 'c2c/transfer': 1, // 资产划转 'etp/creation': 5, // 杠杆ETP换入 'etp/redemption': 5, // 杠杆ETP换出 'etp/{transactId}/cancel': 10, // 杠杆ETP单个撤单 'etp/batch-cancel': 50, // 杠杆ETP批量撤单 }, }, 'market': { 'get': { 'history/kline': 1, // 获取K线数据 'detail/merged': 1, // 获取聚合行情(Ticker) 'depth': 1, // 获取 Market Depth 数据 'trade': 1, // 获取 Trade Detail 数据 'history/trade': 1, // 批量获取最近的交易记录 'detail': 1, // 获取 Market Detail 24小时成交量数据 'tickers': 1, 'etp': 1, // 获取杠杆ETP实时净值 }, }, 'public': { 'get': { 'common/symbols': 1, // 查询系统支持的所有交易对 'common/currencys': 1, // 查询系统支持的所有币种 'common/timestamp': 1, // 查询系统当前时间 'common/exchange': 1, // order limits 'settings/currencys': 1, // ?language=en-US }, }, 'private': { 'get': { 'account/accounts': 0.2, // 查询当前用户的所有账户(即account-id) 'account/accounts/{id}/balance': 0.2, // 查询指定账户的余额 'account/accounts/{sub-uid}': 1, 'account/history': 4, 'cross-margin/loan-info': 1, 'margin/loan-info': 1, // 查询借币币息率及额度 'fee/fee-rate/get': 1, 'order/openOrders': 0.4, 'order/orders': 0.4, 'order/orders/{id}': 0.4, // 查询某个订单详情 'order/orders/{id}/matchresults': 0.4, // 查询某个订单的成交明细 'order/orders/getClientOrder': 0.4, 'order/history': 1, // 查询当前委托、历史委托 'order/matchresults': 1, // 查询当前成交、历史成交 // 'dw/withdraw-virtual/addresses', // 查询虚拟币提现地址(Deprecated) 'query/deposit-withdraw': 1, // 'margin/loan-info', // duplicate 'margin/loan-orders': 0.2, // 借贷订单 'margin/accounts/balance': 0.2, // 借贷账户详情 'cross-margin/loan-orders': 1, // 查询借币订单 'cross-margin/accounts/balance': 1, // 借币账户详情 'points/actions': 1, 'points/orders': 1, 'subuser/aggregate-balance': 10, 'stable-coin/exchange_rate': 1, 'stable-coin/quote': 1, }, 'post': { 'account/transfer': 1, // 资产划转(该节点为母用户和子用户进行资产划转的通用接口。) 'futures/transfer': 1, 'order/batch-orders': 0.4, 'order/orders/place': 0.2, // 创建并执行一个新订单 (一步下单, 推荐使用) 'order/orders/submitCancelClientOrder': 0.2, 'order/orders/batchCancelOpenOrders': 0.4, // 'order/orders', // 创建一个新的订单请求 (仅创建订单,不执行下单) // 'order/orders/{id}/place', // 执行一个订单 (仅执行已创建的订单) 'order/orders/{id}/submitcancel': 0.2, // 申请撤销一个订单请求 'order/orders/batchcancel': 0.4, // 批量撤销订单 // 'dw/balance/transfer', // 资产划转 'dw/withdraw/api/create': 1, // 申请提现虚拟币 // 'dw/withdraw-virtual/create', // 申请提现虚拟币 // 'dw/withdraw-virtual/{id}/place', // 确认申请虚拟币提现(Deprecated) 'dw/withdraw-virtual/{id}/cancel': 1, // 申请取消提现虚拟币 'dw/transfer-in/margin': 10, // 现货账户划入至借贷账户 'dw/transfer-out/margin': 10, // 借贷账户划出至现货账户 'margin/orders': 10, // 申请借贷 'margin/orders/{id}/repay': 10, // 归还借贷 'cross-margin/transfer-in': 1, // 资产划转 'cross-margin/transfer-out': 1, // 资产划转 'cross-margin/orders': 1, // 申请借币 'cross-margin/orders/{id}/repay': 1, // 归还借币 'stable-coin/exchange': 1, 'subuser/transfer': 10, }, }, }, 'fees': { 'trading': { 'feeSide': 'get', 'tierBased': false, 'percentage': true, 'maker': this.parseNumber('0.002'), 'taker': this.parseNumber('0.002'), }, }, 'features': { 'spot': { 'sandbox': false, 'createOrder': { 'marginMode': false, 'triggerPrice': true, // todo: implement 'triggerPriceType': undefined, 'triggerDirection': false, 'stopLossPrice': false, // todo 'takeProfitPrice': false, // todo 'attachedStopLossTakeProfit': undefined, 'timeInForce': { 'IOC': false, 'FOK': false, 'PO': false, 'GTD': false, }, 'hedged': false, 'selfTradePrevention': false, 'trailing': false, 'leverage': false, 'marketBuyByCost': true, 'marketBuyRequiresPrice': false, 'iceberg': false, }, 'createOrders': undefined, 'fetchMyTrades': { 'marginMode': false, 'limit': 100, 'daysBack': 120, 'untilDays': 2, 'symbolRequired': false, }, 'fetchOrder': { 'marginMode': false, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOpenOrders': { 'marginMode': false, 'limit': undefined, // todo 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOrders': { 'marginMode': false, 'limit': undefined, 'daysBack': undefined, // todo 'untilDays': undefined, // todo 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchClosedOrders': { 'marginMode': false, 'limit': undefined, 'daysBack': undefined, // todo 'daysBackCanceled': undefined, // todo 'untilDays': undefined, // todo 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOHLCV': { 'limit': 2000, }, }, 'swap': { 'linear': undefined, 'inverse': undefined, }, 'future': { 'linear': undefined, 'inverse': undefined, }, }, 'precisionMode': TICK_SIZE, 'exceptions': { 'broad': { 'contract is restricted of closing positions on API. Please contact customer service': OnMaintenance, 'maintain': OnMaintenance, }, 'exact': { // err-code 'bad-request': BadRequest, 'base-date-limit-error': BadRequest, // {"status":"error","err-code":"base-date-limit-error","err-msg":"date less than system limit","data":null} 'api-not-support-temp-addr': PermissionDenied, // {"status":"error","err-code":"api-not-support-temp-addr","err-msg":"API withdrawal does not support temporary addresses","data":null} 'timeout': RequestTimeout, // {"ts":1571653730865,"status":"error","err-code":"timeout","err-msg":"Request Timeout"} 'gateway-internal-error': ExchangeNotAvailable, // {"status":"error","err-code":"gateway-internal-error","err-msg":"Failed to load data. Try again later.","data":null} 'account-frozen-balance-insufficient-error': InsufficientFunds, // {"status":"error","err-code":"account-frozen-balance-insufficient-error","err-msg":"trade account balance is not enough, left: `0.0027`","data":null} 'invalid-amount': InvalidOrder, // eg "Paramemter `amount` is invalid." 'order-limitorder-amount-min-error': InvalidOrder, // limit order amount error, min: `0.001` 'order-limitorder-amount-max-error': InvalidOrder, // market order amount error, max: `1000000` 'order-marketorder-amount-min-error': InvalidOrder, // market order amount error, min: `0.01` 'order-limitorder-price-min-error': InvalidOrder, // limit order price error 'order-limitorder-price-max-error': InvalidOrder, // limit order price error 'order-holding-limit-failed': InvalidOrder, // {"status":"error","err-code":"order-holding-limit-failed","err-msg":"Order failed, exceeded the holding limit of this currency","data":null} 'order-orderprice-precision-error': InvalidOrder, // {"status":"error","err-code":"order-orderprice-precision-error","err-msg":"order price precision error, scale: `4`","data":null} 'order-etp-nav-price-max-error': InvalidOrder, // {"status":"error","err-code":"order-etp-nav-price-max-error","err-msg":"Order price cannot be higher than 5% of NAV","data":null} 'order-orderstate-error': OrderNotFound, // canceling an already canceled order 'order-queryorder-invalid': OrderNotFound, // querying a non-existent order 'order-update-error': ExchangeNotAvailable, // undocumented error 'api-signature-check-failed': AuthenticationError, 'api-signature-not-valid': AuthenticationError, // {"status":"error","err-code":"api-signature-not-valid","err-msg":"Signature not valid: Incorrect Access key [Access key错误]","data":null} 'base-record-invalid': OrderNotFound, // https://github.com/ccxt/ccxt/issues/5750 'base-symbol-trade-disabled': BadSymbol, // {"status":"error","err-code":"base-symbol-trade-disabled","err-msg":"Trading is disabled for this symbol","data":null} 'base-symbol-error': BadSymbol, // {"status":"error","err-code":"base-symbol-error","err-msg":"The symbol is invalid","data":null} 'system-maintenance': OnMaintenance, // {"status": "error", "err-code": "system-maintenance", "err-msg": "System is in maintenance!", "data": null} // err-msg 'invalid symbol': BadSymbol, // {"ts":1568813334794,"status":"error","err-code":"invalid-parameter","err-msg":"invalid symbol"} 'symbol trade not open now': BadSymbol, // {"ts":1576210479343,"status":"error","err-code":"invalid-parameter","err-msg":"symbol trade not open now"}, 'invalid-address': BadRequest, // {"status":"error","err-code":"invalid-address","err-msg":"Invalid address.","data":null}, 'base-currency-chain-error': BadRequest, // {"status":"error","err-code":"base-currency-chain-error","err-msg":"The current currency chain does not exist","data":null}, 'dw-insufficient-balance': InsufficientFunds, // {"status":"error","err-code":"dw-insufficient-balance","err-msg":"Insufficient balance. You can only transfer `12.3456` at most.","data":null} }, }, 'options': { 'defaultNetwork': 'ERC20', 'networks': { 'ETH': 'erc20', 'TRX': 'trc20', 'HRC20': 'hrc20', 'HECO': 'hrc20', 'HT': 'hrc20', 'ALGO': 'algo', }, // https://github.com/ccxt/ccxt/issues/5376 'fetchOrdersByStates': { 'method': 'private_get_order_orders', // 'private_get_order_history' // https://github.com/ccxt/ccxt/pull/5392 }, 'fetchOpenOrders': { 'method': 'fetch_open_orders_v1', // 'fetch_open_orders_v2' // https://github.com/ccxt/ccxt/issues/5388 }, 'createOrder': { 'createMarketBuyOrderRequiresPrice': true, 'method': 'privatePostOrderOrdersPlace', }, 'fetchMarkets': { 'method': 'publicGetCommonSymbols', }, 'fetchBalance': { 'method': 'privateGetAccountAccountsIdBalance', }, 'currencyToPrecisionRoundingMode': TRUNCATE, 'fetchCurrencies': { 'language': 'en-US', }, 'broker': { 'id': 'AA03022abc', }, }, 'commonCurrencies': { // https://github.com/ccxt/ccxt/issues/6081 // https://github.com/ccxt/ccxt/issues/3365 // https://github.com/ccxt/ccxt/issues/2873 'GET': 'Themis', // conflict with GET (Guaranteed Entrance Token, GET Protocol) 'GTC': 'Game.com', // conflict with Gitcoin and Gastrocoin 'HIT': 'HitChain', // https://github.com/ccxt/ccxt/issues/7399 // https://coinmarketcap.com/currencies/pnetwork/ // https://coinmarketcap.com/currencies/penta/markets/ // https://en.cryptonomist.ch/blog/eidoo/the-edo-to-pnt-upgrade-what-you-need-to-know-updated/ 'PNT': 'Penta', 'SBTC': 'Super Bitcoin', 'BIFI': 'Bitcoin File', // conflict with Beefy.Finance https://github.com/ccxt/ccxt/issues/8706 }, }); } /** * @method * @name bittrade#fetchTime * @description fetches the current integer timestamp in milliseconds from the exchange server * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {int} the current integer timestamp in milliseconds from the exchange server */ async fetchTime(params = {}) { const response = await this.publicGetCommonTimestamp(params); return this.safeInteger(response, 'data'); } async fetchTradingLimits(symbols = undefined, params = {}) { // this method should not be called directly, use loadTradingLimits () instead // by default it will try load withdrawal fees of all currencies (with separate requests) // however if you define symbols = [ 'ETH/BTC', 'LTC/BTC' ] in args it will only load those if (this.markets === undefined) { await this.loadMarkets(); } if (symbols === undefined) { symbols = this.symbols; } if (symbols === undefined) { throw new ExchangeError(this.id + ' markets not loaded'); } const result = {}; for (let i = 0; i < symbols.length; i++) { const symbol = symbols[i]; result[symbol] = await this.fetchTradingLimitsById(this.marketId(symbol), params); } return result; } async fetchTradingLimitsById(id, params = {}) { const request = { 'symbol': id, }; const response = await this.publicGetCommonExchange(this.extend(request, params)); // // { status: "ok", // "data": { symbol: "aidocbtc", // "buy-limit-must-less-than": 1.1, // "sell-limit-must-greater-than": 0.9, // "limit-order-must-greater-than": 1, // "limit-order-must-less-than": 5000000, // "market-buy-order-must-greater-than": 0.0001, // "market-buy-order-must-less-than": 100, // "market-sell-order-must-greater-than": 1, // "market-sell-order-must-less-than": 500000, // "circuit-break-when-greater-than": 10000, // "circuit-break-when-less-than": 10, // "market-sell-order-rate-must-less-than": 0.1, // "market-buy-order-rate-must-less-than": 0.1 } } // return this.parseTradingLimits(this.safeValue(response, 'data', {})); } parseTradingLimits(limits, symbol = undefined, params = {}) { // // { symbol: "aidocbtc", // "buy-limit-must-less-than": 1.1, // "sell-limit-must-greater-than": 0.9, // "limit-order-must-greater-than": 1, // "limit-order-must-less-than": 5000000, // "market-buy-order-must-greater-than": 0.0001, // "market-buy-order-must-less-than": 100, // "market-sell-order-must-greater-than": 1, // "market-sell-order-must-less-than": 500000, // "circuit-break-when-greater-than": 10000, // "circuit-break-when-less-than": 10, // "market-sell-order-rate-must-less-than": 0.1, // "market-buy-order-rate-must-less-than": 0.1 } // return { 'info': limits, 'limits': { 'amount': { 'min': this.safeNumber(limits, 'limit-order-must-greater-than'), 'max': this.safeNumber(limits, 'limit-order-must-less-than'), }, }, }; } costToPrecision(symbol, cost) { return this.decimalToPrecision(cost, TRUNCATE, this.market(symbol)['precision']['cost'], this.precisionMode); } /** * @method * @name bittrade#fetchMarkets * @description retrieves data on all markets for huobijp * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} an array of objects representing market data */ async fetchMarkets(params = {}) { const method = this.handleOption('fetchMarkets', 'method', 'publicGetCommonSymbols'); const response = await this[method](params); // // { // "status": "ok", // "data": [ // { // "base-currency": "xrp", // "quote-currency": "btc", // "price-precision": 9, // "amount-precision": 2, // "symbol-partition": "default", // "symbol": "xrpbtc", // "state": "online", // "value-precision": 8, // "min-order-amt": 1, // "max-order-amt": 5000000, // "min-order-value": 0.0001, // "limit-order-min-order-amt": 1, // "limit-order-max-order-amt": 5000000, // "limit-order-max-buy-amt": 5000000, // "limit-order-max-sell-amt": 5000000, // "sell-market-min-order-amt": 1, // "sell-market-max-order-amt": 500000, // "buy-market-max-order-value": 100, // "leverage-ratio": 5, // "super-margin-leverage-ratio": 3, // "api-trading": "enabled", // "tags": "" // } // ... // ] // } // const markets = this.safeValue(response, 'data', []); const numMarkets = markets.length; if (numMarkets < 1) { throw new NetworkError(this.id + ' fetchMarkets() returned empty response: ' + this.json(markets)); } const result = []; for (let i = 0; i < markets.length; i++) { const market = markets[i]; const baseId = this.safeString(market, 'base-currency'); const quoteId = this.safeString(market, 'quote-currency'); const base = this.safeCurrencyCode(baseId); const quote = this.safeCurrencyCode(quoteId); const state = this.safeString(market, 'state'); const leverageRatio = this.safeString(market, 'leverage-ratio', '1'); const superLeverageRatio = this.safeString(market, 'super-margin-leverage-ratio', '1'); const margin = Precise.stringGt(leverageRatio, '1') || Precise.stringGt(superLeverageRatio, '1'); const fee = (base === 'OMG') ? this.parseNumber('0') : this.parseNumber('0.002'); if (baseId === undefined) { throw new ExchangeError(this.id + ' fetchMarkets() missing baseId'); } if (quoteId === undefined) { throw new ExchangeError(this.id + ' fetchMarkets() missing quoteId'); } result.push({ 'id': baseId + quoteId, 'symbol': base + '/' + quote, 'base': base, 'quote': quote, 'settle': undefined, 'baseId': baseId, 'quoteId': quoteId, 'settleId': undefined, 'type': 'spot', 'spot': true, 'margin': margin, 'swap': false, 'future': false, 'option': false, 'active': (state === 'online'), 'contract': false, 'linear': undefined, 'inverse': undefined, 'taker': fee, 'maker': fee, 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'price-precision'))), 'amount': this.parseNumber(this.parsePrecision(this.safeString(market, 'amount-precision'))), 'cost': this.parseNumber(this.parsePrecision(this.safeString(market, 'value-precision'))), }, 'limits': { 'leverage': { 'min': this.parseNumber('1'), 'max': this.parseNumber(leverageRatio), 'superMax': this.parseNumber(superLeverageRatio), }, 'amount': { 'min': this.safeNumber(market, 'min-order-amt'), 'max': this.safeNumber(market, 'max-order-amt'), }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': this.safeNumber(market, 'min-order-value'), 'max': undefined, }, }, 'created': undefined, 'info': market, }); } return result; } parseTicker(ticker, market = undefined) { // // fetchTicker // // { // "amount": 26228.672978342216, // "open": 9078.95, // "close": 9146.86, // "high": 9155.41, // "id": 209988544334, // "count": 265846, // "low": 8988.0, // "version": 209988544334, // "ask": [ 9146.87, 0.156134 ], // "vol": 2.3822168242201668E8, // "bid": [ 9146.86, 0.080758 ], // } // // fetchTickers // { // "symbol": "bhdht", // "open": 2.3938, // "high": 2.4151, // "low": 2.3323, // "close": 2.3909, // "amount": 628.992, // "vol": 1493.71841095, // "count": 2088, // "bid": 2.3643, // "bidSize": 0.7136, // "ask": 2.4061, // "askSize": 0.4156 // } // const symbol = this.safeSymbol(undefined, market); const timestamp = this.safeInteger(ticker, 'ts'); let bid = undefined; let bidVolume = undefined; let ask = undefined; let askVolume = undefined; if ('bid' in ticker) { if (Array.isArray(ticker['bid'])) { bid = this.safeString(ticker['bid'], 0); bidVolume = this.safeString(ticker['bid'], 1); } else { bid = this.safeString(ticker, 'bid'); bidVolume = this.safeString(ticker, 'bidSize'); } } if ('ask' in ticker) { if (Array.isArray(ticker['ask'])) { ask = this.safeString(ticker['ask'], 0); askVolume = this.safeString(ticker['ask'], 1); } else { ask = this.safeString(ticker, 'ask'); askVolume = this.safeString(ticker, 'askSize'); } } const open = this.safeString(ticker, 'open'); const close = this.safeString(ticker, 'close'); const baseVolume = this.safeString(ticker, 'amount'); const quoteVolume = this.safeString(ticker, 'vol'); return this.safeTicker({ 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'high': this.safeString(ticker, 'high'), 'low': this.safeString(ticker, 'low'), 'bid': bid, 'bidVolume': bidVolume, 'ask': ask, 'askVolume': askVolume, 'vwap': undefined, 'open': open, 'close': close, 'last': close, 'previousClose': undefined, 'change': undefined, 'percentage': undefined, 'average': undefined, 'baseVolume': baseVolume, 'quoteVolume': quoteVolume, 'info': ticker, }, market); } /** * @method * @name bittrade#fetchOrderBook * @description 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 {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} an [order book structure]{@link https://docs.ccxt.com/?id=order-book-structure} */ async fetchOrderBook(symbol, limit = undefined, params = {}) { if (this.markets === undefined) { await this.loadMarkets(); } const market = this.market(symbol); const request = { 'symbol': market['id'], 'type': 'step0', }; const response = await this.marketGetDepth(this.extend(request, params)); // // { // "status": "ok", // "ch": "market.btcusdt.depth.step0", // "ts": 1583474832790, // "tick": { // "bids": [ // [ 9100.290000000000000000, 0.200000000000000000 ], // [ 9099.820000000000000000, 0.200000000000000000 ], // [ 9099.610000000000000000, 0.205000000000000000 ], // ], // "asks": [ // [ 9100.640000000000000000, 0.005904000000000000 ], // [ 9101.010000000000000000, 0.287311000000000000 ], // [ 9101.030000000000000000, 0.012121000000000000 ], // ], // "ts":1583474832008, // "version":104999698780 // } // } // if ('tick' in response) { if (!response['tick']) { throw new BadSymbol(this.id + ' fetchOrderBook() returned empty response: ' + this.json(response)); } const tick = this.safeValue(response, 'tick'); const timestamp = this.safeInteger(tick, 'ts', this.safeInteger(response, 'ts')); const result = this.parseOrderBook(tick, symbol, timestamp); result['nonce'] = this.safeInteger(tick, 'version'); return result; } throw new ExchangeError(this.id + ' fetchOrderBook() returned unrecognized response: ' + this.json(response)); } /** * @method * @name bittrade#fetchTicker * @description 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 {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure} */ async fetchTicker(symbol, params = {}) { if (this.markets === undefined) { await this.loadMarkets(); } const market = this.market(symbol); const request = { 'symbol': market['id'], }; const response = await this.marketGetDetailMerged(this.extend(request, params)); // // { // "status": "ok", // "ch": "market.btcusdt.detail.merged", // "ts": 1583494336669, // "tick": { // "amount": 26228.672978342216, // "open": 9078.95, // "close": 9146.86, // "high": 9155.41, // "id": 209988544334, // "count": 265846, // "low": 8988.0, // "version": 209988544334, // "ask": [ 9146.87, 0.156134 ], // "vol": 2.3822168242201668E8, // "bid": [ 9146.86, 0.080758 ], // } // } // const ticker = this.parseTicker(response['tick'], market); const timestamp = this.safeInteger(response, 'ts'); ticker['timestamp'] = timestamp; ticker['datetime'] = this.iso8601(timestamp); return ticker; } /** * @method * @name bittrade#fetchTickers * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market * @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/?id=ticker-structure} */ async fetchTickers(symbols = undefined, params = {}) { if (this.markets === undefined) { await this.loadMarkets(); } symbols = this.marketSymbols(symbols); const response = await this.marketGetTickers(params); const tickers = this.safeValue(response, 'data', []); const timestamp = this.safeInteger(response, 'ts'); const result = {}; for (let i = 0; i < tickers.length; i++) { const marketId = this.safeString(tickers[i], 'symbol'); const market = this.safeMarket(marketId); const symbol = market['symbol']; const ticker = this.parseTicker(tickers[i], market); ticker['timestamp'] = timestamp; ticker['datetime'] = this.iso8601(timestamp); result[symbol] = ticker; } return this.filterByArrayTickers(result, 'symbol', symbols); } parseTrade(trade, market = undefined) { // // fetchTrades (public) // // { // "amount": 0.010411000000000000, // "trade-id": 102090736910, // "ts": 1583497692182, // "id": 10500517034273194594947, // "price": 9096.050000000000000000, // "direction": "sell" // } // // fetchMyTrades (private) // // { // "symbol": "swftcbtc", // "fee-currency": "swftc", // "filled-fees": "0", // "source": "spot-api", // "id": 83789509854000, // "type": "buy-limit", // "order-id": 83711103204909, // 'filled-points': "0.005826843283532154", // "fee-deduct-currency": "ht", // 'filled-amount': "45941.53", // "price": "0.0000001401", // "created-at": 1597933260729, // "match-id": 100087455560, // "role": "maker", // "trade-id": 100050305348 // }, // const marketId = this.safeString(trade, 'symbol'); const symbol = this.safeSymbol(marketId, market); const timestamp = this.safeInteger2(trade, 'ts', 'created-at'); const order = this.safeString(trade, 'order-id'); let side = this.safeString(trade, 'direction'); let type = this.safeString(trade, 'type'); if (type !== undefined) { const typeParts = type.split('-'); side = typeParts[0]; type = typeParts[1]; } const takerOrMaker = this.safeString(trade, 'role'); const price = this.safeString(trade, 'price'); const amount = this.safeString2(trade, 'filled-amount', 'amount'); const cost = Precise.stringMul(price, amount); let fee = undefined; let feeCost = this.safeString(trade, 'filled-fees'); let feeCurrency = this.safeCurrencyCode(this.safeString(trade, 'fee-currency')); const filledPoints = this.safeString(trade, 'filled-points'); if (filledPoints !== undefined) { if ((feeCost === undefined) || (Precise.stringEq(feeCost, '0.0'))) { feeCost = filledPoints; feeCurrency = this.safeCurrencyCode(this.safeString(trade, 'fee-deduct-currency')); } } if (feeCost !== undefined) { fee = { 'cost': feeCost, 'currency': feeCurrency, }; } const tradeId = this.safeString2(trade, 'trade-id', 'tradeId'); const id = this.safeString(trade, 'id', tradeId); return this.safeTrade({ 'info': trade, 'id': id, 'symbol': symbol, 'order': order, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'type': type, 'side': side, 'takerOrMaker': takerOrMaker, 'price': price, 'amount': amount, 'cost': cost, 'fee': fee, }); } /** * @method * @name bittrade#fetchOrderTrades * @description fetch all the trades made from a single 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 {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=trade-structure} */ async fetchOrderTrades(id, symbol = undefined, since = undefined, limit = undefined, params = {}) { if (this.markets === undefined) { await this.loadMarkets(); } const request = { 'id': id, }; const response = await this.privateGetOrderOrdersIdMatchresults(this.extend(request, params)); return this.parseTrades(response['data'], undefined, since, limit); } /** * @method * @name bittrade#fetchMyTrades * @description fetch all trades made by the user * @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 {object} [params] extra parameters specific to the exchange API endpoint * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=trade-structure} */ async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) { if (this.markets === undefined) { await this.loadMarkets(); } let market = undefined; const request = {}; if (symbol !== undefined) { market = this.market(symbol); request['symbol'] = market['id']; } if (limit !== undefined) { request['size'] = limit; // 1-100 orders, default is 100 } if (since !== undefined) { request['start-time'] = since; // a date within 120 days from today // request['end-time'] = this.sum (since, 172800000); // 48 hours window } const response = await this.privateGetOrderMatchresults(this.extend(request, params)); return this.parseTrades(response['data'], market, since, limit); } /** * @method * @name bittrade#fetchTrades * @description get the list of most recent trades for a particular symbol * @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 {object} [params] extra parameters specific to the exchange API endpoint * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades} */ async fetchTrades(symbol, since = undefined, limit = 1000, params = {}) { if (this.markets === undefined) { await this.loadMarkets(); } const market = this.market(symbol); const request = { 'symbol': market['id'], }; if (limit !== undefined) { request['size'] = Math.min(limit, 2000); } const response = await this.marketGetHistoryTrade(this.extend(request, params)); // // { // "status": "ok", // "ch": "market.btcusdt.trade.detail", // "ts": 1583497692365, // "data": [ // { // "id": 105005170342, // "ts": 1583497692182, // "data": [ // { // "amount": 0.010411000000000000, // "trade-id": 102090736910, // "ts": 1583497692182, // "id": 10500517034273194594947, // "price": 9096.050000000000000000, // "direction": "sell" // } // ] // }, // // ... // ] // } // const data = this.safeValue(response, 'data', []); let result = []; for (let i = 0; i < data.length; i++) { const trades = this.safeValue(data[i], 'data', []); for (let j = 0; j < trades.length; j++) { const trade = this.parseTrade(trades[j], market); result.push(trade); } } result = this.sortBy(result, 'timestamp'); return this.filterBySymbolSinceLimit(result, market['symbol'], since, limit); } parseOHLCV(ohlcv, market = undefined) { // // { // "amount":1.2082, // "open":0.025096, // "close":0.025095, // "high":0.025096, // "id":1591515300, // "count":6, // "low":0.025095, // "vol":0.0303205097 // } // return [ this.safeTimestamp(ohlcv, 'id'), this.safeNumber(ohlcv, 'open'), this.safeNumber(ohlcv, 'high'), this.safeNumber(ohlcv, 'low'), this.safeNumber(ohlcv, 'close'), this.safeNumber(ohlcv, 'amount'), ]; } /** * @method * @name bittrade#fetchOHLCV * @description fetches historical candlestick data containing the ope