UNPKG

sfccxt

Version:

A JavaScript / Python / PHP cryptocurrency trading library with support for 130+ exchanges

1,161 lines (1,140 loc) 113 kB
'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); const { ExchangeError, AuthenticationError, InsufficientFunds, BadSymbol, OrderNotFound } = require ('./base/errors'); const { TICK_SIZE } = require ('./base/functions/number'); // --------------------------------------------------------------------------- module.exports = class ndax extends Exchange { describe () { return this.deepExtend (super.describe (), { 'id': 'ndax', 'name': 'NDAX', 'countries': [ 'CA' ], // Canada 'rateLimit': 1000, 'pro': true, 'has': { 'CORS': undefined, 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'addMargin': false, 'cancelAllOrders': true, 'cancelOrder': true, 'createDepositAddress': true, 'createOrder': true, 'createReduceOnlyOrder': false, 'editOrder': true, 'fetchAccounts': true, 'fetchBalance': true, 'fetchBorrowRate': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchBorrowRates': false, 'fetchBorrowRatesPerSymbol': false, 'fetchCurrencies': true, 'fetchDepositAddress': true, 'fetchDeposits': true, 'fetchFundingHistory': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': false, 'fetchFundingRates': false, 'fetchIndexOHLCV': false, 'fetchLedger': true, '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, 'fetchPositions': false, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchTicker': true, 'fetchTickers': false, 'fetchTime': false, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': false, 'fetchWithdrawals': true, 'reduceMargin': false, 'setLeverage': false, 'setMarginMode': false, 'setPositionMode': false, 'signIn': true, 'transfer': false, 'withdraw': true, }, 'timeframes': { '1m': '60', '5m': '300', '15m': '900', '30m': '1800', '1h': '3600', '2h': '7200', '4h': '14400', '6h': '21600', '12h': '43200', '1d': '86400', '1w': '604800', '1M': '2419200', '4M': '9676800', }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/108623144-67a3ef00-744e-11eb-8140-75c6b851e945.jpg', 'test': { 'public': 'https://ndaxmarginstaging.cdnhop.net:8443/AP', 'private': 'https://ndaxmarginstaging.cdnhop.net:8443/AP', }, 'api': { 'public': 'https://api.ndax.io:8443/AP', 'private': 'https://api.ndax.io:8443/AP', }, 'www': 'https://ndax.io', 'doc': [ 'https://apidoc.ndax.io/', ], 'fees': 'https://ndax.io/fees', 'referral': 'https://one.ndax.io/bfQiSL', }, 'api': { 'public': { 'get': { 'Activate2FA': 1, 'Authenticate2FA': 1, 'AuthenticateUser': 1, 'GetL2Snapshot': 1, 'GetLevel1': 1, 'GetValidate2FARequiredEndpoints': 1, 'LogOut': 1, 'GetTickerHistory': 1, 'GetProduct': 1, 'GetProducts': 1, 'GetInstrument': 1, 'GetInstruments': 1, 'Ping': 1, 'trades': 1, // undocumented 'GetLastTrades': 1, // undocumented 'SubscribeLevel1': 1, 'SubscribeLevel2': 1, 'SubscribeTicker': 1, 'SubscribeTrades': 1, 'SubscribeBlockTrades': 1, 'UnsubscribeBlockTrades': 1, 'UnsubscribeLevel1': 1, 'UnsubscribeLevel2': 1, 'UnsubscribeTicker': 1, 'UnsubscribeTrades': 1, 'Authenticate': 1, // undocumented }, }, 'private': { 'get': { 'GetUserAccountInfos': 1, 'GetUserAccounts': 1, 'GetUserAffiliateCount': 1, 'GetUserAffiliateTag': 1, 'GetUserConfig': 1, 'GetAllUnredactedUserConfigsForUser': 1, 'GetUnredactedUserConfigByKey': 1, 'GetUserDevices': 1, 'GetUserReportTickets': 1, 'GetUserReportWriterResultRecords': 1, 'GetAccountInfo': 1, 'GetAccountPositions': 1, 'GetAllAccountConfigs': 1, 'GetTreasuryProductsForAccount': 1, 'GetAccountTrades': 1, 'GetAccountTransactions': 1, 'GetOpenTradeReports': 1, 'GetAllOpenTradeReports': 1, 'GetTradesHistory': 1, 'GetOpenOrders': 1, 'GetOpenQuotes': 1, 'GetOrderFee': 1, 'GetOrderHistory': 1, 'GetOrdersHistory': 1, 'GetOrderStatus': 1, 'GetOmsFeeTiers': 1, 'GetAccountDepositTransactions': 1, 'GetAccountWithdrawTransactions': 1, 'GetAllDepositRequestInfoTemplates': 1, 'GetDepositInfo': 1, 'GetDepositRequestInfoTemplate': 1, 'GetDeposits': 1, 'GetDepositTicket': 1, 'GetDepositTickets': 1, 'GetOMSWithdrawFees': 1, 'GetWithdrawFee': 1, 'GetWithdraws': 1, 'GetWithdrawTemplate': 1, 'GetWithdrawTemplateTypes': 1, 'GetWithdrawTicket': 1, 'GetWithdrawTickets': 1, }, 'post': { 'AddUserAffiliateTag': 1, 'CancelUserReport': 1, 'RegisterNewDevice': 1, 'SubscribeAccountEvents': 1, 'UpdateUserAffiliateTag': 1, 'GenerateTradeActivityReport': 1, 'GenerateTransactionActivityReport': 1, 'GenerateTreasuryActivityReport': 1, 'ScheduleTradeActivityReport': 1, 'ScheduleTransactionActivityReport': 1, 'ScheduleTreasuryActivityReport': 1, 'CancelAllOrders': 1, 'CancelOrder': 1, 'CancelQuote': 1, 'CancelReplaceOrder': 1, 'CreateQuote': 1, 'ModifyOrder': 1, 'SendOrder': 1, 'SubmitBlockTrade': 1, 'UpdateQuote': 1, 'CancelWithdraw': 1, 'CreateDepositTicket': 1, 'CreateWithdrawTicket': 1, 'SubmitDepositTicketComment': 1, 'SubmitWithdrawTicketComment': 1, 'GetOrderHistoryByOrderId': 1, }, }, }, 'fees': { 'trading': { 'tierBased': false, 'percentage': true, 'maker': this.parseNumber ('0.002'), 'taker': this.parseNumber ('0.0025'), }, }, 'requiredCredentials': { 'apiKey': true, 'secret': true, 'uid': true, // these credentials are required for signIn() and withdraw() 'login': true, 'password': true, // 'twofa': true, }, 'precisionMode': TICK_SIZE, 'exceptions': { 'exact': { 'Not_Enough_Funds': InsufficientFunds, // {"status":"Rejected","errormsg":"Not_Enough_Funds","errorcode":101} 'Server Error': ExchangeError, // {"result":false,"errormsg":"Server Error","errorcode":102,"detail":null} 'Resource Not Found': OrderNotFound, // {"result":false,"errormsg":"Resource Not Found","errorcode":104,"detail":null} }, 'broad': { 'Invalid InstrumentId': BadSymbol, // {"result":false,"errormsg":"Invalid InstrumentId: 10000","errorcode":100,"detail":null} 'This endpoint requires 2FACode along with the payload': AuthenticationError, }, }, 'options': { 'omsId': 1, 'orderTypes': { 'Market': 1, 'Limit': 2, 'StopMarket': 3, 'StopLimit': 4, 'TrailingStopMarket': 5, 'TrailingStopLimit': 6, 'BlockTrade': 7, }, }, }); } async signIn (params = {}) { /** * @method * @name ndax#signIn * @description sign in, must be called prior to using other authenticated methods * @param {object} params extra parameters specific to the ndax api endpoint * @returns response from exchange */ this.checkRequiredCredentials (); if (this.login === undefined || this.password === undefined) { throw new AuthenticationError (this.id + ' signIn() requires exchange.login, exchange.password'); } let request = { 'grant_type': 'client_credentials', // the only supported value }; const response = await this.publicGetAuthenticate (this.extend (request, params)); // // { // "Authenticated":true, // "Requires2FA":true, // "AuthType":"Google", // "AddtlInfo":"", // "Pending2FaToken": "6f5c4e66-f3ee-493e-9227-31cc0583b55f" // } // let sessionToken = this.safeString (response, 'SessionToken'); if (sessionToken !== undefined) { this.options['sessionToken'] = sessionToken; return response; } const pending2faToken = this.safeString (response, 'Pending2FaToken'); if (pending2faToken !== undefined) { if (this.twofa === undefined) { throw new AuthenticationError (this.id + ' signIn() requires exchange.twofa credentials'); } this.options['pending2faToken'] = pending2faToken; request = { 'Code': this.oath (), }; const response = await this.publicGetAuthenticate2FA (this.extend (request, params)); // // { // "Authenticated": true, // "UserId":57765, // "SessionToken":"4a2a5857-c4e5-4fac-b09e-2c4c30b591a0" // } // sessionToken = this.safeString (response, 'SessionToken'); this.options['sessionToken'] = sessionToken; return response; } return response; } async fetchCurrencies (params = {}) { /** * @method * @name ndax#fetchCurrencies * @description fetches all available currencies on an exchange * @param {object} params extra parameters specific to the ndax api endpoint * @returns {object} an associative dictionary of currencies */ const omsId = this.safeInteger (this.options, 'omsId', 1); const request = { 'omsId': omsId, }; const response = await this.publicGetGetProducts (this.extend (request, params)); // // [ // { // "OMSId":1, // "ProductId":1, // "Product":"BTC", // "ProductFullName":"Bitcoin", // "ProductType":"CryptoCurrency", // "DecimalPlaces":8, // "TickSize":0.0000000100000000000000000000, // "NoFees":false, // "IsDisabled":false, // "MarginEnabled":false // }, // ] // const result = {}; for (let i = 0; i < response.length; i++) { const currency = response[i]; const id = this.safeString (currency, 'ProductId'); const name = this.safeString (currency, 'ProductFullName'); const type = this.safeString (currency, 'ProductType'); const code = this.safeCurrencyCode (this.safeString (currency, 'Product')); const isDisabled = this.safeValue (currency, 'IsDisabled'); const active = !isDisabled; result[code] = { 'id': id, 'name': name, 'code': code, 'type': type, 'precision': this.safeNumber (currency, 'TickSize'), 'info': currency, 'active': active, 'deposit': undefined, 'withdraw': undefined, 'fee': undefined, 'limits': { 'amount': { 'min': undefined, 'max': undefined, }, 'withdraw': { 'min': undefined, 'max': undefined, }, }, }; } return result; } async fetchMarkets (params = {}) { /** * @method * @name ndax#fetchMarkets * @description retrieves data on all markets for ndax * @param {object} params extra parameters specific to the exchange api endpoint * @returns {[object]} an array of objects representing market data */ const omsId = this.safeInteger (this.options, 'omsId', 1); const request = { 'omsId': omsId, }; const response = await this.publicGetGetInstruments (this.extend (request, params)); // // [ // { // "OMSId":1, // "InstrumentId":3, // "Symbol":"LTCBTC", // "Product1":3, // "Product1Symbol":"LTC", // "Product2":1, // "Product2Symbol":"BTC", // "InstrumentType":"Standard", // "VenueInstrumentId":3, // "VenueId":1, // "SortIndex":0, // "SessionStatus":"Running", // "PreviousSessionStatus":"Stopped", // "SessionStatusDateTime":"2020-11-25T19:42:15.245Z", // "SelfTradePrevention":true, // "QuantityIncrement":0.0000000100000000000000000000, // "PriceIncrement":0.0000000100000000000000000000, // "MinimumQuantity":0.0100000000000000000000000000, // "MinimumPrice":0.0000010000000000000000000000, // "VenueSymbol":"LTCBTC", // "IsDisable":false, // "MasterDataId":0, // "PriceCollarThreshold":0.0000000000000000000000000000, // "PriceCollarPercent":0.0000000000000000000000000000, // "PriceCollarEnabled":false, // "PriceFloorLimit":0.0000000000000000000000000000, // "PriceFloorLimitEnabled":false, // "PriceCeilingLimit":0.0000000000000000000000000000, // "PriceCeilingLimitEnabled":false, // "CreateWithMarketRunning":true, // "AllowOnlyMarketMakerCounterParty":false, // "PriceCollarIndexDifference":0.0000000000000000000000000000, // "PriceCollarConvertToOtcEnabled":false, // "PriceCollarConvertToOtcClientUserId":0, // "PriceCollarConvertToOtcAccountId":0, // "PriceCollarConvertToOtcThreshold":0.0000000000000000000000000000, // "OtcConvertSizeThreshold":0.0000000000000000000000000000, // "OtcConvertSizeEnabled":false, // "OtcTradesPublic":true, // "PriceTier":0 // }, // ] // const result = []; for (let i = 0; i < response.length; i++) { const market = response[i]; const id = this.safeString (market, 'InstrumentId'); // const lowercaseId = this.safeStringLower (market, 'symbol'); const baseId = this.safeString (market, 'Product1'); const quoteId = this.safeString (market, 'Product2'); const base = this.safeCurrencyCode (this.safeString (market, 'Product1Symbol')); const quote = this.safeCurrencyCode (this.safeString (market, 'Product2Symbol')); const sessionStatus = this.safeString (market, 'SessionStatus'); const isDisable = this.safeValue (market, 'IsDisable'); const sessionRunning = (sessionStatus === 'Running'); result.push ({ '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': (sessionRunning && !isDisable), 'contract': false, 'linear': undefined, 'inverse': undefined, 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.safeNumber (market, 'QuantityIncrement'), 'price': this.safeNumber (market, 'PriceIncrement'), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': this.safeNumber (market, 'MinimumQuantity'), 'max': undefined, }, 'price': { 'min': this.safeNumber (market, 'MinimumPrice'), 'max': undefined, }, 'cost': { 'min': undefined, 'max': undefined, }, }, 'info': market, }); } return result; } parseOrderBook (orderbook, symbol, timestamp = undefined, bidsKey = 'bids', asksKey = 'asks', priceKey = 6, amountKey = 8) { let nonce = undefined; const result = { 'symbol': symbol, 'bids': [], 'asks': [], 'timestamp': undefined, 'datetime': undefined, 'nonce': undefined, }; for (let i = 0; i < orderbook.length; i++) { const level = orderbook[i]; if (timestamp === undefined) { timestamp = this.safeInteger (level, 2); } else { const newTimestamp = this.safeInteger (level, 2); timestamp = Math.max (timestamp, newTimestamp); } if (nonce === undefined) { nonce = this.safeInteger (level, 0); } else { const newNonce = this.safeInteger (level, 0); nonce = Math.max (nonce, newNonce); } const bidask = this.parseBidAsk (level, priceKey, amountKey); const levelSide = this.safeInteger (level, 9); const side = levelSide ? asksKey : bidsKey; result[side].push (bidask); } result['bids'] = this.sortBy (result['bids'], 0, true); result['asks'] = this.sortBy (result['asks'], 0); result['timestamp'] = timestamp; result['datetime'] = this.iso8601 (timestamp); result['nonce'] = nonce; return result; } async fetchOrderBook (symbol, limit = undefined, params = {}) { /** * @method * @name ndax#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|undefined} limit the maximum amount of order book entries to return * @param {object} params extra parameters specific to the ndax api endpoint * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-book-structure} indexed by market symbols */ const omsId = this.safeInteger (this.options, 'omsId', 1); await this.loadMarkets (); const market = this.market (symbol); limit = (limit === undefined) ? 100 : limit; // default 100 const request = { 'omsId': omsId, 'InstrumentId': market['id'], 'Depth': limit, // default 100 }; const response = await this.publicGetGetL2Snapshot (this.extend (request, params)); // // [ // [ // 0, // 0 MDUpdateId // 1, // 1 Number of Unique Accounts // 123, // 2 ActionDateTime in Posix format X 1000 // 0, // 3 ActionType 0 (New), 1 (Update), 2(Delete) // 0.0, // 4 LastTradePrice // 0, // 5 Number of Orders // 0.0, // 6 Price // 0, // 7 ProductPairCode // 0.0, // 8 Quantity // 0, // 9 Side // ], // [97244115,1,1607456142963,0,19069.32,1,19069.31,8,0.140095,0], // [97244115,0,1607456142963,0,19069.32,1,19068.64,8,0.0055,0], // [97244115,0,1607456142963,0,19069.32,1,19068.26,8,0.021291,0], // [97244115,1,1607456142964,0,19069.32,1,19069.32,8,0.099636,1], // [97244115,0,1607456142964,0,19069.32,1,19069.98,8,0.1,1], // [97244115,0,1607456142964,0,19069.32,1,19069.99,8,0.141604,1], // ] // return this.parseOrderBook (response, symbol); } parseTicker (ticker, market = undefined) { // // fetchTicker // // { // "OMSId":1, // "InstrumentId":8, // "BestBid":19069.31, // "BestOffer":19069.32, // "LastTradedPx":19069.32, // "LastTradedQty":0.0001, // "LastTradeTime":1607040406424, // "SessionOpen":19069.32, // "SessionHigh":19069.32, // "SessionLow":19069.32, // "SessionClose":19069.32, // "Volume":0.0001, // "CurrentDayVolume":0.0001, // "CurrentDayNotional":1.906932, // "CurrentDayNumTrades":1, // "CurrentDayPxChange":0.00, // "Rolling24HrVolume":0.000000000000000000000000000, // "Rolling24HrNotional":0.00000000000000000000000, // "Rolling24NumTrades":0, // "Rolling24HrPxChange":0, // "TimeStamp":"1607040406425", // "BidQty":0, // "AskQty":0, // "BidOrderCt":0, // "AskOrderCt":0, // "Rolling24HrPxChangePercent":0, // } // const timestamp = this.safeInteger (ticker, 'TimeStamp'); const marketId = this.safeString (ticker, 'InstrumentId'); market = this.safeMarket (marketId, market); const symbol = this.safeSymbol (marketId, market); const last = this.safeString (ticker, 'LastTradedPx'); const percentage = this.safeString (ticker, 'Rolling24HrPxChangePercent'); const change = this.safeString (ticker, 'Rolling24HrPxChange'); const open = this.safeString (ticker, 'SessionOpen'); const baseVolume = this.safeString (ticker, 'Rolling24HrVolume'); const quoteVolume = this.safeString (ticker, 'Rolling24HrNotional'); return this.safeTicker ({ 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'high': this.safeString (ticker, 'SessionHigh'), 'low': this.safeString (ticker, 'SessionLow'), 'bid': this.safeString (ticker, 'BestBid'), 'bidVolume': undefined, // this.safeNumber (ticker, 'BidQty'), always shows 0 'ask': this.safeString (ticker, 'BestOffer'), 'askVolume': undefined, // this.safeNumber (ticker, 'AskQty'), always shows 0 'vwap': undefined, 'open': open, 'close': last, 'last': last, 'previousClose': undefined, 'change': change, 'percentage': percentage, 'average': undefined, 'baseVolume': baseVolume, 'quoteVolume': quoteVolume, 'info': ticker, }, market); } async fetchTicker (symbol, params = {}) { /** * @method * @name ndax#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 ndax api endpoint * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure} */ const omsId = this.safeInteger (this.options, 'omsId', 1); await this.loadMarkets (); const market = this.market (symbol); const request = { 'omsId': omsId, 'InstrumentId': market['id'], }; const response = await this.publicGetGetLevel1 (this.extend (request, params)); // // { // "OMSId":1, // "InstrumentId":8, // "BestBid":19069.31, // "BestOffer":19069.32, // "LastTradedPx":19069.32, // "LastTradedQty":0.0001, // "LastTradeTime":1607040406424, // "SessionOpen":19069.32, // "SessionHigh":19069.32, // "SessionLow":19069.32, // "SessionClose":19069.32, // "Volume":0.0001, // "CurrentDayVolume":0.0001, // "CurrentDayNotional":1.906932, // "CurrentDayNumTrades":1, // "CurrentDayPxChange":0.00, // "Rolling24HrVolume":0.000000000000000000000000000, // "Rolling24HrNotional":0.00000000000000000000000, // "Rolling24NumTrades":0, // "Rolling24HrPxChange":0, // "TimeStamp":"1607040406425", // "BidQty":0, // "AskQty":0, // "BidOrderCt":0, // "AskOrderCt":0, // "Rolling24HrPxChangePercent":0, // } // return this.parseTicker (response, market); } parseOHLCV (ohlcv, market = undefined) { // // [ // 1501603632000, // 0 DateTime // 2700.33, // 1 High // 2687.01, // 2 Low // 2687.01, // 3 Open // 2687.01, // 4 Close // 24.86100992, // 5 Volume // 0, // 6 Inside Bid Price // 2870.95, // 7 Inside Ask Price // 1 // 8 InstrumentId // ] // return [ this.safeInteger (ohlcv, 0), this.safeNumber (ohlcv, 3), this.safeNumber (ohlcv, 1), this.safeNumber (ohlcv, 2), this.safeNumber (ohlcv, 4), this.safeNumber (ohlcv, 5), ]; } async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { /** * @method * @name ndax#fetchOHLCV * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market * @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|undefined} since timestamp in ms of the earliest candle to fetch * @param {int|undefined} limit the maximum amount of candles to fetch * @param {object} params extra parameters specific to the ndax api endpoint * @returns {[[int]]} A list of candles ordered as timestamp, open, high, low, close, volume */ const omsId = this.safeInteger (this.options, 'omsId', 1); await this.loadMarkets (); const market = this.market (symbol); const request = { 'omsId': omsId, 'InstrumentId': market['id'], 'Interval': this.timeframes[timeframe], }; const duration = this.parseTimeframe (timeframe); const now = this.milliseconds (); if (since === undefined) { if (limit !== undefined) { request['FromDate'] = this.ymdhms (now - duration * limit * 1000); request['ToDate'] = this.ymdhms (now); } } else { request['FromDate'] = this.ymdhms (since); if (limit === undefined) { request['ToDate'] = this.ymdhms (now); } else { request['ToDate'] = this.ymdhms (this.sum (since, duration * limit * 1000)); } } const response = await this.publicGetGetTickerHistory (this.extend (request, params)); // // [ // [1607299260000,19069.32,19069.32,19069.32,19069.32,0,19069.31,19069.32,8,1607299200000], // [1607299320000,19069.32,19069.32,19069.32,19069.32,0,19069.31,19069.32,8,1607299260000], // [1607299380000,19069.32,19069.32,19069.32,19069.32,0,19069.31,19069.32,8,1607299320000], // ] // return this.parseOHLCVs (response, market, timeframe, since, limit); } parseTrade (trade, market = undefined) { // // fetchTrades (public) // // [ // 6913253, // 0 TradeId // 8, // 1 ProductPairCode // 0.03340802, // 2 Quantity // 19116.08, // 3 Price // 2543425077, // 4 Order1 // 2543425482, // 5 Order2 // 1606935922416, // 6 Tradetime // 0, // 7 Direction // 1, // 8 TakerSide // 0, // 9 BlockTrade // 0, // 10 Either Order1ClientId or Order2ClientId // ] // // fetchMyTrades (private) // // { // "OMSId":1, // "ExecutionId":16916567, // "TradeId":14476351, // "OrderId":2543565231, // "AccountId":449, // "AccountName":"igor@ccxt.trade", // "SubAccountId":0, // "ClientOrderId":0, // "InstrumentId":8, // "Side":"Sell", // "OrderType":"Market", // "Quantity":0.1230000000000000000000000000, // "RemainingQuantity":0.0000000000000000000000000000, // "Price":19069.310000000000000000000000, // "Value":2345.5251300000000000000000000, // "CounterParty":"7", // "OrderTradeRevision":1, // "Direction":"NoChange", // "IsBlockTrade":false, // "Fee":1.1727625650000000000000000000, // "FeeProductId":8, // "OrderOriginator":446, // "UserName":"igor@ccxt.trade", // "TradeTimeMS":1607565031569, // "MakerTaker":"Taker", // "AdapterTradeId":0, // "InsideBid":19069.310000000000000000000000, // "InsideBidSize":0.2400950000000000000000000000, // "InsideAsk":19069.320000000000000000000000, // "InsideAskSize":0.0997360000000000000000000000, // "IsQuote":false, // "CounterPartyClientUserId":1, // "NotionalProductId":2, // "NotionalRate":1.0000000000000000000000000000, // "NotionalValue":2345.5251300000000000000000000, // "NotionalHoldAmount":0, // "TradeTime":637431618315686826 // } // // fetchOrderTrades // // { // "Side":"Sell", // "OrderId":2543565235, // "Price":18600.000000000000000000000000, // "Quantity":0.0000000000000000000000000000, // "DisplayQuantity":0.0000000000000000000000000000, // "Instrument":8, // "Account":449, // "AccountName":"igor@ccxt.trade", // "OrderType":"Limit", // "ClientOrderId":0, // "OrderState":"FullyExecuted", // "ReceiveTime":1607585844956, // "ReceiveTimeTicks":637431826449564182, // "LastUpdatedTime":1607585844959, // "LastUpdatedTimeTicks":637431826449593893, // "OrigQuantity":0.1230000000000000000000000000, // "QuantityExecuted":0.1230000000000000000000000000, // "GrossValueExecuted":2345.3947500000000000000000000, // "ExecutableValue":0.0000000000000000000000000000, // "AvgPrice":19068.250000000000000000000000, // "CounterPartyId":0, // "ChangeReason":"Trade", // "OrigOrderId":2543565235, // "OrigClOrdId":0, // "EnteredBy":446, // "UserName":"igor@ccxt.trade", // "IsQuote":false, // "InsideAsk":19069.320000000000000000000000, // "InsideAskSize":0.0997360000000000000000000000, // "InsideBid":19068.250000000000000000000000, // "InsideBidSize":1.3300010000000000000000000000, // "LastTradePrice":19068.250000000000000000000000, // "RejectReason":"", // "IsLockedIn":false, // "CancelReason":"", // "OrderFlag":"0", // "UseMargin":false, // "StopPrice":0.0000000000000000000000000000, // "PegPriceType":"Unknown", // "PegOffset":0.0000000000000000000000000000, // "PegLimitOffset":0.0000000000000000000000000000, // "IpAddress":"x.x.x.x", // "ClientOrderIdUuid":null, // "OMSId":1 // } // let priceString = undefined; let amountString = undefined; let costString = undefined; let timestamp = undefined; let id = undefined; let marketId = undefined; let side = undefined; let orderId = undefined; let takerOrMaker = undefined; let fee = undefined; let type = undefined; if (Array.isArray (trade)) { priceString = this.safeString (trade, 3); amountString = this.safeString (trade, 2); timestamp = this.safeInteger (trade, 6); id = this.safeString (trade, 0); marketId = this.safeString (trade, 1); const takerSide = this.safeValue (trade, 8); side = takerSide ? 'sell' : 'buy'; orderId = this.safeString (trade, 4); } else { timestamp = this.safeInteger2 (trade, 'TradeTimeMS', 'ReceiveTime'); id = this.safeString (trade, 'TradeId'); orderId = this.safeString2 (trade, 'OrderId', 'OrigOrderId'); marketId = this.safeString2 (trade, 'InstrumentId', 'Instrument'); priceString = this.safeString (trade, 'Price'); amountString = this.safeString (trade, 'Quantity'); costString = this.safeString2 (trade, 'Value', 'GrossValueExecuted'); takerOrMaker = this.safeStringLower (trade, 'MakerTaker'); side = this.safeStringLower (trade, 'Side'); type = this.safeStringLower (trade, 'OrderType'); const feeCostString = this.safeString (trade, 'Fee'); if (feeCostString !== undefined) { const feeCurrencyId = this.safeString (trade, 'FeeProductId'); const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); fee = { 'cost': feeCostString, 'currency': feeCurrencyCode, }; } } const symbol = this.safeSymbol (marketId, market); return this.safeTrade ({ 'info': trade, 'id': id, 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'order': orderId, 'type': type, 'side': side, 'takerOrMaker': takerOrMaker, 'price': priceString, 'amount': amountString, 'cost': costString, 'fee': fee, }, market); } async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { /** * @method * @name ndax#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|undefined} since timestamp in ms of the earliest trade to fetch * @param {int|undefined} limit the maximum amount of trades to fetch * @param {object} params extra parameters specific to the ndax api endpoint * @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades} */ const omsId = this.safeInteger (this.options, 'omsId', 1); await this.loadMarkets (); const market = this.market (symbol); const request = { 'omsId': omsId, 'InstrumentId': market['id'], }; if (limit !== undefined) { request['Count'] = limit; } const response = await this.publicGetGetLastTrades (this.extend (request, params)); // // [ // [6913253,8,0.03340802,19116.08,2543425077,2543425482,1606935922416,0,1,0,0], // [6913254,8,0.01391671,19117.42,2543427510,2543427811,1606935927998,1,1,0,0], // [6913255,8,0.000006,19107.81,2543430495,2543430793,1606935933881,2,0,0,0], // ] // return this.parseTrades (response, market, since, limit); } async fetchAccounts (params = {}) { /** * @method * @name ndax#fetchAccounts * @description fetch all the accounts associated with a profile * @param {object} params extra parameters specific to the ndax api endpoint * @returns {object} a dictionary of [account structures]{@link https://docs.ccxt.com/en/latest/manual.html#account-structure} indexed by the account type */ if (!this.login) { throw new AuthenticationError (this.id + ' fetchAccounts() requires exchange.login email credential'); } const omsId = this.safeInteger (this.options, 'omsId', 1); this.checkRequiredCredentials (); const request = { 'omsId': omsId, 'UserId': this.uid, 'UserName': this.login, }; const response = await this.privateGetGetUserAccounts (this.extend (request, params)); // // [ 449 ] // comma-separated list of account ids // const result = []; for (let i = 0; i < response.length; i++) { const accountId = this.safeString (response, i); result.push ({ 'id': accountId, 'type': undefined, 'currency': undefined, 'info': accountId, }); } return result; } parseBalance (response) { const result = { 'info': response, 'timestamp': undefined, 'datetime': undefined, }; for (let i = 0; i < response.length; i++) { const balance = response[i]; const currencyId = this.safeString (balance, 'ProductId'); if (currencyId in this.currencies_by_id) { const code = this.safeCurrencyCode (currencyId); const account = this.account (); account['total'] = this.safeString (balance, 'Amount'); account['used'] = this.safeString (balance, 'Hold'); result[code] = account; } } return this.safeBalance (result); } async fetchBalance (params = {}) { /** * @method * @name ndax#fetchBalance * @description query for balance and get the amount of funds available for trading or funds locked in orders * @param {object} params extra parameters specific to the ndax api endpoint * @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure} */ const omsId = this.safeInteger (this.options, 'omsId', 1); await this.loadMarkets (); await this.loadAccounts (); const defaultAccountId = this.safeInteger2 (this.options, 'accountId', 'AccountId', parseInt (this.accounts[0]['id'])); const accountId = this.safeInteger2 (params, 'accountId', 'AccountId', defaultAccountId); params = this.omit (params, [ 'accountId', 'AccountId' ]); const request = { 'omsId': omsId, 'AccountId': accountId, }; const response = await this.privateGetGetAccountPositions (this.extend (request, params)); // // [ // { // "OMSId":1, // "AccountId":449, // "ProductSymbol":"BTC", // "ProductId":1, // "Amount":10.000000000000000000000000000, // "Hold":0, // "PendingDeposits":0.0000000000000000000000000000, // "PendingWithdraws":0.0000000000000000000000000000, // "TotalDayDeposits":10.000000000000000000000000000, // "TotalMonthDeposits":10.000000000000000000000000000, // "TotalYearDeposits":10.000000000000000000000000000, // "TotalDayDepositNotional":10.000000000000000000000000000, // "TotalMonthDepositNotional":10.000000000000000000000000000, // "TotalYearDepositNotional":10.000000000000000000000000000, // "TotalDayWithdraws":0, // "TotalMonthWithdraws":0, // "TotalYearWithdraws":0, // "TotalDayWithdrawNotional":0, // "TotalMonthWithdrawNotional":0, // "TotalYearWithdrawNotional":0, // "NotionalProductId":8, // "NotionalProductSymbol":"USDT", // "NotionalValue":10.000000000000000000000000000, // "NotionalHoldAmount":0, // "NotionalRate":1 // }, // ] // return this.parseBalance (response); } parseLedgerEntryType (type) { const types = { 'Trade': 'trade', 'Deposit': 'transaction', 'Withdraw': 'transaction', 'Transfer': 'transfer', 'OrderHold': 'trade', 'WithdrawHold': 'transaction', 'DepositHold': 'transaction', 'MarginHold': 'trade', 'ManualHold': 'trade', 'ManualEntry': 'trade', 'MarginAcquisition': 'trade', 'MarginRelinquish': 'trade', 'MarginQuoteHold': 'trade', }; return this.safeString (types, type, type); } parseLedgerEntry (item, currency = undefined) { // // { // "TransactionId":2663709493, // "ReferenceId":68, // "OMSId":1, // "AccountId":449, // "CR":10.000000000000000000000000000, // "DR":0.0000000000000000000000000000, // "Counterparty":3, // "TransactionType":"Other", // "ReferenceType":"Deposit", // "ProductId":1, // "Balance":10.000000000000000000000000000, // "TimeStamp":1607532331591 // } // const id = this.safeString (item, 'TransactionId'); const account = this.safeString (item, 'AccountId'); const referenceId = this.safeString (item, 'ReferenceId'); const referenceAccount = this.safeString (item, 'Counterparty'); const type = this.parseLedgerEntryType (this.safeString (item, 'ReferenceType')); const currencyId = this.safeString (item, 'ProductId'); const code = this.safeCurrencyCode (currencyId, currency); const credit = this.safeNumber (item, 'CR'); const debit = this.safeNumber (item, 'DR'); let amount = undefined; let direction = undefined; if (credit > 0) { amount = credit; direction = 'in'; } else if (debit > 0) { amount = debit; direction = 'out'; } const timestamp = this.safeInteger (item, 'TimeStamp'); let before = undefined; const after = this.safeNumber (item, 'Balance'); if (direction === 'out') { before = this.sum (after, amount); } else if (direction === 'in') { before = Math.max (0, after - amount); } const status = 'ok'; return { 'info': item, 'id': id, 'direction': direction, 'account': account, 'referenceId': referenceId, 'referenceAccount': referenceAccount, 'type': type, 'currency': code, 'amount': amount, 'before': before, 'after': after, 'status': status, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'fee': undefined, }; } async fetchLedger (code = undefined, since = undefined, limit = undefin