sfccxt
Version:
A JavaScript / Python / PHP cryptocurrency trading library with support for 130+ exchanges
1,131 lines (1,109 loc) • 84.6 kB
JavaScript
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { BadSymbol, ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, BadRequest } = require ('./base/errors');
const { TICK_SIZE } = require ('./base/functions/number');
const Precise = require ('./base/Precise');
// ---------------------------------------------------------------------------
module.exports = class currencycom extends Exchange {
describe () {
return this.deepExtend (super.describe (), {
'id': 'currencycom',
'name': 'Currency.com',
'countries': [ 'BY' ], // Belarus
'rateLimit': 100,
'certified': false,
'pro': true,
'version': 'v2',
// new metainfo interface
'has': {
'CORS': undefined,
'spot': true,
'margin': true,
'swap': true,
'future': false,
'option': false,
'addMargin': undefined,
'cancelAllOrders': undefined,
'cancelOrder': true,
'cancelOrders': undefined,
'createDepositAddress': undefined,
'createLimitOrder': true,
'createMarketOrder': true,
'createOrder': true,
'createStopLimitOrder': true,
'createStopMarketOrder': true,
'createStopOrder': true,
'editOrder': 'emulated',
'fetchAccounts': true,
'fetchBalance': true,
'fetchBidsAsks': undefined,
'fetchBorrowRate': undefined,
'fetchBorrowRateHistory': undefined,
'fetchBorrowRates': undefined,
'fetchBorrowRatesPerSymbol': undefined,
'fetchCanceledOrders': undefined,
'fetchClosedOrder': undefined,
'fetchClosedOrders': undefined,
'fetchCurrencies': true,
'fetchDeposit': undefined,
'fetchDepositAddress': true,
'fetchDepositAddresses': false,
'fetchDepositAddressesByNetwork': false,
'fetchDeposits': true,
'fetchFundingHistory': false,
'fetchFundingRate': false,
'fetchFundingRateHistory': false,
'fetchFundingRates': false,
'fetchIndexOHLCV': false,
'fetchL2OrderBook': true,
'fetchLedger': true,
'fetchLedgerEntry': false,
'fetchLeverage': true,
'fetchLeverageTiers': false,
'fetchMarginMode': false,
'fetchMarkets': true,
'fetchMarkOHLCV': false,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrder': undefined,
'fetchOpenOrders': true,
'fetchOrder': undefined,
'fetchOrderBook': true,
'fetchOrderBooks': undefined,
'fetchOrders': undefined,
'fetchOrderTrades': undefined,
'fetchPosition': undefined,
'fetchPositionMode': false,
'fetchPositions': true,
'fetchPositionsRisk': undefined,
'fetchPremiumIndexOHLCV': false,
'fetchTicker': true,
'fetchTickers': true,
'fetchTime': true,
'fetchTrades': true,
'fetchTradingFee': false,
'fetchTradingFees': true,
'fetchTradingLimits': undefined,
'fetchTransactionFee': undefined,
'fetchTransactionFees': undefined,
'fetchTransactions': true,
'fetchTransfers': undefined,
'fetchWithdrawal': undefined,
'fetchWithdrawals': true,
'reduceMargin': undefined,
'setLeverage': undefined,
'setMarginMode': undefined,
'setPositionMode': undefined,
'signIn': undefined,
'transfer': undefined,
'withdraw': undefined,
},
'timeframes': {
'1m': '1m',
'5m': '5m',
'10m': '10m',
'15m': '15m',
'30m': '30m',
'1h': '1h',
'4h': '4h',
'1d': '1d',
'1w': '1w',
},
'hostname': 'backend.currency.com',
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/83718672-36745c00-a63e-11ea-81a9-677b1f789a4d.jpg',
'api': {
'public': 'https://api-adapter.{hostname}/api',
'private': 'https://api-adapter.{hostname}/api',
'marketcap': 'https://marketcap.{hostname}/api',
},
'test': {
'public': 'https://demo-api-adapter.{hostname}/api',
'private': 'https://demo-api-adapter.{hostname}/api',
},
'www': 'https://www.currency.com',
'referral': 'https://currency.com/trading/signup?c=362jaimv&pid=referral',
'doc': [
'https://currency.com/api',
],
'fees': 'https://currency.com/fees-charges',
},
// rate-limits are described at: https://currency.com/api-get-started
'api': {
'public': {
'get': {
'v1/time': 1,
'v1/exchangeInfo': 1,
'v1/depth': 1,
'v1/aggTrades': 1,
'v1/klines': 1,
'v1/ticker/24hr': 1,
'v2/time': 1,
'v2/exchangeInfo': 1,
'v2/depth': 1,
'v2/aggTrades': 1,
'v2/klines': 1,
'v2/ticker/24hr': 1,
},
},
'marketcap': {
'get': {
'v1/assets': 1,
'v1/candles': 1,
'v1/orderbook': 1,
'v1/summary': 1,
'v1/ticker': 1,
'v1/token/assets': 1,
'v1/token/orderbook': 1,
'v1/token/summary': 1,
'v1/token/ticker': 1,
'v1/token/trades': 1,
'v1/token_crypto/OHLC': 1,
'v1/token_crypto/assets': 1,
'v1/token_crypto/orderbook': 1,
'v1/token_crypto/summary': 1,
'v1/token_crypto/ticker': 1,
'v1/token_crypto/trades': 1,
'v1/trades': 1,
},
},
'private': {
'get': {
'v1/account': 1,
'v1/currencies': 1,
'v1/deposits': 1,
'v1/depositAddress': 1,
'v1/ledger': 1,
'v1/leverageSettings': 1,
'v1/myTrades': 1,
'v1/openOrders': 1,
'v1/tradingPositions': 1,
'v1/tradingPositionsHistory': 1,
'v1/transactions': 1,
'v1/withdrawals': 1,
'v2/account': 1,
'v2/currencies': 1,
'v2/deposits': 1,
'v2/depositAddress': 1,
'v2/ledger': 1,
'v2/leverageSettings': 1,
'v2/myTrades': 1,
'v2/openOrders': 1,
'v2/tradingPositions': 1,
'v2/tradingPositionsHistory': 1,
'v2/transactions': 1,
'v2/withdrawals': 1,
},
'post': {
'v1/order': 1,
'v1/updateTradingPosition': 1,
'v1/updateTradingOrder': 1,
'v1/closeTradingPosition': 1,
'v2/order': 1,
'v2/updateTradingPosition': 1,
'v2/updateTradingOrder': 1,
'v2/closeTradingPosition': 1,
},
'delete': {
'v1/order': 1,
'v2/order': 1,
},
},
},
'fees': {
'trading': {
'feeSide': 'get',
'tierBased': false,
'percentage': true,
'taker': this.parseNumber ('0.002'),
'maker': this.parseNumber ('0.002'),
},
},
'precisionMode': TICK_SIZE,
// exchange-specific options
'options': {
'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel, 'FOK' = Fill Or Kill
'warnOnFetchOpenOrdersWithoutSymbol': true,
'recvWindow': 5 * 1000, // 5 sec, default
'timeDifference': 0, // the difference between system clock and Binance clock
'adjustForTimeDifference': false, // controls the adjustment logic upon instantiation
'parseOrderToPrecision': false, // force amounts and costs in parseOrder to precision
'newOrderRespType': {
'market': 'FULL', // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
'limit': 'RESULT', // we change it from 'ACK' by default to 'RESULT'
'stop': 'RESULT',
},
'leverage_markets_suffix': '_LEVERAGE',
'collateralCurrencies': [ 'USD', 'EUR', 'USDT' ],
},
'exceptions': {
'broad': {
'FIELD_VALIDATION_ERROR Cancel is available only for LIMIT order': InvalidOrder,
'API key does not exist': AuthenticationError,
'Order would trigger immediately.': InvalidOrder,
'Account has insufficient balance for requested action.': InsufficientFunds,
'Rest API trading is not enabled.': ExchangeNotAvailable,
'Combination of parameters invalid': BadRequest,
'Invalid limit price': BadRequest,
'Only leverage symbol allowed here:': BadSymbol, // when you fetchLeverage for non-leverage symbols, like 'BTC/USDT' instead of 'BTC/USDT_LEVERAGE': {"code":"-1128","msg":"Only leverage symbol allowed here: BTC/USDT"}
'market data service is not available': ExchangeNotAvailable, // {"code":"-1021","msg":"market data service is not available"}
'your time is ahead of server': InvalidNonce, // {"code":"-1021","msg":"your time is ahead of server"}
},
'exact': {
'-1000': ExchangeNotAvailable, // {"code":-1000,"msg":"An unknown error occured while processing the request."}
'-1013': InvalidOrder, // createOrder -> 'invalid quantity'/'invalid price'/MIN_NOTIONAL
// '-1021': InvalidNonce, // {"code":"-1021","msg":"your time is ahead of server"} // see above in the broad section
'-1022': AuthenticationError, // {"code":-1022,"msg":"Signature for this request is not valid."}
'-1030': InvalidOrder, // {"code":"-1030","msg":"You mentioned an invalid value for the price parameter."}
'-1100': InvalidOrder, // createOrder(symbol, 1, asdf) -> 'Illegal characters found in parameter 'price'
'-1104': ExchangeError, // Not all sent parameters were read, read 8 parameters but was sent 9
'-1025': AuthenticationError, // {"code":-1025,"msg":"Invalid API-key, IP, or permissions for action"}
'-1128': BadRequest, // {"code":-1128,"msg":"Combination of optional parameters invalid."} | {"code":"-1128","msg":"Combination of parameters invalid"} | {"code":"-1128","msg":"Invalid limit price"}
'-2010': ExchangeError, // generic error code for createOrder -> 'Account has insufficient balance for requested action.', {"code":-2010,"msg":"Rest API trading is not enabled."}, etc...
'-2011': OrderNotFound, // cancelOrder(1, 'BTC/USDT') -> 'UNKNOWN_ORDER'
'-2013': OrderNotFound, // fetchOrder (1, 'BTC/USDT') -> 'Order does not exist'
'-2014': AuthenticationError, // { "code":-2014, "msg": "API-key format invalid." }
'-2015': AuthenticationError, // "Invalid API-key, IP, or permissions for action."
},
},
'commonCurrencies': {
'ACN': 'Accenture',
'AMC': 'AMC Entertainment Holdings',
'BNS': 'Bank of Nova Scotia',
'CAR': 'Avis Budget Group Inc',
'CLR': 'Continental Resources',
'EDU': 'New Oriental Education & Technology Group Inc',
'ETN': 'Eaton',
'FOX': 'Fox Corporation',
'GM': 'General Motors Co',
'IQ': 'iQIYI',
'OSK': 'Oshkosh',
'PLAY': "Dave & Buster's Entertainment",
},
});
}
nonce () {
return this.milliseconds () - this.options['timeDifference'];
}
async fetchTime (params = {}) {
/**
* @method
* @name currencycom#fetchTime
* @description fetches the current integer timestamp in milliseconds from the exchange server
* @param {object} params extra parameters specific to the currencycom api endpoint
* @returns {int} the current integer timestamp in milliseconds from the exchange server
*/
const response = await this.publicGetV2Time (params);
//
// {
// "serverTime": 1590998366609
// }
//
return this.safeInteger (response, 'serverTime');
}
async fetchCurrencies (params = {}) {
/**
* @method
* @name currencycom#fetchCurrencies
* @description fetches all available currencies on an exchange
* @param {object} params extra parameters specific to the currencycom api endpoint
* @returns {object} an associative dictionary of currencies
*/
// requires authentication
if (!this.checkRequiredCredentials (false)) {
return undefined;
}
const response = await this.privateGetV2Currencies (params);
//
// [
// {
// "name": "Euro",
// "displaySymbol": "EUR.cx",
// "precision": "2",
// "type": "FIAT",
// "minWithdrawal": "90.0",
// "maxWithdrawal": "1.0E+8",
// "commissionMin": "0.02", // some instruments do not have this property
// "commissionPercent": "1.5", // some instruments do not have this property
// "minDeposit": "90.0",
// },
// {
// name: "Bitcoin",
// displaySymbol: "BTC",
// precision: "8",
// type: "CRYPTO", // only a few major currencies have this value, others like USDT have a value of "TOKEN"
// minWithdrawal: "0.00020",
// commissionFixed: "0.00010",
// minDeposit: "0.00010",
// },
// ]
//
const result = {};
for (let i = 0; i < response.length; i++) {
const currency = response[i];
const id = this.safeString (currency, 'displaySymbol');
const code = this.safeCurrencyCode (id);
const fee = this.safeNumber (currency, 'commissionFixed');
result[code] = {
'id': id,
'code': code,
'address': this.safeString (currency, 'baseAddress'),
'type': this.safeStringLower (currency, 'type'),
'name': this.safeString (currency, 'name'),
'active': undefined,
'deposit': undefined,
'withdraw': undefined,
'fee': fee,
'precision': this.parseNumber (this.parsePrecision (this.safeString (currency, 'precision'))),
'limits': {
'amount': {
'min': undefined,
'max': undefined,
},
'withdraw': {
'min': this.safeNumber (currency, 'minWithdrawal'),
'max': this.safeNumber (currency, 'maxWithdrawal'),
},
'deposit': {
'min': this.safeNumber (currency, 'minDeposit'),
'max': undefined,
},
},
'info': currency,
};
}
return result;
}
async fetchMarkets (params = {}) {
/**
* @method
* @name currencycom#fetchMarkets
* @description retrieves data on all markets for currencycom
* @param {object} params extra parameters specific to the exchange api endpoint
* @returns {[object]} an array of objects representing market data
*/
const response = await this.publicGetV2ExchangeInfo (params);
//
// {
// timezone: "UTC",
// serverTime: "1645186287261",
// rateLimits: [
// { rateLimitType: "REQUEST_WEIGHT", interval: "MINUTE", intervalNum: "1", limit: "1200" },
// { rateLimitType: "ORDERS", interval: "SECOND", intervalNum: "1", limit: "10" },
// { rateLimitType: "ORDERS", interval: "DAY", intervalNum: "1", limit: "864000" },
// ],
// exchangeFilters: [],
// symbols: [
// {
// symbol: "BTC/USDT", // BTC/USDT, BTC/USDT_LEVERAGE
// name: "Bitcoin / Tether",
// status: "TRADING", // TRADING, BREAK, HALT
// baseAsset: "BTC",
// baseAssetPrecision: "4",
// quoteAsset: "USDT",
// quoteAssetId: "USDT", // USDT, USDT_LEVERAGE
// quotePrecision: "4",
// orderTypes: [ "LIMIT", "MARKET" ], // LIMIT, MARKET, STOP
// filters: [
// { filterType: "LOT_SIZE", minQty: "0.0001", maxQty: "100", stepSize: "0.0001", },
// { filterType: "MIN_NOTIONAL", minNotional: "5", },
// ],
// marketModes: [ "REGULAR" ], // CLOSE_ONLY, LONG_ONLY, REGULAR
// marketType: "SPOT", // SPOT, LEVERAGE
// longRate: -0.0684932, // LEVERAGE only
// shortRate: -0.0684932, // LEVERAGE only
// swapChargeInterval: 1440, // LEVERAGE only
// country: "",
// sector: "",
// industry: "",
// tradingHours: "UTC; Mon - 22:00, 22:05 -; Tue - 22:00, 22:05 -; Wed - 22:00, 22:05 -; Thu - 22:00, 22:05 -; Fri - 22:00, 23:01 -; Sat - 22:00, 22:05 -; Sun - 21:00, 22:05 -",
// tickSize: "0.01",
// tickValue: "403.4405", // not available in BTC/USDT_LEVERAGE, but available in BTC/USD_LEVERAGE
// exchangeFee: "0.2", // SPOT only
// tradingFee: 0.075, // LEVERAGE only
// makerFee: -0.025, // LEVERAGE only
// takerFee: 0.06, // LEVERAGE only
// maxSLGap: 50, // LEVERAGE only
// minSLGap: 1, // LEVERAGE only
// maxTPGap: 50, // LEVERAGE only
// minTPGap: 0.5, // LEVERAGE only
// assetType: "CRYPTOCURRENCY",
// },
// ]
// }
//
if (this.options['adjustForTimeDifference']) {
await this.loadTimeDifference ();
}
const markets = this.safeValue (response, 'symbols', []);
const result = [];
for (let i = 0; i < markets.length; i++) {
const market = markets[i];
const id = this.safeString (market, 'symbol');
const baseId = this.safeString (market, 'baseAsset');
const quoteId = this.safeString (market, 'quoteAsset');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
let symbol = base + '/' + quote;
const type = this.safeString (market, 'marketType');
const spot = (type === 'SPOT');
const futures = false;
const swap = (type === 'LEVERAGE');
const margin = swap; // as we decided to set
if (swap) {
symbol = symbol.replace (this.options['leverage_markets_suffix'], '');
symbol += ':' + quote;
}
const active = this.safeString (market, 'status') === 'TRADING';
// to set taker & maker fees, we use one from the below data - pairs either have 'exchangeFee' or 'tradingFee', if none of them (rare cases), then they should have 'takerFee & makerFee'
const exchangeFee = this.safeString2 (market, 'exchangeFee', 'tradingFee');
let makerFee = this.safeString (market, 'makerFee', exchangeFee);
let takerFee = this.safeString (market, 'takerFee', exchangeFee);
makerFee = Precise.stringDiv (makerFee, '100');
takerFee = Precise.stringDiv (takerFee, '100');
const filters = this.safeValue (market, 'filters', []);
const filtersByType = this.indexBy (filters, 'filterType');
let limitPriceMin = undefined;
let limitPriceMax = undefined;
let precisionPrice = this.safeNumber (market, 'tickSize');
if ('PRICE_FILTER' in filtersByType) {
const filter = this.safeValue (filtersByType, 'PRICE_FILTER', {});
precisionPrice = this.safeNumber (filter, 'tickSize');
// PRICE_FILTER reports zero values for maxPrice
// since they updated filter types in November 2018
// https://github.com/ccxt/ccxt/issues/4286
// therefore limits['price']['max'] doesn't have any meaningful value except undefined
limitPriceMin = this.safeNumber (filter, 'minPrice');
const maxPrice = this.safeString (filter, 'maxPrice');
if ((maxPrice !== undefined) && (Precise.stringGt (maxPrice, '0'))) {
limitPriceMax = maxPrice;
}
}
let precisionAmount = this.parseNumber (this.parsePrecision (this.safeString (market, 'baseAssetPrecision')));
let limitAmount = {
'min': undefined,
'max': undefined,
};
if ('LOT_SIZE' in filtersByType) {
const filter = this.safeValue (filtersByType, 'LOT_SIZE', {});
precisionAmount = this.safeNumber (filter, 'stepSize');
limitAmount = {
'min': this.safeNumber (filter, 'minQty'),
'max': this.safeNumber (filter, 'maxQty'),
};
}
let limitMarket = {
'min': undefined,
'max': undefined,
};
if ('MARKET_LOT_SIZE' in filtersByType) {
const filter = this.safeValue (filtersByType, 'MARKET_LOT_SIZE', {});
limitMarket = {
'min': this.safeNumber (filter, 'minQty'),
'max': this.safeNumber (filter, 'maxQty'),
};
}
let costMin = undefined;
if ('MIN_NOTIONAL' in filtersByType) {
const filter = this.safeValue (filtersByType, 'MIN_NOTIONAL', {});
costMin = this.safeNumber (filter, 'minNotional');
}
const isContract = swap || futures;
result.push ({
'id': id,
'symbol': symbol,
'base': base,
'quote': quote,
'settle': undefined,
'baseId': baseId,
'quoteId': quoteId,
'settleId': undefined,
'type': type,
'spot': spot,
'margin': margin,
'swap': swap,
'future': futures,
'option': false,
'active': active,
'contract': isContract,
'linear': isContract ? true : undefined,
'inverse': undefined,
'taker': this.parseNumber (takerFee),
'maker': this.parseNumber (makerFee),
'contractSize': undefined,
'expiry': undefined,
'expiryDatetime': undefined,
'strike': undefined,
'optionType': undefined,
'precision': {
'amount': precisionAmount,
'price': precisionPrice,
},
'limits': {
'leverage': {
'min': undefined,
'max': undefined,
},
'amount': limitAmount,
'market': limitMarket,
'price': {
'min': limitPriceMin,
'max': this.parseNumber (limitPriceMax),
},
'cost': {
'min': costMin,
'max': undefined,
},
},
'info': market,
});
}
return result;
}
async fetchAccounts (params = {}) {
/**
* @method
* @name currencycom#fetchAccounts
* @description fetch all the accounts associated with a profile
* @param {object} params extra parameters specific to the currencycom 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
*/
const response = await this.privateGetV2Account (params);
//
// {
// "makerCommission": "0.20",
// "takerCommission": "0.20",
// "buyerCommission": "0.20",
// "sellerCommission": "0.20",
// "canTrade": true,
// "canWithdraw": true,
// "canDeposit": true,
// "updateTime": "1645266330",
// "userId": "644722",
// "balances": [
// {
// "accountId": "120702016179403605",
// "collateralCurrency": false,
// "asset": "CAKE",
// "free": "3.1",
// "locked": "0.0",
// "default": false,
// },
// {
// "accountId": "109698017713125316",
// "collateralCurrency": true,
// "asset": "USD",
// "free": "17.58632",
// "locked": "0.0",
// "default": true,
// }
// ]
// }
//
const accounts = this.safeValue (response, 'balances', []);
const result = [];
for (let i = 0; i < accounts.length; i++) {
const account = accounts[i];
const accountId = this.safeInteger (account, 'accountId');
const currencyId = this.safeString (account, 'asset');
const currencyCode = this.safeCurrencyCode (currencyId);
result.push ({
'id': accountId,
'type': undefined,
'currency': currencyCode,
'info': account,
});
}
return result;
}
async fetchTradingFees (params = {}) {
/**
* @method
* @name currencycom#fetchTradingFees
* @description fetch the trading fees for multiple markets
* @param {object} params extra parameters specific to the currencycom api endpoint
* @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/en/latest/manual.html#fee-structure} indexed by market symbols
*/
await this.loadMarkets ();
const response = await this.privateGetV2Account (params);
//
// {
// makerCommission: '0.20',
// takerCommission: '0.20',
// buyerCommission: '0.20',
// sellerCommission: '0.20',
// canTrade: true,
// canWithdraw: true,
// canDeposit: true,
// updateTime: '1645738976',
// userId: '-1924114235',
// balances: []
// }
//
const makerFee = this.safeNumber (response, 'makerCommission');
const takerFee = this.safeNumber (response, 'takerCommission');
const result = {};
for (let i = 0; i < this.symbols.length; i++) {
const symbol = this.symbols[i];
result[symbol] = {
'info': response,
'symbol': symbol,
'maker': makerFee,
'taker': takerFee,
'percentage': true,
'tierBased': false,
};
}
return result;
}
parseBalance (response, type = undefined) {
//
// {
// "makerCommission":0.20,
// "takerCommission":0.20,
// "buyerCommission":0.20,
// "sellerCommission":0.20,
// "canTrade":true,
// "canWithdraw":true,
// "canDeposit":true,
// "updateTime":1591056268,
// "balances":[
// {
// "accountId":5470306579272368,
// "collateralCurrency":true,
// "asset":"ETH",
// "free":0.0,
// "locked":0.0,
// "default":false,
// },
// ]
// }
//
const result = { 'info': response };
const balances = this.safeValue (response, 'balances', []);
for (let i = 0; i < balances.length; i++) {
const balance = balances[i];
const currencyId = this.safeString (balance, 'asset');
const code = this.safeCurrencyCode (currencyId);
const account = this.account ();
account['free'] = this.safeString (balance, 'free');
account['used'] = this.safeString (balance, 'locked');
result[code] = account;
}
return this.safeBalance (result);
}
async fetchBalance (params = {}) {
/**
* @method
* @name currencycom#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 currencycom api endpoint
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure}
*/
await this.loadMarkets ();
const response = await this.privateGetV2Account (params);
//
// {
// "makerCommission": "0.20",
// "takerCommission": "0.20",
// "buyerCommission": "0.20",
// "sellerCommission": "0.20",
// "canTrade": true,
// "canWithdraw": true,
// "canDeposit": true,
// "updateTime": "1645266330",
// "userId": "644722",
// "balances": [
// {
// "accountId": "120702016179403605",
// "collateralCurrency": false,
// "asset": "CAKE",
// "free": "1.784",
// "locked": "0.0",
// "default": false,
// },
// {
// "accountId": "109698017413175316",
// "collateralCurrency": true,
// "asset": "USD",
// "free": "7.58632",
// "locked": "0.0",
// "default": true,
// }
// ]
// }
//
return this.parseBalance (response);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
/**
* @method
* @name currencycom#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 currencycom 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
*/
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
};
if (limit !== undefined) {
request['limit'] = limit; // default 100, max 1000, valid limits 5, 10, 20, 50, 100, 500, 1000, 5000
}
const response = await this.publicGetV2Depth (this.extend (request, params));
//
// {
// "lastUpdateId":1590999849037,
// "asks":[
// [0.02495,60.0345],
// [0.02496,34.1],
// ...
// ],
// "bids":[
// [0.02487,72.4144854],
// [0.02486,24.043],
// ...
// ]
// }
//
const orderbook = this.parseOrderBook (response, symbol);
orderbook['nonce'] = this.safeInteger (response, 'lastUpdateId');
return orderbook;
}
parseTicker (ticker, market = undefined) {
//
// fetchTicker
//
// {
// "symbol":"ETH/BTC",
// "priceChange":"0.00030",
// "priceChangePercent":"1.21",
// "weightedAvgPrice":"0.02481",
// "prevClosePrice":"0.02447",
// "lastPrice":"0.02477",
// "lastQty":"60.0",
// "bidPrice":"0.02477",
// "askPrice":"0.02484",
// "openPrice":"0.02447",
// "highPrice":"0.02524",
// "lowPrice":"0.02438",
// "volume":"11.97",
// "quoteVolume":"0.298053",
// "openTime":1590969600000,
// "closeTime":1591000072693
// }
//
// fetchTickers
//
// {
// "symbol": "SHIB/USD_LEVERAGE",
// "weightedAvgPrice": "0.000027595",
// "lastPrice": "0.00002737",
// "lastQty": "1.11111111E8",
// "bidPrice": "0.00002737",
// "askPrice": "0.00002782",
// "highPrice": "0.00002896",
// "lowPrice": "0.00002738",
// "volume": "16472160000",
// "quoteVolume": "454796.3376",
// "openTime": "1645187472000",
// "closeTime": "1645273872000",
// }
//
// ws:marketData.subscribe
//
// {
// "symbolName":"TXN",
// "bid":139.85,
// "bidQty":2500,
// "ofr":139.92000000000002,
// "ofrQty":2500,
// "timestamp":1597850971558
// }
//
const timestamp = this.safeInteger2 (ticker, 'closeTime', 'timestamp');
const marketId = this.safeString2 (ticker, 'symbol', 'symbolName');
market = this.safeMarket (marketId, market, '/');
const last = this.safeString (ticker, 'lastPrice');
return this.safeTicker ({
'symbol': market['symbol'],
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'high': this.safeString (ticker, 'highPrice'),
'low': this.safeString (ticker, 'lowPrice'),
'bid': this.safeString2 (ticker, 'bidPrice', 'bid'),
'bidVolume': this.safeString (ticker, 'bidQty'),
'ask': this.safeString2 (ticker, 'askPrice', 'ofr'),
'askVolume': this.safeString (ticker, 'ofrQty'),
'vwap': this.safeString (ticker, 'weightedAvgPrice'),
'open': this.safeString (ticker, 'openPrice'),
'close': last,
'last': last,
'previousClose': this.safeString (ticker, 'prevClosePrice'), // previous day close
'change': this.safeString (ticker, 'priceChange'),
'percentage': this.safeString (ticker, 'priceChangePercent'),
'average': undefined,
'baseVolume': this.safeString (ticker, 'volume'),
'quoteVolume': this.safeString (ticker, 'quoteVolume'),
'info': ticker,
}, market);
}
async fetchTicker (symbol, params = {}) {
/**
* @method
* @name currencycom#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 currencycom api endpoint
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure}
*/
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
};
const response = await this.publicGetV2Ticker24hr (this.extend (request, params));
//
// {
// "symbol":"ETH/BTC",
// "priceChange":"0.00030",
// "priceChangePercent":"1.21",
// "weightedAvgPrice":"0.02481",
// "prevClosePrice":"0.02447",
// "lastPrice":"0.02477",
// "lastQty":"60.0",
// "bidPrice":"0.02477",
// "askPrice":"0.02484",
// "openPrice":"0.02447",
// "highPrice":"0.02524",
// "lowPrice":"0.02438",
// "volume":"11.97",
// "quoteVolume":"0.298053",
// "openTime":1590969600000,
// "closeTime":1591000072693
// }
//
return this.parseTicker (response, market);
}
async fetchTickers (symbols = undefined, params = {}) {
/**
* @method
* @name currencycom#fetchTickers
* @description fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours 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 currencycom api endpoint
* @returns {object} an array of [ticker structures]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure}
*/
await this.loadMarkets ();
const response = await this.publicGetV2Ticker24hr (params);
//
// [
// {
// "symbol": "SHIB/USD_LEVERAGE",
// "weightedAvgPrice": "0.000027595",
// "lastPrice": "0.00002737",
// "lastQty": "1.11111111E8",
// "bidPrice": "0.00002737",
// "askPrice": "0.00002782",
// "highPrice": "0.00002896",
// "lowPrice": "0.00002738",
// "volume": "16472160000",
// "quoteVolume": "454796.3376",
// "openTime": "1645187472000",
// "closeTime": "1645273872000",
// }
// ]
//
return this.parseTickers (response, symbols);
}
parseOHLCV (ohlcv, market = undefined) {
//
// [
// 1590971040000,
// "0.02454",
// "0.02456",
// "0.02452",
// "0.02456",
// 249
// ]
//
return [
this.safeInteger (ohlcv, 0),
this.safeNumber (ohlcv, 1),
this.safeNumber (ohlcv, 2),
this.safeNumber (ohlcv, 3),
this.safeNumber (ohlcv, 4),
this.safeNumber (ohlcv, 5),
];
}
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name currencycom#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 currencycom api endpoint
* @returns {[[int]]} A list of candles ordered as timestamp, open, high, low, close, volume
*/
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
'interval': this.timeframes[timeframe],
};
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
request['limit'] = limit; // default 500, max 1000
}
const response = await this.publicGetV2Klines (this.extend (request, params));
//
// [
// [1590971040000,"0.02454","0.02456","0.02452","0.02456",249],
// [1590971100000,"0.02455","0.02457","0.02452","0.02456",300],
// [1590971160000,"0.02455","0.02456","0.02453","0.02454",286],
// ]
//
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
parseTrade (trade, market = undefined) {
//
// fetchTrades (public aggregate trades)
//
// {
// "a":"1658318071", // Aggregate tradeId
// "p":"0.02476", // Price
// "q":"0.0", // Official doc says: "Quantity (should be ignored)"
// "T":"1591001423382", // Epoch timestamp in MS
// "m":false // Was the buyer the maker
// }
//
// createOrder fills (private)
//
// {
// "price": "9807.05",
// "qty": "0.01",
// "commission": "0",
// "commissionAsset": "dUSD"
// }
//
// fetchMyTrades
//
// {
// "symbol": "DOGE/USD",
// "id": "116046000",
// "orderId": "00000000-0000-0000-0000-000006dbb8ad",
// "price": "0.14094",
// "qty": "40.0",
// "commission": "0.01",
// "commissionAsset": "USD",
// "time": "1645283022351",
// "buyer": false,
// "maker": false,
// "isBuyer": false,
// "isMaker": false
// }
//
const timestamp = this.safeInteger2 (trade, 'T', 'time');
const priceString = this.safeString2 (trade, 'p', 'price');
const amountString = this.safeString2 (trade, 'q', 'qty');
const id = this.safeString2 (trade, 'a', 'id');
let side = undefined;
const orderId = this.safeString (trade, 'orderId');
let takerOrMaker = undefined;
if ('m' in trade) {
side = trade['m'] ? 'sell' : 'buy'; // this is reversed intentionally [TODO: needs reason to be mentioned]
takerOrMaker = 'taker'; // in public trades, it's always taker
} else if ('isBuyer' in trade) {
side = (trade['isBuyer']) ? 'buy' : 'sell'; // this is a true side
takerOrMaker = trade['isMaker'] ? 'maker' : 'taker';
}
let fee = undefined;
if ('commission' in trade) {
fee = {
'cost': this.safeString (trade, 'commission'),
'currency': this.safeCurrencyCode (this.safeString (trade, 'commissionAsset')),
};
}
const marketId = this.safeString (trade, 'symbol');
const symbol = this.safeSymbol (marketId, market);
return this.safeTrade ({
'id': id,
'order': orderId,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'symbol': symbol,
'type': undefined,
'takerOrMaker': takerOrMaker,
'side': side,
'price': priceString,
'amount': amountString,
'cost': undefined,
'fee': fee,
'info': trade,
}, market);
}
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name currencycom#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 currencycom api endpoint
* @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
*/
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
// 'limit': 500, // default 500, max 1000
};
if (limit !== undefined) {
request['limit'] = limit; // default 500, max 1000
}
if (since !== undefined) {
request['startTime'] = since;
}
const response = await this.publicGetV2AggTrades (this.extend (request, params));
//
// [
// {
// "a":"1658318071", // Aggregate tradeId
// "p":"0.02476", // Price
// "q":"0.0", // Official doc says: "Quantity (should be ignored)"
// "T":"1591001423382", // Epoch timestamp in MS
// "m":false // Was the buyer the maker
// },
// ]
//
return this.parseTrades (response, market, since, limit);
}
parseOrder (order, market = undefined) {
//
// createOrder
//
// limit
//
// {
// "symbol": "BTC/USD",
// "orderId": "00000000-0000-0000-0000-000006eacaa0",
// "transactTime": "1645281669295",
// "price": "30000.00000000",
// "origQty": "0.0002",
// "executedQty": "0.0", // positive for BUY, negative for SELL
// "status": "NEW",
// "timeInForce": "GTC",
// "type": "LIMIT",
// "side": "BUY",
// }
//