sfccxt
Version:
A JavaScript / Python / PHP cryptocurrency trading library with support for 130+ exchanges
1,072 lines (1,052 loc) • 123 kB
JavaScript
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { ArgumentsRequired, AuthenticationError, ExchangeError, InsufficientFunds, OrderNotFound, PermissionDenied, BadRequest, BadSymbol, DDoSProtection, InvalidOrder, AccountSuspended } = require ('./base/errors');
const { TICK_SIZE } = require ('./base/functions/number');
const Precise = require ('./base/Precise');
// ---------------------------------------------------------------------------
module.exports = class stex extends Exchange {
describe () {
return this.deepExtend (super.describe (), {
'id': 'stex',
'name': 'STEX', // formerly known as stocks.exchange
'countries': [ 'EE' ], // Estonia
'rateLimit': 1000 / 3, // https://help.stex.com/en/articles/2815043-api-3-rate-limits
'certified': false,
// new metainfo interface
'has': {
'CORS': undefined,
'spot': true,
'margin': false,
'swap': false,
'future': false,
'option': false,
'addMargin': false,
'cancelAllOrders': true,
'cancelOrder': true,
'createDepositAddress': true,
'createMarketOrder': false,
'createOrder': true,
'createReduceOnlyOrder': false,
'fetchBalance': true,
'fetchBorrowRate': false,
'fetchBorrowRateHistories': false,
'fetchBorrowRateHistory': false,
'fetchBorrowRates': false,
'fetchBorrowRatesPerSymbol': false,
'fetchClosedOrder': true,
'fetchCurrencies': true,
'fetchDeposit': true,
'fetchDepositAddress': true,
'fetchDeposits': true,
'fetchDepositWithdrawFee': 'emulated',
'fetchDepositWithdrawFees': true,
'fetchFundingHistory': false,
'fetchFundingRate': false,
'fetchFundingRateHistory': false,
'fetchFundingRates': false,
'fetchIndexOHLCV': false,
'fetchLeverage': false,
'fetchLeverageTiers': false,
'fetchMarginMode': false,
'fetchMarkets': true,
'fetchMarkOHLCV': false,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenInterestHistory': false,
'fetchOpenOrders': true,
'fetchOrder': true,
'fetchOrderBook': true,
'fetchOrderTrades': true,
'fetchPosition': false,
'fetchPositionMode': false,
'fetchPositions': false,
'fetchPositionsRisk': false,
'fetchPremiumIndexOHLCV': false,
'fetchTicker': true,
'fetchTickers': true,
'fetchTime': true,
'fetchTrades': true,
'fetchTradingFee': true,
'fetchTradingFees': false,
'fetchTransactionFees': true,
'fetchWithdrawal': true,
'fetchWithdrawals': true,
'reduceMargin': false,
'setLeverage': false,
'setMarginMode': false,
'setPositionMode': false,
'transfer': true,
'withdraw': true,
},
'version': 'v3',
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/69680782-03fd0b80-10bd-11ea-909e-7f603500e9cc.jpg',
'api': {
'rest': 'https://api3.stex.com',
},
'www': 'https://www.stex.com',
'doc': [
'https://apidocs.stex.com/',
'https://help.stex.com/en/collections/1593608-api-v3-documentation',
],
'fees': 'https://app.stex.com/en/pairs-specification',
'referral': 'https://app.stex.com?ref=36416021',
},
'requiredCredentials': {
'apiKey': false,
'secret': false,
'token': true,
},
'timeframes': {
'1m': '1',
'5m': '5',
'30m': '30',
'1h': '60',
'4h': '240',
'12h': '720',
'1d': '1D', // default
},
'api': {
'public': {
'get': {
'currencies': 1, // Available Currencies
'currencies/{currencyId}': 1, // Get currency info
'markets': 1, // Available markets
'pairs-groups': 1, // Available currency pairs groups (as displayed at stex trading page)
'currency_pairs/list/{code}': 1, // Available currency pairs
'currency_pairs/group/{currencyPairGroupId}': 1, // Available currency pairs for a given group
'currency_pairs/{currencyPairId}': 1, // Get currency pair information
'ticker': 1, // Tickers list for all currency pairs
'ticker/{currencyPairId}': 1, // Ticker for currency pair
'trades/{currencyPairId}': 1, // Trades for given currency pair
'orderbook/{currencyPairId}': 1, // Orderbook for given currency pair
'chart/{currencyPairId}/{candlesType}': 1, // A list of candles for given currency pair
'deposit-statuses': 1, // Available Deposit Statuses
'deposit-statuses/{statusId}': 1, // Get deposit status info
'withdrawal-statuses': 1, // Available Withdrawal Statuses
'withdrawal-statuses/{statusId}': 1, // Get status info
'ping': 1, // Test API is working and get server time
'mobile-versions': 1, // Shows the official mobile applications data
'twitter': 1, // Get the last 20 posts (stex.com) on Twitter
},
},
'trading': {
'get': {
'fees/{currencyPairId}': 1, // Returns the user's fees for a given currency pair
'orders': 12, // List your currently open orders
'orders/{currencyPairId}': 6, // List your currently open orders for given currency pair
'order/{orderId}': 12, // Get a single order
},
'post': {
'orders/{currencyPairId}': 1.5, // Create new order and put it to the orders processing queue
'orders/bulk/{currencyPairId}': 12, // Create new orders in a bulk and put it to the orders processing queue
},
'delete': {
'orders': 30, // Delete all active orders
'orders/{currencyPairId}': 12, // Delete active orders for given currency pair
'order/{orderId}': 1.5, // Cancel order
},
},
'reports': {
'get': {
'currencies': 12, // Get a list of currencies user had any activity in
'currency_pairs': 12, // Gets the list of currency pairs the user had orders in for all the time
'orders': 12, // Get past orders
'orders/{orderId}': 12, // Get specified order details
'trades/{currencyPairId}': 12, // Get a list of user trades according to request parameters
'background/{listMode}': 12, // Get reports list for category
'background/{id}': 12, // Get some report info
'background/download/{id}': 12, // Get file by id
},
'post': {
'background/create': 12, // Create new report
},
'delete': {
'background/{id}': 12, // Remove report by id
},
},
'profile': {
'get': {
'info': 3, // Account information
'wallets': 3, // Get a list of user wallets
'wallets/{walletId}': 3, // Single wallet information
'wallets/address/{walletId}': 3, // Get deposit address for given wallet
'deposits': 3, // Get a list of deposits made by user
'deposits/{id}': 3, // Get deposit by id
'rewards': 3, // Get a list of rewards obtained by user (e.g. in trading competitions)
'rewards/{id}': 3, // Get reward by id
'addressbook': 3, // Get a list of user address book items
'addressbook/{itemId}': 3, // Single address book item
'withdrawals': 3, // Get a list of withdrawals made by user
'withdrawals/{id}': 3, // Get withdrawal by id
'notifications': 3, // Get notifications
'notifications/price': 3, // Get a list of active price alerts
'favorite/currency_pairs': 3, // Get favorite currency pairs
'token-scopes': 3, // Get current token scopes
},
'post': {
'wallets/burn/{walletId}': 3, // Burns the given wallet
'wallets/{walletId}/hold_amount': 3, // Move a part of the funds on the wallet to the "hold" to keep it safe from trading
'wallets/{currencyId}': 3, // Create a wallet for given currency
'wallets/address/{walletId}': 3, // Create new deposit address
'addressbook/disable_item/{itemId}': 3, // Disables the address book item
'addressbook/enable_item/{itemId}': 3, // Enable the address book item
'addressbook/enable_strict_wd': 3, // Restrict the withdrawals to only addresses that are active in addressbook
'addressbook/disable_strict_wd': 3, // Remove restriction to withdraw to only addresses that are active in addressbook. E.g. allow to withdraw to any address.
'withdraw': 30, // Create withdrawal request
'notifications/price': 3, // Create new price alert
'referral/program': 3, // Create referral program
'referral/insert/{code}': 3, // Insert referral code
'referral/bonus_transfer/{currencyId}': 3, // Transfer referral bonuses balance to main balance for given currency
},
'put': {
'favorite/currency_pairs/set': 3, // Set favorite currency pairs
},
'delete': {
'addressbook/{itemId}': 3, // Deletes address book item
'withdraw/{withdrawalId}': 30, // Cancel unconfirmed withdrawal
'notifications/price/{priceAlertId}': 3, // Delete the price alert by ID
},
},
'verification': {
'get': {
'countries': 1, // Countries list, beta
'status': 1, // Get status verify
'fractal/url': 1, // Generate verify url from Fractal
'smart-id': 1, // Check Smart-ID verify
'stex': 1, // Get information about your KYC, beta
'cryptonomica/code': 1, // Get Discount code for Cryptonomica
},
'post': {
'smart-id': 1, // Initialization Smart-ID verify (Send request to Smart-ID App)
'stex': 1, // Update information regarding of your KYC verification, beta
'cryptonomica': 1, // Add verification from Cryptonomica
},
},
'settings': {
'get': {
'notifications/{event}': 1, // User event notification settings
'notifications': 1, // User events notification settings
},
'put': {
'notifications': 1, // Set notification settings
'notifications/set': 1,
},
},
},
'fees': {
'trading': {
'tierBased': false,
'percentage': true,
'taker': this.parseNumber ('0.002'),
'maker': this.parseNumber ('0.002'),
},
},
'commonCurrencies': {
'BC': 'Bitcoin Confidential',
'BITS': 'Bitcoinus',
'BITSW': 'BITS',
'BHD': 'Bithold',
'BTH': 'Bithereum',
'MPH': 'Chasyr Token',
'SBTC': 'SBTCT', // SiamBitcoin
},
'options': {
'parseOrderToPrecision': false,
'networks': {
'ERC20': 5,
'ETH': 5,
'OMNI': 10,
'XLM': 20,
'BEP2': 22,
'TRC20': 24,
'TRX': 24,
'SOL': 25,
'BEP20': 501,
},
'accountsByType': {
'spot': 'spot',
'hold': 'hold',
'funding': 'funding',
'referal': 'referal',
},
'transfer': {
'fillResponseFromRequest': true,
},
},
'precisionMode': TICK_SIZE,
'exceptions': {
'exact': {
// {"success":false,"message":"Wrong parameters","errors":{"candleType":["Invalid Candle Type!"]}}
// {"success":false,"message":"Wrong parameters","errors":{"time":["timeStart or timeEnd is less then 1"]}}
'Wrong parameters': BadRequest,
'Unauthenticated.': AuthenticationError, // {"message":"Unauthenticated."}
'Server Error': ExchangeError, // { "message": "Server Error" }
'This feature is only enabled for users verifies by Cryptonomica': PermissionDenied, // {"success":false,"message":"This feature is only enabled for users verifies by Cryptonomica"}
'Too Many Attempts.': DDoSProtection, // { "message": "Too Many Attempts." }
'Selected Pair is disabled': BadSymbol, // {"success":false,"message":"Selected Pair is disabled"}
'Invalid scope(s) provided.': PermissionDenied, // { "message": "Invalid scope(s) provided." }
'The maximum amount of open orders with the same price cannot exceed 10': InvalidOrder, // { "success":false,"message":"The maximum amount of open orders with the same price cannot exceed 10" }
'Your account not verified!': AccountSuspended, // {"success":false,"message":"Your account not verified!","unified_message":{"message_id":"verification_required_to_continue","substitutions":null},"notice":"Please be informed that parameter `message` is deprecated and will be removed. Use unified_message instead."}
},
'broad': {
'Not enough': InsufficientFunds, // {"success":false,"message":"Not enough ETH"}
},
},
});
}
async fetchCurrencies (params = {}) {
/**
* @method
* @name stex#fetchCurrencies
* @description fetches all available currencies on an exchange
* @param {object} params extra parameters specific to the stex api endpoint
* @returns {object} an associative dictionary of currencies
*/
const response = await this.publicGetCurrencies (params);
//
// {
// "success":true,
// "data":[
// {
// "id":1,
// "code":"BTC",
// "name":"Bitcoin",
// "active":true,
// "delisted":false,
// "precision":8,
// "minimum_tx_confirmations":1,
// "minimum_withdrawal_amount":"0.00200000",
// "minimum_deposit_amount":"0.00000000",
// "deposit_fee_currency_id":1,
// "deposit_fee_currency_code":"BTC",
// "deposit_fee_const":"0.00000000",
// "deposit_fee_percent":"0.00000000",
// "withdrawal_fee_currency_id":1,
// "withdrawal_fee_currency_code":"BTC",
// "withdrawal_fee_const":"0.00100000",
// "withdrawal_fee_percent":"0.00000000",
// "block_explorer_url":"https:\/\/blockchain.info\/tx\/",
// "protocol_specific_settings":null
// },
// ]
// }
//
const result = {};
const currencies = this.safeValue (response, 'data', []);
for (let i = 0; i < currencies.length; i++) {
const currency = currencies[i];
const id = this.safeString (currency, 'id');
const numericId = this.safeInteger (currency, 'id');
// todo: will need to rethink the fees
// to add support for multiple withdrawal/deposit methods and
// differentiated fees for each particular method
const code = this.safeCurrencyCode (this.safeString (currency, 'code'));
const precision = this.parseNumber (this.parsePrecision (this.safeString (currency, 'precision')));
const fee = this.safeNumber (currency, 'withdrawal_fee_const'); // todo: redesign
const active = this.safeValue (currency, 'active', true);
result[code] = {
'id': id,
'numericId': numericId,
'code': code,
'info': currency,
'type': undefined,
'name': this.safeString (currency, 'name'),
'active': active,
'deposit': undefined,
'withdraw': undefined,
'fee': fee,
'precision': precision,
'limits': {
'amount': {
'min': precision,
'max': undefined,
},
'deposit': {
'min': this.safeNumber (currency, 'minimum_deposit_amount'),
'max': undefined,
},
'withdraw': {
'min': this.safeNumber (currency, 'minimum_withdrawal_amount'),
'max': undefined,
},
},
};
}
return result;
}
async fetchMarkets (params = {}) {
/**
* @method
* @name stex#fetchMarkets
* @description retrieves data on all markets for stex
* @param {object} params extra parameters specific to the exchange api endpoint
* @returns {[object]} an array of objects representing market data
*/
const request = {
'code': 'ALL',
};
const response = await this.publicGetCurrencyPairsListCode (this.extend (request, params));
//
// {
// "success":true,
// "data":[
// {
// "id":935,
// "currency_id":662,
// "currency_code":"ABET",
// "currency_name":"Altbet",
// "market_currency_id":1,
// "market_code":"BTC",
// "market_name":"Bitcoin",
// "min_order_amount":"0.00000010",
// "min_buy_price":"0.00000001",
// "min_sell_price":"0.00000001",
// "buy_fee_percent":"0.20000000",
// "sell_fee_percent":"0.20000000",
// "active":true,
// "delisted":false,
// "pair_message":"",
// "currency_precision":8,
// "market_precision":8,
// "symbol":"ABET_BTC",
// "group_name":"BTC",
// "group_id":1
// }
// ]
// }
//
const result = [];
const markets = this.safeValue (response, 'data', []);
for (let i = 0; i < markets.length; i++) {
const market = markets[i];
const id = this.safeString (market, 'id');
const numericId = this.safeInteger (market, 'id');
const baseId = this.safeString (market, 'currency_id');
const quoteId = this.safeString (market, 'market_currency_id');
const baseNumericId = this.safeInteger (market, 'currency_id');
const quoteNumericId = this.safeInteger (market, 'market_currency_id');
const base = this.safeCurrencyCode (this.safeString (market, 'currency_code'));
const quote = this.safeCurrencyCode (this.safeString (market, 'market_code'));
const minBuyPrice = this.safeString (market, 'min_buy_price');
const minSellPrice = this.safeString (market, 'min_sell_price');
const minPrice = Precise.stringMax (minBuyPrice, minSellPrice);
const buyFee = Precise.stringDiv (this.safeString (market, 'buy_fee_percent'), '100');
const sellFee = Precise.stringDiv (this.safeString (market, 'sell_fee_percent'), '100');
const fee = Precise.stringMax (buyFee, sellFee);
result.push ({
'id': id,
'numericId': numericId,
'symbol': base + '/' + quote,
'base': base,
'quote': quote,
'settle': undefined,
'baseId': baseId,
'quoteId': quoteId,
'settleId': undefined,
'baseNumericId': baseNumericId,
'quoteNumericId': quoteNumericId,
'type': 'spot',
'spot': true,
'margin': false,
'swap': false,
'future': false,
'option': false,
'active': this.safeValue (market, 'active'),
'contract': false,
'linear': undefined,
'inverse': undefined,
'taker': fee,
'maker': fee,
'contractSize': undefined,
'expiry': undefined,
'expiryDatetime': undefined,
'strike': undefined,
'optionType': undefined,
'precision': {
'amount': this.parseNumber (this.parsePrecision (this.safeString (market, 'currency_precision'))),
'price': this.parseNumber (this.parsePrecision (this.safeString (market, 'market_precision'))),
},
'limits': {
'leverage': {
'min': undefined,
'max': undefined,
},
'amount': {
'min': this.safeNumber (market, 'min_order_amount'),
'max': undefined,
},
'price': {
'min': minPrice,
'max': undefined,
},
'cost': {
'min': undefined,
'max': undefined,
},
},
'info': market,
});
}
return result;
}
async fetchTicker (symbol, params = {}) {
/**
* @method
* @name stex#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 stex 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 = {
'currencyPairId': market['id'],
};
const response = await this.publicGetTickerCurrencyPairId (this.extend (request, params));
//
// {
// "success": true,
// "data": {
// "id": 2,
// "amount_multiplier": 1,
// "currency_code": "ETH",
// "market_code": "BTC",
// "currency_name": "Ethereum",
// "market_name": "Bitcoin",
// "symbol": "ETH_BTC",
// "group_name": "BTC",
// "group_id": 1,
// "ask": "0.02069998",
// "bid": "0.02028622",
// "last": "0.02049224",
// "open": "0.02059605",
// "low": "0.01977744",
// "high": "0.02097005",
// "volume": "480.43248971",
// "volumeQuote": "23491.29826130",
// "count": "7384",
// "fiatsRate": {
// "USD": 7230.86,
// "EUR": 6590.79,
// "UAH": 173402,
// "AUD": 10595.51,
// "IDR": 101568085,
// "CNY": 50752,
// "KRW": 8452295,
// "JPY": 784607,
// "VND": 167315119,
// "INR": 517596,
// "GBP": 5607.25,
// "CAD": 9602.63,
// "BRL": 30472,
// "RUB": 460718
// },
// "timestamp": 1574698235601
// }
// }
//
const ticker = this.safeValue (response, 'data', {});
return this.parseTicker (ticker, market);
}
async fetchTime (params = {}) {
/**
* @method
* @name stex#fetchTime
* @description fetches the current integer timestamp in milliseconds from the exchange server
* @param {object} params extra parameters specific to the stex api endpoint
* @returns {int} the current integer timestamp in milliseconds from the exchange server
*/
const response = await this.publicGetPing (params);
//
// {
// "success": true,
// "data": {
// "server_datetime": {
// "date": "2019-01-22 15:13:34.233796",
// "timezone_type": 3,
// "timezone": "UTC"
// },
// "server_timestamp": 1548170014
// }
// }
//
const data = this.safeValue (response, 'data', {});
const serverDatetime = this.safeValue (data, 'server_datetime', {});
return this.parse8601 (this.safeString (serverDatetime, 'date'));
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
/**
* @method
* @name stex#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 stex 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 = {
'currencyPairId': market['id'],
};
if (limit !== undefined) {
request['limit_bids'] = limit; // returns all if set to 0, default 100
request['limit_asks'] = limit; // returns all if set to 0, default 100
}
const response = await this.publicGetOrderbookCurrencyPairId (this.extend (request, params));
//
// {
// "success": true,
// "data": {
// "ask": [
// { "currency_pair_id": 2, "amount": "2.17865373", "price": "0.02062917", "amount2": "0.04494382", "count": 1, "cumulative_amount": 2.17865373 },
// { "currency_pair_id": 2, "amount": "2.27521743", "price": "0.02062918", "amount2": "0.04693587", "count": 1, "cumulative_amount": 4.45387116 },
// { "currency_pair_id": 2, "amount": "1.26980049", "price": "0.02063170", "amount2": "0.02619814", "count": 1, "cumulative_amount": 5.72367165 },
// ],
// "bid": [
// { "currency_pair_id": 2, "amount": "0.00978005", "price": "0.02057000", "amount2": "0.00020118", "count": 1, "cumulative_amount": 0.00978005 },
// { "currency_pair_id": 2, "amount": "0.00500000", "price": "0.02056000", "amount2": "0.00010280", "count": 1, "cumulative_amount": 0.01478005 },
// { "currency_pair_id": 2, "amount": "0.77679882", "price": "0.02054001", "amount2": "0.01595546", "count": 1, "cumulative_amount": 0.79157887 },
// ],
// "ask_total_amount": 2555.749174609999,
// "bid_total_amount": 29.180037330000005
// }
// }
//
const orderbook = this.safeValue (response, 'data', {});
return this.parseOrderBook (orderbook, symbol, undefined, 'bid', 'ask', 'price', 'amount');
}
parseTicker (ticker, market = undefined) {
//
// {
// "id": 2,
// "amount_multiplier": 1,
// "currency_code": "ETH",
// "market_code": "BTC",
// "currency_name": "Ethereum",
// "market_name": "Bitcoin",
// "symbol": "ETH_BTC",
// "group_name": "BTC",
// "group_id": 1,
// "ask": "0.02069998",
// "bid": "0.02028622",
// "last": "0.02049224",
// "open": "0.02059605",
// "low": "0.01977744",
// "high": "0.02097005",
// "volume": "480.43248971",
// "volumeQuote": "23491.29826130",
// "count": "7384",
// "fiatsRate": {
// "USD": 7230.86,
// "EUR": 6590.79,
// "UAH": 173402,
// "AUD": 10595.51,
// "IDR": 101568085,
// "CNY": 50752,
// "KRW": 8452295,
// "JPY": 784607,
// "VND": 167315119,
// "INR": 517596,
// "GBP": 5607.25,
// "CAD": 9602.63,
// "BRL": 30472,
// "RUB": 460718
// },
// "timestamp": 1574698235601
// }
//
const timestamp = this.safeInteger (ticker, 'timestamp');
const marketId = this.safeString2 (ticker, 'id', 'symbol');
const symbol = this.safeSymbol (marketId, market, '_');
const last = this.safeString (ticker, 'last');
const open = this.safeString (ticker, 'open');
return this.safeTicker ({
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'high': this.safeString (ticker, 'high'),
'low': this.safeString (ticker, 'low'),
'bid': this.safeString (ticker, 'bid'),
'bidVolume': undefined,
'ask': this.safeString (ticker, 'ask'),
'askVolume': undefined,
'vwap': undefined,
'open': open,
'close': last,
'last': last,
'previousClose': undefined, // previous day close
'change': undefined,
'percentage': undefined,
'average': undefined,
'baseVolume': this.safeString (ticker, 'volumeQuote'),
'quoteVolume': this.safeString (ticker, 'volume'),
'info': ticker,
}, market);
}
async fetchTickers (symbols = undefined, params = {}) {
/**
* @method
* @name stex#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 stex 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.publicGetTicker (params);
//
// {
// "success":true,
// "data":[
// {
// "id":262,
// "amount_multiplier":1,
// "currency_code":"ARDR",
// "market_code":"BTC",
// "currency_name":"ARDOR",
// "market_name":"Bitcoin",
// "symbol":"ARDR_BTC",
// "group_name":"BTC",
// "group_id":1,
// "ask":"0.00000630",
// "bid":"0.00000613",
// "last":"0.00000617",
// "open":"0.00000620",
// "low":"0.00000614",
// "high":"0.00000630",
// "volume":"30.37795305",
// "volumeQuote":"4911487.01996544",
// "count":"710",
// "fiatsRate":{
// "USD":7230.86,
// "EUR":6590.79,
// "UAH":173402,
// "AUD":10744.52,
// "IDR":101568085,
// "CNY":50752,
// "KRW":8452295,
// "JPY":784607,
// "VND":167315119,
// "INR":517596,
// "GBP":5607.25,
// "CAD":9602.63,
// "BRL":30472,
// "RUB":467358
// },
// "timestamp":1574698617304,
// "group_position":1
// },
// ]
// }
//
const tickers = this.safeValue (response, 'data', []);
return this.parseTickers (tickers, symbols);
}
parseOHLCV (ohlcv, market = undefined) {
//
// {
// "time": 1566086400000,
// "close": 0.01895,
// "open": 0.01812427,
// "high": 0.0191588,
// "low": 0.01807001,
// "volume": 2588.597813750006
// }
//
return [
this.safeInteger (ohlcv, 'time'),
this.safeNumber (ohlcv, 'open'),
this.safeNumber (ohlcv, 'high'),
this.safeNumber (ohlcv, 'low'),
this.safeNumber (ohlcv, 'close'),
this.safeNumber (ohlcv, 'volume'),
];
}
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name stex#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 stex 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 = {
'currencyPairId': market['id'],
'candlesType': this.timeframes[timeframe], // default 1d
// 'timeStart': 1574709092, // unix timestamp in seconds, required
// 'timeEnd': 1574709092, // unix timestamp in seconds, required
// 'limit': 100, // default 100, optional
// 'offset' 100, // optional, pagination within timerange
};
if (limit === undefined) {
limit = 100;
} else {
request['limit'] = limit;
}
const duration = this.parseTimeframe (timeframe);
const timerange = limit * duration;
if (since === undefined) {
request['timeEnd'] = this.seconds ();
request['timeStart'] = request['timeEnd'] - timerange;
} else {
request['timeStart'] = parseInt (since / 1000);
request['timeEnd'] = this.sum (request['timeStart'], timerange);
}
const response = await this.publicGetChartCurrencyPairIdCandlesType (this.extend (request, params));
//
// {
// "success": true,
// "data": [
// {
// "time": 1566086400000,
// "close": 0.01895,
// "open": 0.01812427,
// "high": 0.0191588,
// "low": 0.01807001,
// "volume": 2588.597813750006
// },
// ]
// }
//
const data = this.safeValue (response, 'data', []);
return this.parseOHLCVs (data, market, timeframe, since, limit);
}
parseTrade (trade, market = undefined) {
//
// public fetchTrades
//
// {
// "id": 35989317,
// "price": "0.02033813",
// "amount": "3.60000000",
// "type": "BUY",
// "timestamp": "1574713503"
// }
//
// private fetchMyTrades, fetchClosedOrder, fetchOrderTrades
//
// {
// "id": 658745,
// "buy_order_id": 6587453,
// "sell_order_id": 6587459,
// "price": 0.012285,
// "amount": 6.35,
// "trade_type": "SELL",
// "timestamp": "1538737692"
// }
//
const id = this.safeString (trade, 'id');
const timestamp = this.safeTimestamp (trade, 'timestamp');
const priceString = this.safeString (trade, 'price');
const amountString = this.safeString (trade, 'amount');
let symbol = undefined;
if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
}
const side = this.safeStringLower2 (trade, 'type', 'trade_type');
return this.safeTrade ({
'info': trade,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'symbol': symbol,
'id': id,
'order': undefined,
'type': undefined,
'takerOrMaker': undefined,
'side': side,
'price': priceString,
'amount': amountString,
'cost': undefined,
'fee': undefined,
}, market);
}
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name stex#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 stex 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 = {
'currencyPairId': market['id'],
// 'sort': 'ASC', // ASC or DESC, default DESC
// 'from': 1574709092, // unix timestamp, optional
// 'till': 1574709092, // unix timestamp, optional
// 'limit': 100, // default 100, optional
// 'offset': 100, // optional
};
if (limit !== undefined) {
request['limit'] = limit; // currently limited to 100 or fewer
}
if (since !== undefined) {
request['sort'] = 'ASC'; // needed to make the from param work
request['from'] = parseInt (since / 1000);
}
const response = await this.publicGetTradesCurrencyPairId (this.extend (request, params));
//
// {
// "success": true,
// "data": [
// {
// "id": 35989317,
// "price": "0.02033813",
// "amount": "3.60000000",
// "type": "BUY",
// "timestamp": "1574713503"
// },
// ]
// }
//
const trades = this.safeValue (response, 'data', []);
return this.parseTrades (trades, market, since, limit);
}
async fetchTradingFee (symbol, params = {}) {
/**
* @method
* @name stex#fetchTradingFee
* @description fetch the trading fees for a market
* @param {string} symbol unified market symbol
* @param {object} params extra parameters specific to the stex api endpoint
* @returns {object} a [fee structure]{@link https://docs.ccxt.com/en/latest/manual.html#fee-structure}
*/
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'currencyPairId': market['id'],
};
const response = await this.tradingGetFeesCurrencyPairId (this.extend (request, params));
//
// {
// success: true,
// data: { buy_fee: '0.00200000', sell_fee: '0.00200000' },
// unified_message: { message_id: 'operation_successful', substitutions: [] }
// }
//
const data = this.safeValue (response, 'data');
return {
'info': response,
'symbol': market['symbol'],
'maker': this.safeNumber (data, 'sell_fee'),
'taker': this.safeNumber (data, 'buy_fee'),
'percentage': true,
'tierBased': true,
};
}
parseBalance (response) {
const result = {
'info': response,
'timestamp': undefined,
'datetime': undefined,
};
const balances = this.safeValue (response, 'data', []);
for (let i = 0; i < balances.length; i++) {
const balance = balances[i];
const code = this.safeCurrencyCode (this.safeString (balance, 'currency_id'));
const account = this.account ();
account['free'] = this.safeString (balance, 'balance');
account['used'] = this.safeString (balance, 'frozen_balance');
result[code] = account;
}
return this.safeBalance (result);
}
async fetchBalance (params = {}) {
/**
* @method
* @name stex#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 stex api endpoint
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure}
*/
await this.loadMarkets ();
// await this.loadAccounts ();
const response = await this.profileGetWallets (params);
//
// {
// "success": true,
// "data": [
// {
// "id": null,
// "currency_id": 665,
// "delisted": false,
// "disabled": false,
// "disable_deposits": false,
// "currency_code": "ORM",
// "currency_name": "Orium",
// "currency_type_id": 5,
// "balance": "0",
// "frozen_balance": "0",
// "bonus_balance": "0",
// "total_balance": "0",
// "protocol_specific_settings": null,
// "rates": { "BTC": "0.00000000020", "USD": "0.00000147" },
// },
// {
// "id": null,
// "currency_id": 272,
// "delisted": false,
// "disabled": false,
// "disable_deposits": false,
// "currency_code": "USDT",
// "currency_name": "TetherUSD",
// "currency_type_id": 23,
// "balance": "0",
// "frozen_balance": "0",
// "bonus_balance": "0",
// "total_balance": "0",
// "protocol_specific_settings": [
// { "protocol_name": "OMNI", "protocol_id": 10, "active": true, "withdrawal_fee_currency_id": 272, "withdrawal_fee_const": 10, "withdrawal_fee_percent": 0, "block_explorer_url": "https://omniexplorer.info/search/" },
// { "protocol_name": "ERC20", "protocol_id": 5, "active": true, "withdrawal_fee_const": 1.2, "withdrawal_fee_percent": 0, "block_explorer_url": "https://etherscan.io/tx/" },
// { "protocol_name": "TRON", "protocol_id": 24, "active": true, "withdrawal_fee_currency_id": 272, "withdrawal_fee_const": 0.2, "withdrawal_fee_percent": 0, "block_explorer_url": "https://tronscan.org/#/transaction/" }
// ],
// "rates": { "BTC": "0.00013893", "USD": "1" },
// },
// ]
// }
//
return this.parseBalance (response);
}
parseOrderStatus (status) {
const statuses = {
'PROCESSING': 'open',
'PENDING': 'open',
'PARTIAL': 'open',
'FINISHED': 'closed',
'CANCELLED': 'canceled',
};
return this.safeString (statuses, status, status);
}
parseOrder (order, market = undefined) {
//
// createOrder, fetchOpenOrders, fetchClosedOrders, cancelOrder, fetchOrder, fetchClosedOrder
//
// {
// "id": 828680665,
// "currency_pair_id": 1,
// "currency_pair_name": "NXT_BTC",
// "price": "0.011384",
// "trigger_price": 0.011385,
// "initial_amount": "13.942",
// "processed_amount": "3.724", // missing in fetchClosedOrder
// "type": "SELL",
// "original_type": "STOP_LIMIT_SELL",
// "created": "2019-01-17 10:14:48",
// "timestamp": "1547720088",
// "status": "PARTIAL"
// // fetchClosedOrder only
//