UNPKG

ccxt

Version:

A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges

1,178 lines (1,176 loc) • 69.7 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 Exchange from './abstract/novadax.js'; import { AuthenticationError, ExchangeError, PermissionDenied, BadRequest, CancelPending, OrderNotFound, InsufficientFunds, RateLimitExceeded, InvalidOrder, AccountSuspended, BadSymbol, OnMaintenance, ArgumentsRequired, AccountNotEnabled } from './base/errors.js'; import { Precise } from './base/Precise.js'; import { TICK_SIZE } from './base/functions/number.js'; import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; import { md5 } from './static_dependencies/noble-hashes/md5.js'; // --------------------------------------------------------------------------- /** * @class novadax * @augments Exchange */ export default class novadax extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'novadax', 'name': 'NovaDAX', 'countries': ['BR'], // 6000 weight per min => 100 weight per second => min weight = 1 // 100 requests per second => ( 1000ms / 100 ) = 10 ms between requests on average 'rateLimit': 10, 'version': 'v1', // new metainfo interface 'has': { 'CORS': undefined, 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'addMargin': false, 'cancelOrder': true, 'closeAllPositions': false, 'closePosition': false, 'createMarketBuyOrderWithCost': true, 'createMarketOrderWithCost': false, 'createMarketSellOrderWithCost': false, 'createOrder': true, 'createReduceOnlyOrder': false, 'createStopLimitOrder': true, 'createStopMarketOrder': true, 'createStopOrder': true, 'fetchAccounts': true, 'fetchBalance': true, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchClosedOrders': true, 'fetchCrossBorrowRate': false, 'fetchCrossBorrowRates': false, 'fetchDepositAddress': false, 'fetchDepositAddresses': false, 'fetchDepositAddressesByNetwork': false, 'fetchDeposits': true, 'fetchDepositsWithdrawals': true, 'fetchFundingHistory': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': false, 'fetchFundingRates': false, 'fetchIndexOHLCV': false, 'fetchIsolatedBorrowRate': false, 'fetchIsolatedBorrowRates': false, 'fetchLeverage': false, 'fetchLeverageTiers': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenInterestHistory': false, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchOrderTrades': true, 'fetchPosition': false, 'fetchPositionHistory': false, 'fetchPositionMode': false, 'fetchPositions': false, 'fetchPositionsForSymbol': false, 'fetchPositionsHistory': false, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': false, 'fetchTransactions': 'emulated', 'fetchWithdrawals': true, 'reduceMargin': false, 'setLeverage': false, 'setMarginMode': false, 'setPositionMode': false, 'transfer': true, 'withdraw': true, }, 'timeframes': { '1m': 'ONE_MIN', '5m': 'FIVE_MIN', '15m': 'FIFTEEN_MIN', '30m': 'HALF_HOU', '1h': 'ONE_HOU', '1d': 'ONE_DAY', '1w': 'ONE_WEE', '1M': 'ONE_MON', }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/92337550-2b085500-f0b3-11ea-98e7-5794fb07dd3b.jpg', 'api': { 'public': 'https://api.novadax.com', 'private': 'https://api.novadax.com', }, 'www': 'https://www.novadax.com.br', 'doc': [ 'https://doc.novadax.com/pt-BR/', ], 'fees': 'https://www.novadax.com.br/fees-and-limits', 'referral': 'https://www.novadax.com.br/?s=ccxt', }, 'api': { 'public': { 'get': { 'common/symbol': 1, 'common/symbols': 1, 'common/timestamp': 1, 'market/tickers': 5, 'market/ticker': 1, 'market/depth': 1, 'market/trades': 5, 'market/kline/history': 5, }, }, 'private': { 'get': { 'orders/get': 1, 'orders/list': 10, 'orders/fill': 3, 'orders/fills': 10, 'account/getBalance': 1, 'account/subs': 1, 'account/subs/balance': 1, 'account/subs/transfer/record': 10, 'wallet/query/deposit-withdraw': 3, }, 'post': { 'orders/create': 5, 'orders/batch-create': 50, 'orders/cancel': 1, 'orders/batch-cancel': 10, 'orders/cancel-by-symbol': 10, 'account/subs/transfer': 5, 'wallet/withdraw/coin': 3, 'account/withdraw/coin': 3, // not found in doc }, }, }, 'fees': { 'trading': { 'tierBased': false, 'percentage': true, 'taker': this.parseNumber('0.005'), 'maker': this.parseNumber('0.0025'), }, }, 'requiredCredentials': { 'apiKey': true, 'secret': true, }, 'precisionMode': TICK_SIZE, 'exceptions': { 'exact': { 'A99999': ExchangeError, // 'A10000': ExchangeError, // 200 Success Successful request 'A10001': BadRequest, 'A10002': ExchangeError, 'A10003': AuthenticationError, 'A10004': RateLimitExceeded, 'A10005': PermissionDenied, 'A10006': AccountSuspended, 'A10007': AccountNotEnabled, 'A10011': BadSymbol, 'A10012': BadSymbol, 'A10013': OnMaintenance, 'A30001': OrderNotFound, 'A30002': InvalidOrder, 'A30003': InvalidOrder, 'A30004': InvalidOrder, 'A30005': InvalidOrder, 'A30006': InvalidOrder, 'A30007': InsufficientFunds, 'A30008': InvalidOrder, 'A30009': InvalidOrder, 'A30010': CancelPending, 'A30011': InvalidOrder, 'A30012': InvalidOrder, 'A40004': InsufficientFunds, // {"code":"A40004","data":[],"message":"sub account balance Insufficient"} }, 'broad': {}, }, 'options': { 'fetchOHLCV': { 'volume': 'amount', // 'amount' for base volume or 'vol' for quote volume }, 'transfer': { 'fillResponseFromRequest': true, }, }, 'features': { 'spot': { 'sandbox': false, 'createOrder': { 'marginMode': false, 'triggerPrice': true, 'triggerDirection': true, 'triggerPriceType': undefined, 'stopLossPrice': false, 'takeProfitPrice': false, 'attachedStopLossTakeProfit': undefined, // todo 'timeInForce': { 'IOC': false, 'FOK': false, 'PO': false, 'GTD': false, }, 'hedged': false, 'trailing': false, 'leverage': false, 'marketBuyByCost': true, 'marketBuyRequiresPrice': false, 'selfTradePrevention': false, 'iceberg': true, // todo }, 'createOrders': undefined, 'fetchMyTrades': { 'marginMode': false, 'limit': 100, 'daysBack': 100000, 'untilDays': 100000, 'symbolRequired': false, }, 'fetchOrder': { 'marginMode': false, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOpenOrders': { 'marginMode': false, 'limit': undefined, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOrders': { 'marginMode': false, 'limit': 100, 'daysBack': 100000, 'untilDays': 100000, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchClosedOrders': { 'marginMode': false, 'limit': 100, 'daysBack': 100000, 'daysBackCanceled': 1, 'untilDays': 100000, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOHLCV': { 'limit': undefined, // todo max 3000 }, }, 'swap': { 'linear': undefined, 'inverse': undefined, }, 'future': { 'linear': undefined, 'inverse': undefined, }, }, }); } /** * @method * @name novadax#fetchTime * @description fetches the current integer timestamp in milliseconds from the exchange server * @see https://doc.novadax.com/en-US/#get-current-system-time * @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); // // { // "code":"A10000", // "data":1599090512080, // "message":"Success" // } // return this.safeInteger(response, 'data'); } /** * @method * @name novadax#fetchMarkets * @description retrieves data on all markets for novadax * @see https://doc.novadax.com/en-US/#get-all-supported-trading-symbol * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} an array of objects representing market data */ async fetchMarkets(params = {}) { const response = await this.publicGetCommonSymbols(params); // // { // "code":"A10000", // "data":[ // { // "amountPrecision":8, // "baseCurrency":"BTC", // "minOrderAmount":"0.001", // "minOrderValue":"25", // "pricePrecision":2, // "quoteCurrency":"BRL", // "status":"ONLINE", // "symbol":"BTC_BRL", // "valuePrecision":2 // }, // ], // "message":"Success" // } // const data = this.safeValue(response, 'data', []); return this.parseMarkets(data); } parseMarket(market) { const baseId = this.safeString(market, 'baseCurrency'); const quoteId = this.safeString(market, 'quoteCurrency'); const id = this.safeString(market, 'symbol'); const base = this.safeCurrencyCode(baseId); const quote = this.safeCurrencyCode(quoteId); const status = this.safeString(market, 'status'); return { 'id': id, 'symbol': base + '/' + quote, 'base': base, 'quote': quote, 'settle': undefined, 'baseId': baseId, 'quoteId': quoteId, 'settleId': undefined, 'type': 'spot', 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'active': (status === 'ONLINE'), 'contract': false, 'linear': undefined, 'inverse': undefined, 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.parseNumber(this.parsePrecision(this.safeString(market, 'amountPrecision'))), 'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'pricePrecision'))), // 'cost': this.parseNumber (this.parsePrecision (this.safeString (market, 'valuePrecision'))), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': this.safeNumber(market, 'minOrderAmount'), 'max': undefined, }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': this.safeNumber(market, 'minOrderValue'), 'max': undefined, }, }, 'created': undefined, 'info': market, }; } parseTicker(ticker, market = undefined) { // // fetchTicker, fetchTickers // // { // "ask":"61946.1", // "baseVolume24h":"164.41930186", // "bid":"61815", // "high24h":"64930.72", // "lastPrice":"61928.41", // "low24h":"61156.32", // "open24h":"64512.46", // "quoteVolume24h":"10308157.95", // "symbol":"BTC_BRL", // "timestamp":1599091115090 // } // const timestamp = this.safeInteger(ticker, 'timestamp'); const marketId = this.safeString(ticker, 'symbol'); const symbol = this.safeSymbol(marketId, market, '_'); const open = this.safeString(ticker, 'open24h'); const last = this.safeString(ticker, 'lastPrice'); const baseVolume = this.safeString(ticker, 'baseVolume24h'); const quoteVolume = this.safeString(ticker, 'quoteVolume24h'); return this.safeTicker({ 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'high': this.safeString(ticker, 'high24h'), 'low': this.safeString(ticker, 'low24h'), 'bid': this.safeString(ticker, 'bid'), 'bidVolume': undefined, 'ask': this.safeString(ticker, 'ask'), 'askVolume': undefined, 'vwap': undefined, 'open': open, 'close': last, 'last': last, 'previousClose': undefined, 'change': undefined, 'percentage': undefined, 'average': undefined, 'baseVolume': baseVolume, 'quoteVolume': quoteVolume, 'info': ticker, }, market); } /** * @method * @name novadax#fetchTicker * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market * @see https://doc.novadax.com/en-US/#get-latest-ticker-for-specific-pair * @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 = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], }; const response = await this.publicGetMarketTicker(this.extend(request, params)); // // { // "code":"A10000", // "data":{ // "ask":"61946.1", // "baseVolume24h":"164.41930186", // "bid":"61815", // "high24h":"64930.72", // "lastPrice":"61928.41", // "low24h":"61156.32", // "open24h":"64512.46", // "quoteVolume24h":"10308157.95", // "symbol":"BTC_BRL", // "timestamp":1599091115090 // }, // "message":"Success" // } // const data = this.safeDict(response, 'data', {}); return this.parseTicker(data, market); } /** * @method * @name novadax#fetchTickers * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market * @see https://doc.novadax.com/en-US/#get-latest-tickers-for-all-trading-pairs * @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 = {}) { await this.loadMarkets(); symbols = this.marketSymbols(symbols); const response = await this.publicGetMarketTickers(params); // // { // "code":"A10000", // "data":[ // { // "ask":"61879.36", // "baseVolume24h":"164.40955092", // "bid":"61815", // "high24h":"64930.72", // "lastPrice":"61820.04", // "low24h":"61156.32", // "open24h":"64624.19", // "quoteVolume24h":"10307493.92", // "symbol":"BTC_BRL", // "timestamp":1599091291083 // }, // ], // "message":"Success" // } // const data = this.safeValue(response, 'data', []); const result = {}; for (let i = 0; i < data.length; i++) { const ticker = this.parseTicker(data[i]); const symbol = ticker['symbol']; result[symbol] = ticker; } return this.filterByArrayTickers(result, 'symbol', symbols); } /** * @method * @name novadax#fetchOrderBook * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @see https://doc.novadax.com/en-US/#get-market-depth * @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} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols */ async fetchOrderBook(symbol, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], }; if (limit !== undefined) { request['limit'] = limit; // default 10, max 20 } const response = await this.publicGetMarketDepth(this.extend(request, params)); // // { // "code":"A10000", // "data":{ // "asks":[ // ["0.037159","0.3741"], // ["0.037215","0.2706"], // ["0.037222","1.8459"], // ], // "bids":[ // ["0.037053","0.3857"], // ["0.036969","0.8101"], // ["0.036953","1.5226"], // ], // "timestamp":1599280414448 // }, // "message":"Success" // } // const data = this.safeValue(response, 'data', {}); const timestamp = this.safeInteger(data, 'timestamp'); return this.parseOrderBook(data, market['symbol'], timestamp, 'bids', 'asks'); } parseTrade(trade, market = undefined) { // // public fetchTrades // // { // "amount":"0.0632", // "price":"0.037288", // "side":"BUY", // "timestamp":1599279694576 // } // // private fetchOrderTrades // // { // "id": "608717046691139584", // "orderId": "608716957545402368", // "symbol": "BTC_BRL", // "side": "BUY", // "amount": "0.0988", // "price": "45514.76", // "fee": "0.0000988 BTC", // "feeAmount": "0.0000988", // "feeCurrency": "BTC", // "role": "MAKER", // "timestamp": 1565171053345 // } // // private fetchMyTrades (same endpoint as fetchOrderTrades) // // { // "id": "608717046691139584", // "orderId": "608716957545402368", // "symbol": "BTC_BRL", // "side": "BUY", // "amount": "0.0988", // "price": "45514.76", // "fee": "0.0000988 BTC", // "feeAmount": "0.0000988", // "feeCurrency": "BTC", // "role": "MAKER", // "timestamp": 1565171053345 // } // const id = this.safeString(trade, 'id'); const orderId = this.safeString(trade, 'orderId'); const timestamp = this.safeInteger(trade, 'timestamp'); const side = this.safeStringLower(trade, 'side'); const priceString = this.safeString(trade, 'price'); const amountString = this.safeString(trade, 'amount'); const marketId = this.safeString(trade, 'symbol'); const symbol = this.safeSymbol(marketId, market, '_'); const takerOrMaker = this.safeStringLower(trade, 'role'); const feeString = this.safeString(trade, 'fee'); let fee = undefined; if (feeString !== undefined) { const feeCurrencyId = this.safeString(trade, 'feeCurrency'); const feeCurrencyCode = this.safeCurrencyCode(feeCurrencyId); fee = { 'cost': this.safeString(trade, 'feeAmount'), 'currency': feeCurrencyCode, }; } return this.safeTrade({ 'id': id, 'order': orderId, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': symbol, 'type': undefined, 'side': side, 'price': priceString, 'amount': amountString, 'cost': undefined, 'takerOrMaker': takerOrMaker, 'fee': fee, 'info': trade, }, market); } /** * @method * @name novadax#fetchTrades * @description get the list of most recent trades for a particular symbol * @see https://doc.novadax.com/en-US/#get-recent-trades * @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 = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], }; if (limit !== undefined) { request['limit'] = limit; // default 100 } const response = await this.publicGetMarketTrades(this.extend(request, params)); // // { // "code":"A10000", // "data":[ // {"amount":"0.0632","price":"0.037288","side":"BUY","timestamp":1599279694576}, // {"amount":"0.0052","price":"0.03715","side":"SELL","timestamp":1599276606852}, // {"amount":"0.0058","price":"0.037188","side":"SELL","timestamp":1599275187812}, // ], // "message":"Success" // } // const data = this.safeList(response, 'data', []); return this.parseTrades(data, market, since, limit); } /** * @method * @name novadax#fetchOHLCV * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market * @see https://doc.novadax.com/en-US/#get-kline-data * @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 {object} [params] extra parameters specific to the exchange API endpoint * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume */ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], 'unit': this.safeString(this.timeframes, timeframe, timeframe), }; const duration = this.parseTimeframe(timeframe); const now = this.seconds(); if (limit === undefined) { limit = 3000; // max } if (since === undefined) { request['from'] = now - limit * duration; request['to'] = now; } else { const startFrom = this.parseToInt(since / 1000); request['from'] = startFrom; request['to'] = this.sum(startFrom, limit * duration); } const response = await this.publicGetMarketKlineHistory(this.extend(request, params)); // // { // "code": "A10000", // "data": [ // { // "amount": 8.25709100, // "closePrice": 62553.20, // "count": 29, // "highPrice": 62592.87, // "lowPrice": 62553.20, // "openPrice": 62554.23, // "score": 1602501480, // "symbol": "BTC_BRL", // "vol": 516784.2504067500 // } // ], // "message": "Success" // } // const data = this.safeList(response, 'data', []); return this.parseOHLCVs(data, market, timeframe, since, limit); } parseOHLCV(ohlcv, market = undefined) { // // { // "amount": 8.25709100, // "closePrice": 62553.20, // "count": 29, // "highPrice": 62592.87, // "lowPrice": 62553.20, // "openPrice": 62554.23, // "score": 1602501480, // "symbol": "BTC_BRL", // "vol": 516784.2504067500 // } // const options = this.safeValue(this.options, 'fetchOHLCV', {}); const volumeField = this.safeString(options, 'volume', 'amount'); // or vol return [ this.safeTimestamp(ohlcv, 'score'), this.safeNumber(ohlcv, 'openPrice'), this.safeNumber(ohlcv, 'highPrice'), this.safeNumber(ohlcv, 'lowPrice'), this.safeNumber(ohlcv, 'closePrice'), this.safeNumber(ohlcv, volumeField), ]; } parseBalance(response) { const data = this.safeValue(response, 'data', []); const result = { 'info': response, 'timestamp': undefined, 'datetime': undefined, }; for (let i = 0; i < data.length; i++) { const balance = data[i]; const currencyId = this.safeString(balance, 'currency'); const code = this.safeCurrencyCode(currencyId); const account = this.account(); account['total'] = this.safeString(balance, 'balance'); account['free'] = this.safeString(balance, 'available'); account['used'] = this.safeString(balance, 'hold'); result[code] = account; } return this.safeBalance(result); } /** * @method * @name novadax#fetchBalance * @description query for balance and get the amount of funds available for trading or funds locked in orders * @see https://doc.novadax.com/en-US/#get-account-balance * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure} */ async fetchBalance(params = {}) { await this.loadMarkets(); const response = await this.privateGetAccountGetBalance(params); // // { // "code": "A10000", // "data": [ // { // "available": "1.23", // "balance": "0.23", // "currency": "BTC", // "hold": "1" // } // ], // "message": "Success" // } // return this.parseBalance(response); } /** * @method * @name novadax#createOrder * @description create a trade order * @see https://doc.novadax.com/en-US/#order-introduction * @param {string} symbol unified symbol of the market to create an order in * @param {string} type 'market' or 'limit' * @param {string} side 'buy' or 'sell' * @param {float} amount how much you want to trade in units of the 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 {object} [params] extra parameters specific to the exchange API endpoint * @param {float} [params.cost] for spot market buy orders, the quote quantity that can be used as an alternative for the amount * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ async createOrder(symbol, type, side, amount, price = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); let uppercaseType = type.toUpperCase(); const uppercaseSide = side.toUpperCase(); const request = { 'symbol': market['id'], 'side': uppercaseSide, // or SELL // "amount": this.amountToPrecision (symbol, amount), // "price": "1234.5678", // required for LIMIT and STOP orders // "operator": "" // for stop orders, can be found in order introduction // "stopPrice": this.priceToPrecision (symbol, stopPrice), // "accountId": "...", // subaccount id, optional }; const triggerPrice = this.safeValue2(params, 'triggerPrice', 'stopPrice'); if (triggerPrice === undefined) { if ((uppercaseType === 'STOP_LIMIT') || (uppercaseType === 'STOP_MARKET')) { throw new ArgumentsRequired(this.id + ' createOrder() requires a stopPrice parameter for ' + uppercaseType + ' orders'); } } else { if (uppercaseType === 'LIMIT') { uppercaseType = 'STOP_LIMIT'; } else if (uppercaseType === 'MARKET') { uppercaseType = 'STOP_MARKET'; } const defaultOperator = (uppercaseSide === 'BUY') ? 'LTE' : 'GTE'; request['operator'] = this.safeString(params, 'operator', defaultOperator); request['stopPrice'] = this.priceToPrecision(symbol, triggerPrice); params = this.omit(params, ['triggerPrice', 'stopPrice']); } if ((uppercaseType === 'LIMIT') || (uppercaseType === 'STOP_LIMIT')) { request['price'] = this.priceToPrecision(symbol, price); request['amount'] = this.amountToPrecision(symbol, amount); } else if ((uppercaseType === 'MARKET') || (uppercaseType === 'STOP_MARKET')) { if (uppercaseSide === 'SELL') { request['amount'] = this.amountToPrecision(symbol, amount); } else if (uppercaseSide === 'BUY') { let quoteAmount = undefined; let createMarketBuyOrderRequiresPrice = true; [createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true); const cost = this.safeNumber2(params, 'cost', 'value'); params = this.omit(params, 'cost'); if (cost !== undefined) { quoteAmount = this.costToPrecision(symbol, cost); } else if (createMarketBuyOrderRequiresPrice) { if (price === undefined) { throw new InvalidOrder(this.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend (amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to false and pass the cost to spend (quote quantity) in the amount argument'); } else { const amountString = this.numberToString(amount); const priceString = this.numberToString(price); const costRequest = Precise.stringMul(amountString, priceString); quoteAmount = this.costToPrecision(symbol, costRequest); } } else { quoteAmount = this.costToPrecision(symbol, amount); } request['value'] = quoteAmount; } } request['type'] = uppercaseType; const response = await this.privatePostOrdersCreate(this.extend(request, params)); // // { // "code": "A10000", // "data": { // "amount": "0.001", // "averagePrice": null, // "filledAmount": "0", // "filledFee": "0", // "filledValue": "0", // "id": "870613508008464384", // "operator": "GTE", // "price": "210000", // "side": "BUY", // "status": "SUBMITTED", // "stopPrice": "211000", // "symbol": "BTC_BRL", // "timestamp": 1627612035528, // "type": "STOP_LIMIT", // "value": "210" // }, // "message": "Success" // } // const data = this.safeDict(response, 'data', {}); return this.parseOrder(data, market); } /** * @method * @name novadax#cancelOrder * @description cancels an open order * @see https://doc.novadax.com/en-US/#cancel-an-order * @param {string} id order id * @param {string} symbol not used by novadax cancelOrder () * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ async cancelOrder(id, symbol = undefined, params = {}) { await this.loadMarkets(); const request = { 'id': id, }; const response = await this.privatePostOrdersCancel(this.extend(request, params)); // // { // "code": "A10000", // "data": { // "result": true // }, // "message": "Success" // } // const data = this.safeDict(response, 'data', {}); return this.parseOrder(data); } /** * @method * @name novadax#fetchOrder * @description fetches information on an order made by the user * @see https://doc.novadax.com/en-US/#get-order-details * @param {string} id order id * @param {string} symbol not used by novadax fetchOrder * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchOrder(id, symbol = undefined, params = {}) { await this.loadMarkets(); const request = { 'id': id, }; const response = await this.privateGetOrdersGet(this.extend(request, params)); // // { // "code": "A10000", // "data": { // "id": "608695623247466496", // "symbol": "BTC_BRL", // "type": "MARKET", // "side": "SELL", // "price": null, // "averagePrice": "0", // "amount": "0.123", // "filledAmount": "0", // "value": null, // "filledValue": "0", // "filledFee": "0", // "status": "REJECTED", // "timestamp": 1565165945588 // }, // "message": "Success" // } // const data = this.safeDict(response, 'data', {}); return this.parseOrder(data); } /** * @method * @name novadax#fetchOrders * @description fetches information on multiple orders made by the user * @see https://doc.novadax.com/en-US/#get-order-history * @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 {object} [params] extra parameters specific to the exchange API endpoint * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const request = { // 'symbol': market['id'], // 'status': 'SUBMITTED,PROCESSING', // SUBMITTED, PROCESSING, PARTIAL_FILLED, CANCELING, FILLED, CANCELED, REJECTED // 'fromId': '...', // order id to begin with // 'toId': '...', // order id to end up with // 'fromTimestamp': since, // 'toTimestamp': this.milliseconds (), // 'limit': limit, // default 100, max 100 }; let market = undefined; if (symbol !== undefined) { market = this.market(symbol); request['symbol'] = market['id']; } if (limit !== undefined) { request['limit'] = limit; // default 100, max 100 } if (since !== undefined) { request['fromTimestamp'] = since; } const response = await this.privateGetOrdersList(this.extend(request, params)); // // { // "code": "A10000", // "data": [ // { // "id": "608695678650028032", // "symbol": "BTC_BRL", // "type": "MARKET", // "side": "SELL", // "price": null, // "averagePrice": "0", // "amount": "0.123", // "filledAmount": "0", // "value": null, // "filledValue": "0", // "filledFee": "0", // "status": "REJECTED", // "timestamp": 1565165958796 // }, // ], // "message": "Success" // } // const data = this.safeList(response, 'data', []); return this.parseOrders(data, market, since, limit); } /** * @method * @name novadax#fetchOpenOrders * @description fetch all unfilled currently open orders * @see https://doc.novadax.com/en-US/#get-order-history * @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 {object} [params] extra parameters specific to the exchange API endpoint * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { const request = { 'status': 'SUBMITTED,PROCESSING,PARTIAL_FILLED,CANCELING', }; return await this.fetchOrders(symbol, since, limit, this.extend(request, params)); } /** * @method * @name novadax#fetchClosedOrders * @description fetches information on multiple closed orders made by the user * @see https://doc.novadax.com/en-US/#get-order-history * @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 {object} [params] extra parameters specific to the exchange API endpoint * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { const request = { 'status': 'FILLED,CANCELED,REJECTED', }; return await this.fetchOrders(symbol, since, limit, this.extend(request, params)); } /** * @method * @name novadax#fetchOrderTrades * @description fetch all the trades made from a single order * @see https://doc.novadax.com/en-US/#get-order-match-details * @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 = {}) { await this.loadMarkets(); const request = { 'id': id, }; const response = await this.privateGetOrdersFill(this.extend(request, params)); let market = undefined; if (symbol !== undefined) { market = this.market(symbol); } const data = this.safeValue(response, 'data', []); // // { // "code": "A10000", // "data": [ // { // "id": "608717046691139584", // "orderId": "608716957545402368", // "symbol": "BTC_BRL", // "side": "BUY", // "amount": "0.0988", // "price": "45514.76", // "fee": "0.0000988 BTC", // "feeAmount": "0.0000988", // "feeCurrency": "BTC", // "role": "MAKER", // "timestamp": 1565171053345 // }, // ], // "message": "Success" // } // return this.parseTrades(data, market, since, limit); } parseOrderStatus(status) { const statuses = { 'SUBMITTED': 'open', 'PROCESSING': 'open', 'PARTIAL_FILLED': 'open', 'CANCELING': 'open', 'FILLED': 'closed', 'CANCELED': 'canceled', 'REJECTED': 'rejected', }; return this.safeString(statuses, status, status); } parseOrder(order, market = undefined) { // // createOrder, fetchOrders, fetchOrder // // { // "amount": "0.001", // "averagePrice": null, // "filledAmount": "0", // "filledFee": "0", // "filledValue": "0", // "id": "870613508008464384", // "operator": "GTE", // "price": "210000", // "side": "BUY", // "status": "SUBMITTED", // "stopPrice": "211000", // "symbol": "BTC_BRL", // "timestamp": 1627612035528, // "type": "STOP_LIMIT", // "value": "210" // } // // cancelOrder // // { // "result": true // } // const id = this.safeString(order, 'id'); const amount = this.safeString(order, 'amount'); const price = this.safeString(order, 'price'); const cost = this.safeString2(order, 'filledValue', 'value'); const type = this.safeStringLower(order, 'type'); const side = this.safeStringLower(order, 'side'); const status = this.parseOrderStatus(this.safeString(order, 'status')); const timestamp = this.safeInteger(order, 'timestamp'); const average = this.safeString(order, 'averagePrice'); const filled = this.safeString(order, 'filled